diff options
410 files changed, 20719 insertions, 15805 deletions
diff --git a/Android.bp b/Android.bp index 60ec7e2709a7..9d48cf81e998 100644 --- a/Android.bp +++ b/Android.bp @@ -97,7 +97,7 @@ filegroup { ":platform-compat-native-aidl", // AIDL sources from external directories - ":android.hardware.security.keymint-V1-java-source", + ":android.hardware.security.keymint-V2-java-source", ":android.hardware.security.secureclock-V1-java-source", ":android.security.apc-java-source", ":android.security.authorization-java-source", @@ -140,21 +140,8 @@ java_library { name: "framework-all", installable: false, static_libs: [ - "android.net.ipsec.ike.impl", + "all-framework-module-impl", "framework-minus-apex", - "framework-appsearch.impl", - "framework-connectivity.impl", - "framework-connectivity-tiramisu.impl", - "framework-graphics.impl", - "framework-mediaprovider.impl", - "framework-permission.impl", - "framework-permission-s.impl", - "framework-scheduling.impl", - "framework-sdkextensions.impl", - "framework-statsd.impl", - "framework-tethering.impl", - "framework-wifi.impl", - "updatable-media", ], apex_available: ["//apex_available:platform"], sdk_version: "core_platform", @@ -188,7 +175,6 @@ java_defaults { "sax/java", "telecomm/java", - "apex/media/aidl/stable", // TODO(b/147699819): remove this "telephony/java", ], @@ -284,7 +270,10 @@ java_defaults { include_dirs: [ "frameworks/av/aidl", "frameworks/native/libs/permission/aidl", + // TODO: remove when moved to the below package + "frameworks/base/packages/ConnectivityT/framework-t/aidl-export", "packages/modules/Connectivity/framework/aidl-export", + "packages/modules/Media/apex/aidl/stable", ], }, dxflags: [ @@ -409,7 +398,6 @@ filegroup { // TODO: remove these annotations as soon as we can use andoid.support.annotations.* ":framework-annotations", ":modules-utils-preconditions-srcs", - "core/java/android/net/DhcpResults.java", "core/java/android/util/IndentingPrintWriter.java", "core/java/android/util/LocalLog.java", "core/java/com/android/internal/util/HexDump.java", @@ -461,21 +449,28 @@ java_library { } // TODO(b/145644363): move this to under StubLibraries.bp or ApiDocs.bp -metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.xml) " + - "--hide-package com.android.server " + - "--hide-package android.audio.policy.configuration.V7_0 " + - "--error UnhiddenSystemApi " + - "--hide RequiresPermission " + - "--hide CallbackInterface " + - "--hide MissingPermission --hide BroadcastBehavior " + - "--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " + - "--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo " + - "--error NoSettingsProvider " + - "--force-convert-to-warning-nullability-annotations +*:-android.*:+android.icu.*:-dalvik.* " + +metalava_framework_docs_args = "" + "--api-lint-ignore-prefix android.icu. " + "--api-lint-ignore-prefix java. " + "--api-lint-ignore-prefix junit. " + - "--api-lint-ignore-prefix org. " + "--api-lint-ignore-prefix org. " + + "--error NoSettingsProvider " + + "--error UnhiddenSystemApi " + + "--force-convert-to-warning-nullability-annotations +*:-android.*:+android.icu.*:-dalvik.* " + + "--hide BroadcastBehavior " + + "--hide CallbackInterface " + + "--hide DeprecationMismatch " + + "--hide HiddenSuperclass " + + "--hide HiddenTypeParameter " + + "--hide MissingPermission " + + "--hide-package android.audio.policy.configuration.V7_0 " + + "--hide-package com.android.server " + + "--hide RequiresPermission " + + "--hide SdkConstant " + + "--hide Todo " + + "--hide Typo " + + "--hide UnavailableSymbol " + + "--manifest $(location core/res/AndroidManifest.xml) " packages_to_document = [ "android", @@ -521,6 +516,9 @@ stubs_defaults { include_dirs: [ "frameworks/av/aidl", "frameworks/native/libs/permission/aidl", + // TODO: remove when moved to the below package + "frameworks/base/packages/ConnectivityT/framework-t/aidl-export", + "packages/modules/Connectivity/framework/aidl-export", ], }, // These are libs from framework-internal-utils that are required (i.e. being referenced) @@ -558,16 +556,15 @@ stubs_defaults { stubs_defaults { name: "module-classpath-stubs-defaults", aidl: { - local_include_dirs: [ - "apex/media/aidl/stable", - ], include_dirs: [ "packages/modules/Connectivity/framework/aidl-export", + "packages/modules/Media/apex/aidl/stable", ], }, libs: [ "art.module.public.api", "sdk_module-lib_current_framework-tethering", + "sdk_module-lib_current_framework-connectivity-t", "sdk_public_current_framework-bluetooth", // There are a few classes from modules used by the core that // need to be resolved by metalava. We use a prebuilt stub of the diff --git a/Android.mk b/Android.mk index 46529eb64657..d9e202c9305c 100644 --- a/Android.mk +++ b/Android.mk @@ -15,6 +15,14 @@ # LOCAL_PATH := $(call my-dir) +$(eval $(call declare-1p-copy-files,frameworks/base,.ogg)) +$(eval $(call declare-1p-copy-files,frameworks/base,.kl)) +$(eval $(call declare-1p-copy-files,frameworks/base,.kcm)) +$(eval $(call declare-1p-copy-files,frameworks/base,.idc)) +$(eval $(call declare-1p-copy-files,frameworks/base,dirty-image-objects)) +$(eval $(call declare-1p-copy-files,frameworks/base/config,)) +$(eval $(call declare-1p-copy-files,frameworks/native/data,)) + # Load framework-specific path mappings used later in the build. include $(LOCAL_PATH)/pathmap.mk diff --git a/ApiDocs.bp b/ApiDocs.bp index 5595e95631ad..2efeab6da670 100644 --- a/ApiDocs.bp +++ b/ApiDocs.bp @@ -140,11 +140,9 @@ droidstubs { "api-versions-jars-dir", ], aidl: { - local_include_dirs: [ - "apex/media/aidl/stable", - ], include_dirs: [ "packages/modules/Connectivity/framework/aidl-export", + "packages/modules/Media/apex/aidl/stable", ], }, } diff --git a/INPUT_OWNERS b/INPUT_OWNERS new file mode 100644 index 000000000000..6041f637f9c1 --- /dev/null +++ b/INPUT_OWNERS @@ -0,0 +1,3 @@ +michaelwr@google.com +prabirmsp@google.com +svv@google.com diff --git a/StubLibraries.bp b/StubLibraries.bp index 5cb0a785bc2b..fef95e813ec7 100644 --- a/StubLibraries.bp +++ b/StubLibraries.bp @@ -250,6 +250,7 @@ java_library { srcs: [":module-lib-api-stubs-docs-non-updatable"], libs: [ "sdk_module-lib_current_framework-tethering", + "sdk_module-lib_current_framework-connectivity-t", "sdk_public_current_framework-bluetooth", // NOTE: The below can be removed once the prebuilt stub contains bluetooth. "sdk_system_current_android", @@ -365,6 +366,64 @@ java_library { }, } +//////////////////////////////////////////////////////////////////////// +// api-versions.xml generation, for public and system. This API database +// also contains the android.test.* APIs. +//////////////////////////////////////////////////////////////////////// + +java_library { + name: "android_stubs_current_with_test_libs", + static_libs: [ + "android_stubs_current", + "android.test.base.stubs", + "android.test.mock.stubs", + "android.test.runner.stubs", + ], + defaults: ["android.jar_defaults"], + visibility: [ + "//visibility:override", + "//visibility:private", + ], +} + +java_library { + name: "android_system_stubs_current_with_test_libs", + static_libs: [ + "android_system_stubs_current", + "android.test.base.stubs.system", + "android.test.mock.stubs.system", + "android.test.runner.stubs.system", + ], + defaults: ["android.jar_defaults"], + visibility: [ + "//visibility:override", + "//visibility:private", + ], +} + +droidstubs { + name: "api_versions_public", + srcs: [":android_stubs_current_with_test_libs{.jar}"], + generate_stubs: false, + api_levels_annotations_enabled: true, + api_levels_annotations_dirs: [ + "sdk-dir", + "api-versions-jars-dir", + ], +} + +droidstubs { + name: "api_versions_system", + srcs: [":android_system_stubs_current_with_test_libs{.jar}"], + generate_stubs: false, + api_levels_annotations_enabled: true, + api_levels_annotations_dirs: [ + "sdk-dir", + "api-versions-jars-dir", + ], + api_levels_sdk_type: "system", +} + ///////////////////////////////////////////////////////////////////// // hwbinder.stubs provides APIs required for building HIDL Java // libraries. diff --git a/apct-tests/perftests/core/OWNERS b/apct-tests/perftests/core/OWNERS index 18486af9d12c..2b3564eead31 100644 --- a/apct-tests/perftests/core/OWNERS +++ b/apct-tests/perftests/core/OWNERS @@ -1 +1,5 @@ include /graphics/java/android/graphics/fonts/OWNERS + +# Bug component: 568761 +per-file /apct-tests/perftests/core/res/* = felkachang@google.com,zyy@google.com + diff --git a/apct-tests/perftests/core/res/values/colors.xml b/apct-tests/perftests/core/res/values/colors.xml new file mode 100644 index 000000000000..5e56c250511f --- /dev/null +++ b/apct-tests/perftests/core/res/values/colors.xml @@ -0,0 +1,10022 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 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 + --> + +<resources> + <!--- The colors with prefix "i_am_color_%x" and %x is from 0 to 10000. They are used by + ResourcesPerfTest.java --> + <color name="i_am_color_0">#00000000</color> + <color name="i_am_color_1">#00000001</color> + <color name="i_am_color_2">#00000002</color> + <color name="i_am_color_3">#00000003</color> + <color name="i_am_color_4">#00000004</color> + <color name="i_am_color_5">#00000005</color> + <color name="i_am_color_6">#00000006</color> + <color name="i_am_color_7">#00000007</color> + <color name="i_am_color_8">#00000008</color> + <color name="i_am_color_9">#00000009</color> + <color name="i_am_color_a">#0000000a</color> + <color name="i_am_color_b">#0000000b</color> + <color name="i_am_color_c">#0000000c</color> + <color name="i_am_color_d">#0000000d</color> + <color name="i_am_color_e">#0000000e</color> + <color name="i_am_color_f">#0000000f</color> + <color name="i_am_color_10">#00000010</color> + <color name="i_am_color_11">#00000011</color> + <color name="i_am_color_12">#00000012</color> + <color name="i_am_color_13">#00000013</color> + <color name="i_am_color_14">#00000014</color> + <color name="i_am_color_15">#00000015</color> + <color name="i_am_color_16">#00000016</color> + <color name="i_am_color_17">#00000017</color> + <color name="i_am_color_18">#00000018</color> + <color name="i_am_color_19">#00000019</color> + <color name="i_am_color_1a">#0000001a</color> + <color name="i_am_color_1b">#0000001b</color> + <color name="i_am_color_1c">#0000001c</color> + <color name="i_am_color_1d">#0000001d</color> + <color name="i_am_color_1e">#0000001e</color> + <color name="i_am_color_1f">#0000001f</color> + <color name="i_am_color_20">#00000020</color> + <color name="i_am_color_21">#00000021</color> + <color name="i_am_color_22">#00000022</color> + <color name="i_am_color_23">#00000023</color> + <color name="i_am_color_24">#00000024</color> + <color name="i_am_color_25">#00000025</color> + <color name="i_am_color_26">#00000026</color> + <color name="i_am_color_27">#00000027</color> + <color name="i_am_color_28">#00000028</color> + <color name="i_am_color_29">#00000029</color> + <color name="i_am_color_2a">#0000002a</color> + <color name="i_am_color_2b">#0000002b</color> + <color name="i_am_color_2c">#0000002c</color> + <color name="i_am_color_2d">#0000002d</color> + <color name="i_am_color_2e">#0000002e</color> + <color name="i_am_color_2f">#0000002f</color> + <color name="i_am_color_30">#00000030</color> + <color name="i_am_color_31">#00000031</color> + <color name="i_am_color_32">#00000032</color> + <color name="i_am_color_33">#00000033</color> + <color name="i_am_color_34">#00000034</color> + <color name="i_am_color_35">#00000035</color> + <color name="i_am_color_36">#00000036</color> + <color name="i_am_color_37">#00000037</color> + <color name="i_am_color_38">#00000038</color> + <color name="i_am_color_39">#00000039</color> + <color name="i_am_color_3a">#0000003a</color> + <color name="i_am_color_3b">#0000003b</color> + <color name="i_am_color_3c">#0000003c</color> + <color name="i_am_color_3d">#0000003d</color> + <color name="i_am_color_3e">#0000003e</color> + <color name="i_am_color_3f">#0000003f</color> + <color name="i_am_color_40">#00000040</color> + <color name="i_am_color_41">#00000041</color> + <color name="i_am_color_42">#00000042</color> + <color name="i_am_color_43">#00000043</color> + <color name="i_am_color_44">#00000044</color> + <color name="i_am_color_45">#00000045</color> + <color name="i_am_color_46">#00000046</color> + <color name="i_am_color_47">#00000047</color> + <color name="i_am_color_48">#00000048</color> + <color name="i_am_color_49">#00000049</color> + <color name="i_am_color_4a">#0000004a</color> + <color name="i_am_color_4b">#0000004b</color> + <color name="i_am_color_4c">#0000004c</color> + <color name="i_am_color_4d">#0000004d</color> + <color name="i_am_color_4e">#0000004e</color> + <color name="i_am_color_4f">#0000004f</color> + <color name="i_am_color_50">#00000050</color> + <color name="i_am_color_51">#00000051</color> + <color name="i_am_color_52">#00000052</color> + <color name="i_am_color_53">#00000053</color> + <color name="i_am_color_54">#00000054</color> + <color name="i_am_color_55">#00000055</color> + <color name="i_am_color_56">#00000056</color> + <color name="i_am_color_57">#00000057</color> + <color name="i_am_color_58">#00000058</color> + <color name="i_am_color_59">#00000059</color> + <color name="i_am_color_5a">#0000005a</color> + <color name="i_am_color_5b">#0000005b</color> + <color name="i_am_color_5c">#0000005c</color> + <color name="i_am_color_5d">#0000005d</color> + <color name="i_am_color_5e">#0000005e</color> + <color name="i_am_color_5f">#0000005f</color> + <color name="i_am_color_60">#00000060</color> + <color name="i_am_color_61">#00000061</color> + <color name="i_am_color_62">#00000062</color> + <color name="i_am_color_63">#00000063</color> + <color name="i_am_color_64">#00000064</color> + <color name="i_am_color_65">#00000065</color> + <color name="i_am_color_66">#00000066</color> + <color name="i_am_color_67">#00000067</color> + <color name="i_am_color_68">#00000068</color> + <color name="i_am_color_69">#00000069</color> + <color name="i_am_color_6a">#0000006a</color> + <color name="i_am_color_6b">#0000006b</color> + <color name="i_am_color_6c">#0000006c</color> + <color name="i_am_color_6d">#0000006d</color> + <color name="i_am_color_6e">#0000006e</color> + <color name="i_am_color_6f">#0000006f</color> + <color name="i_am_color_70">#00000070</color> + <color name="i_am_color_71">#00000071</color> + <color name="i_am_color_72">#00000072</color> + <color name="i_am_color_73">#00000073</color> + <color name="i_am_color_74">#00000074</color> + <color name="i_am_color_75">#00000075</color> + <color name="i_am_color_76">#00000076</color> + <color name="i_am_color_77">#00000077</color> + <color name="i_am_color_78">#00000078</color> + <color name="i_am_color_79">#00000079</color> + <color name="i_am_color_7a">#0000007a</color> + <color name="i_am_color_7b">#0000007b</color> + <color name="i_am_color_7c">#0000007c</color> + <color name="i_am_color_7d">#0000007d</color> + <color name="i_am_color_7e">#0000007e</color> + <color name="i_am_color_7f">#0000007f</color> + <color name="i_am_color_80">#00000080</color> + <color name="i_am_color_81">#00000081</color> + <color name="i_am_color_82">#00000082</color> + <color name="i_am_color_83">#00000083</color> + <color name="i_am_color_84">#00000084</color> + <color name="i_am_color_85">#00000085</color> + <color name="i_am_color_86">#00000086</color> + <color name="i_am_color_87">#00000087</color> + <color name="i_am_color_88">#00000088</color> + <color name="i_am_color_89">#00000089</color> + <color name="i_am_color_8a">#0000008a</color> + <color name="i_am_color_8b">#0000008b</color> + <color name="i_am_color_8c">#0000008c</color> + <color name="i_am_color_8d">#0000008d</color> + <color name="i_am_color_8e">#0000008e</color> + <color name="i_am_color_8f">#0000008f</color> + <color name="i_am_color_90">#00000090</color> + <color name="i_am_color_91">#00000091</color> + <color name="i_am_color_92">#00000092</color> + <color name="i_am_color_93">#00000093</color> + <color name="i_am_color_94">#00000094</color> + <color name="i_am_color_95">#00000095</color> + <color name="i_am_color_96">#00000096</color> + <color name="i_am_color_97">#00000097</color> + <color name="i_am_color_98">#00000098</color> + <color name="i_am_color_99">#00000099</color> + <color name="i_am_color_9a">#0000009a</color> + <color name="i_am_color_9b">#0000009b</color> + <color name="i_am_color_9c">#0000009c</color> + <color name="i_am_color_9d">#0000009d</color> + <color name="i_am_color_9e">#0000009e</color> + <color name="i_am_color_9f">#0000009f</color> + <color name="i_am_color_a0">#000000a0</color> + <color name="i_am_color_a1">#000000a1</color> + <color name="i_am_color_a2">#000000a2</color> + <color name="i_am_color_a3">#000000a3</color> + <color name="i_am_color_a4">#000000a4</color> + <color name="i_am_color_a5">#000000a5</color> + <color name="i_am_color_a6">#000000a6</color> + <color name="i_am_color_a7">#000000a7</color> + <color name="i_am_color_a8">#000000a8</color> + <color name="i_am_color_a9">#000000a9</color> + <color name="i_am_color_aa">#000000aa</color> + <color name="i_am_color_ab">#000000ab</color> + <color name="i_am_color_ac">#000000ac</color> + <color name="i_am_color_ad">#000000ad</color> + <color name="i_am_color_ae">#000000ae</color> + <color name="i_am_color_af">#000000af</color> + <color name="i_am_color_b0">#000000b0</color> + <color name="i_am_color_b1">#000000b1</color> + <color name="i_am_color_b2">#000000b2</color> + <color name="i_am_color_b3">#000000b3</color> + <color name="i_am_color_b4">#000000b4</color> + <color name="i_am_color_b5">#000000b5</color> + <color name="i_am_color_b6">#000000b6</color> + <color name="i_am_color_b7">#000000b7</color> + <color name="i_am_color_b8">#000000b8</color> + <color name="i_am_color_b9">#000000b9</color> + <color name="i_am_color_ba">#000000ba</color> + <color name="i_am_color_bb">#000000bb</color> + <color name="i_am_color_bc">#000000bc</color> + <color name="i_am_color_bd">#000000bd</color> + <color name="i_am_color_be">#000000be</color> + <color name="i_am_color_bf">#000000bf</color> + <color name="i_am_color_c0">#000000c0</color> + <color name="i_am_color_c1">#000000c1</color> + <color name="i_am_color_c2">#000000c2</color> + <color name="i_am_color_c3">#000000c3</color> + <color name="i_am_color_c4">#000000c4</color> + <color name="i_am_color_c5">#000000c5</color> + <color name="i_am_color_c6">#000000c6</color> + <color name="i_am_color_c7">#000000c7</color> + <color name="i_am_color_c8">#000000c8</color> + <color name="i_am_color_c9">#000000c9</color> + <color name="i_am_color_ca">#000000ca</color> + <color name="i_am_color_cb">#000000cb</color> + <color name="i_am_color_cc">#000000cc</color> + <color name="i_am_color_cd">#000000cd</color> + <color name="i_am_color_ce">#000000ce</color> + <color name="i_am_color_cf">#000000cf</color> + <color name="i_am_color_d0">#000000d0</color> + <color name="i_am_color_d1">#000000d1</color> + <color name="i_am_color_d2">#000000d2</color> + <color name="i_am_color_d3">#000000d3</color> + <color name="i_am_color_d4">#000000d4</color> + <color name="i_am_color_d5">#000000d5</color> + <color name="i_am_color_d6">#000000d6</color> + <color name="i_am_color_d7">#000000d7</color> + <color name="i_am_color_d8">#000000d8</color> + <color name="i_am_color_d9">#000000d9</color> + <color name="i_am_color_da">#000000da</color> + <color name="i_am_color_db">#000000db</color> + <color name="i_am_color_dc">#000000dc</color> + <color name="i_am_color_dd">#000000dd</color> + <color name="i_am_color_de">#000000de</color> + <color name="i_am_color_df">#000000df</color> + <color name="i_am_color_e0">#000000e0</color> + <color name="i_am_color_e1">#000000e1</color> + <color name="i_am_color_e2">#000000e2</color> + <color name="i_am_color_e3">#000000e3</color> + <color name="i_am_color_e4">#000000e4</color> + <color name="i_am_color_e5">#000000e5</color> + <color name="i_am_color_e6">#000000e6</color> + <color name="i_am_color_e7">#000000e7</color> + <color name="i_am_color_e8">#000000e8</color> + <color name="i_am_color_e9">#000000e9</color> + <color name="i_am_color_ea">#000000ea</color> + <color name="i_am_color_eb">#000000eb</color> + <color name="i_am_color_ec">#000000ec</color> + <color name="i_am_color_ed">#000000ed</color> + <color name="i_am_color_ee">#000000ee</color> + <color name="i_am_color_ef">#000000ef</color> + <color name="i_am_color_f0">#000000f0</color> + <color name="i_am_color_f1">#000000f1</color> + <color name="i_am_color_f2">#000000f2</color> + <color name="i_am_color_f3">#000000f3</color> + <color name="i_am_color_f4">#000000f4</color> + <color name="i_am_color_f5">#000000f5</color> + <color name="i_am_color_f6">#000000f6</color> + <color name="i_am_color_f7">#000000f7</color> + <color name="i_am_color_f8">#000000f8</color> + <color name="i_am_color_f9">#000000f9</color> + <color name="i_am_color_fa">#000000fa</color> + <color name="i_am_color_fb">#000000fb</color> + <color name="i_am_color_fc">#000000fc</color> + <color name="i_am_color_fd">#000000fd</color> + <color name="i_am_color_fe">#000000fe</color> + <color name="i_am_color_ff">#000000ff</color> + <color name="i_am_color_100">#00000100</color> + <color name="i_am_color_101">#00000101</color> + <color name="i_am_color_102">#00000102</color> + <color name="i_am_color_103">#00000103</color> + <color name="i_am_color_104">#00000104</color> + <color name="i_am_color_105">#00000105</color> + <color name="i_am_color_106">#00000106</color> + <color name="i_am_color_107">#00000107</color> + <color name="i_am_color_108">#00000108</color> + <color name="i_am_color_109">#00000109</color> + <color name="i_am_color_10a">#0000010a</color> + <color name="i_am_color_10b">#0000010b</color> + <color name="i_am_color_10c">#0000010c</color> + <color name="i_am_color_10d">#0000010d</color> + <color name="i_am_color_10e">#0000010e</color> + <color name="i_am_color_10f">#0000010f</color> + <color name="i_am_color_110">#00000110</color> + <color name="i_am_color_111">#00000111</color> + <color name="i_am_color_112">#00000112</color> + <color name="i_am_color_113">#00000113</color> + <color name="i_am_color_114">#00000114</color> + <color name="i_am_color_115">#00000115</color> + <color name="i_am_color_116">#00000116</color> + <color name="i_am_color_117">#00000117</color> + <color name="i_am_color_118">#00000118</color> + <color name="i_am_color_119">#00000119</color> + <color name="i_am_color_11a">#0000011a</color> + <color name="i_am_color_11b">#0000011b</color> + <color name="i_am_color_11c">#0000011c</color> + <color name="i_am_color_11d">#0000011d</color> + <color name="i_am_color_11e">#0000011e</color> + <color name="i_am_color_11f">#0000011f</color> + <color name="i_am_color_120">#00000120</color> + <color name="i_am_color_121">#00000121</color> + <color name="i_am_color_122">#00000122</color> + <color name="i_am_color_123">#00000123</color> + <color name="i_am_color_124">#00000124</color> + <color name="i_am_color_125">#00000125</color> + <color name="i_am_color_126">#00000126</color> + <color name="i_am_color_127">#00000127</color> + <color name="i_am_color_128">#00000128</color> + <color name="i_am_color_129">#00000129</color> + <color name="i_am_color_12a">#0000012a</color> + <color name="i_am_color_12b">#0000012b</color> + <color name="i_am_color_12c">#0000012c</color> + <color name="i_am_color_12d">#0000012d</color> + <color name="i_am_color_12e">#0000012e</color> + <color name="i_am_color_12f">#0000012f</color> + <color name="i_am_color_130">#00000130</color> + <color name="i_am_color_131">#00000131</color> + <color name="i_am_color_132">#00000132</color> + <color name="i_am_color_133">#00000133</color> + <color name="i_am_color_134">#00000134</color> + <color name="i_am_color_135">#00000135</color> + <color name="i_am_color_136">#00000136</color> + <color name="i_am_color_137">#00000137</color> + <color name="i_am_color_138">#00000138</color> + <color name="i_am_color_139">#00000139</color> + <color name="i_am_color_13a">#0000013a</color> + <color name="i_am_color_13b">#0000013b</color> + <color name="i_am_color_13c">#0000013c</color> + <color name="i_am_color_13d">#0000013d</color> + <color name="i_am_color_13e">#0000013e</color> + <color name="i_am_color_13f">#0000013f</color> + <color name="i_am_color_140">#00000140</color> + <color name="i_am_color_141">#00000141</color> + <color name="i_am_color_142">#00000142</color> + <color name="i_am_color_143">#00000143</color> + <color name="i_am_color_144">#00000144</color> + <color name="i_am_color_145">#00000145</color> + <color name="i_am_color_146">#00000146</color> + <color name="i_am_color_147">#00000147</color> + <color name="i_am_color_148">#00000148</color> + <color name="i_am_color_149">#00000149</color> + <color name="i_am_color_14a">#0000014a</color> + <color name="i_am_color_14b">#0000014b</color> + <color name="i_am_color_14c">#0000014c</color> + <color name="i_am_color_14d">#0000014d</color> + <color name="i_am_color_14e">#0000014e</color> + <color name="i_am_color_14f">#0000014f</color> + <color name="i_am_color_150">#00000150</color> + <color name="i_am_color_151">#00000151</color> + <color name="i_am_color_152">#00000152</color> + <color name="i_am_color_153">#00000153</color> + <color name="i_am_color_154">#00000154</color> + <color name="i_am_color_155">#00000155</color> + <color name="i_am_color_156">#00000156</color> + <color name="i_am_color_157">#00000157</color> + <color name="i_am_color_158">#00000158</color> + <color name="i_am_color_159">#00000159</color> + <color name="i_am_color_15a">#0000015a</color> + <color name="i_am_color_15b">#0000015b</color> + <color name="i_am_color_15c">#0000015c</color> + <color name="i_am_color_15d">#0000015d</color> + <color name="i_am_color_15e">#0000015e</color> + <color name="i_am_color_15f">#0000015f</color> + <color name="i_am_color_160">#00000160</color> + <color name="i_am_color_161">#00000161</color> + <color name="i_am_color_162">#00000162</color> + <color name="i_am_color_163">#00000163</color> + <color name="i_am_color_164">#00000164</color> + <color name="i_am_color_165">#00000165</color> + <color name="i_am_color_166">#00000166</color> + <color name="i_am_color_167">#00000167</color> + <color name="i_am_color_168">#00000168</color> + <color name="i_am_color_169">#00000169</color> + <color name="i_am_color_16a">#0000016a</color> + <color name="i_am_color_16b">#0000016b</color> + <color name="i_am_color_16c">#0000016c</color> + <color name="i_am_color_16d">#0000016d</color> + <color name="i_am_color_16e">#0000016e</color> + <color name="i_am_color_16f">#0000016f</color> + <color name="i_am_color_170">#00000170</color> + <color name="i_am_color_171">#00000171</color> + <color name="i_am_color_172">#00000172</color> + <color name="i_am_color_173">#00000173</color> + <color name="i_am_color_174">#00000174</color> + <color name="i_am_color_175">#00000175</color> + <color name="i_am_color_176">#00000176</color> + <color name="i_am_color_177">#00000177</color> + <color name="i_am_color_178">#00000178</color> + <color name="i_am_color_179">#00000179</color> + <color name="i_am_color_17a">#0000017a</color> + <color name="i_am_color_17b">#0000017b</color> + <color name="i_am_color_17c">#0000017c</color> + <color name="i_am_color_17d">#0000017d</color> + <color name="i_am_color_17e">#0000017e</color> + <color name="i_am_color_17f">#0000017f</color> + <color name="i_am_color_180">#00000180</color> + <color name="i_am_color_181">#00000181</color> + <color name="i_am_color_182">#00000182</color> + <color name="i_am_color_183">#00000183</color> + <color name="i_am_color_184">#00000184</color> + <color name="i_am_color_185">#00000185</color> + <color name="i_am_color_186">#00000186</color> + <color name="i_am_color_187">#00000187</color> + <color name="i_am_color_188">#00000188</color> + <color name="i_am_color_189">#00000189</color> + <color name="i_am_color_18a">#0000018a</color> + <color name="i_am_color_18b">#0000018b</color> + <color name="i_am_color_18c">#0000018c</color> + <color name="i_am_color_18d">#0000018d</color> + <color name="i_am_color_18e">#0000018e</color> + <color name="i_am_color_18f">#0000018f</color> + <color name="i_am_color_190">#00000190</color> + <color name="i_am_color_191">#00000191</color> + <color name="i_am_color_192">#00000192</color> + <color name="i_am_color_193">#00000193</color> + <color name="i_am_color_194">#00000194</color> + <color name="i_am_color_195">#00000195</color> + <color name="i_am_color_196">#00000196</color> + <color name="i_am_color_197">#00000197</color> + <color name="i_am_color_198">#00000198</color> + <color name="i_am_color_199">#00000199</color> + <color name="i_am_color_19a">#0000019a</color> + <color name="i_am_color_19b">#0000019b</color> + <color name="i_am_color_19c">#0000019c</color> + <color name="i_am_color_19d">#0000019d</color> + <color name="i_am_color_19e">#0000019e</color> + <color name="i_am_color_19f">#0000019f</color> + <color name="i_am_color_1a0">#000001a0</color> + <color name="i_am_color_1a1">#000001a1</color> + <color name="i_am_color_1a2">#000001a2</color> + <color name="i_am_color_1a3">#000001a3</color> + <color name="i_am_color_1a4">#000001a4</color> + <color name="i_am_color_1a5">#000001a5</color> + <color name="i_am_color_1a6">#000001a6</color> + <color name="i_am_color_1a7">#000001a7</color> + <color name="i_am_color_1a8">#000001a8</color> + <color name="i_am_color_1a9">#000001a9</color> + <color name="i_am_color_1aa">#000001aa</color> + <color name="i_am_color_1ab">#000001ab</color> + <color name="i_am_color_1ac">#000001ac</color> + <color name="i_am_color_1ad">#000001ad</color> + <color name="i_am_color_1ae">#000001ae</color> + <color name="i_am_color_1af">#000001af</color> + <color name="i_am_color_1b0">#000001b0</color> + <color name="i_am_color_1b1">#000001b1</color> + <color name="i_am_color_1b2">#000001b2</color> + <color name="i_am_color_1b3">#000001b3</color> + <color name="i_am_color_1b4">#000001b4</color> + <color name="i_am_color_1b5">#000001b5</color> + <color name="i_am_color_1b6">#000001b6</color> + <color name="i_am_color_1b7">#000001b7</color> + <color name="i_am_color_1b8">#000001b8</color> + <color name="i_am_color_1b9">#000001b9</color> + <color name="i_am_color_1ba">#000001ba</color> + <color name="i_am_color_1bb">#000001bb</color> + <color name="i_am_color_1bc">#000001bc</color> + <color name="i_am_color_1bd">#000001bd</color> + <color name="i_am_color_1be">#000001be</color> + <color name="i_am_color_1bf">#000001bf</color> + <color name="i_am_color_1c0">#000001c0</color> + <color name="i_am_color_1c1">#000001c1</color> + <color name="i_am_color_1c2">#000001c2</color> + <color name="i_am_color_1c3">#000001c3</color> + <color name="i_am_color_1c4">#000001c4</color> + <color name="i_am_color_1c5">#000001c5</color> + <color name="i_am_color_1c6">#000001c6</color> + <color name="i_am_color_1c7">#000001c7</color> + <color name="i_am_color_1c8">#000001c8</color> + <color name="i_am_color_1c9">#000001c9</color> + <color name="i_am_color_1ca">#000001ca</color> + <color name="i_am_color_1cb">#000001cb</color> + <color name="i_am_color_1cc">#000001cc</color> + <color name="i_am_color_1cd">#000001cd</color> + <color name="i_am_color_1ce">#000001ce</color> + <color name="i_am_color_1cf">#000001cf</color> + <color name="i_am_color_1d0">#000001d0</color> + <color name="i_am_color_1d1">#000001d1</color> + <color name="i_am_color_1d2">#000001d2</color> + <color name="i_am_color_1d3">#000001d3</color> + <color name="i_am_color_1d4">#000001d4</color> + <color name="i_am_color_1d5">#000001d5</color> + <color name="i_am_color_1d6">#000001d6</color> + <color name="i_am_color_1d7">#000001d7</color> + <color name="i_am_color_1d8">#000001d8</color> + <color name="i_am_color_1d9">#000001d9</color> + <color name="i_am_color_1da">#000001da</color> + <color name="i_am_color_1db">#000001db</color> + <color name="i_am_color_1dc">#000001dc</color> + <color name="i_am_color_1dd">#000001dd</color> + <color name="i_am_color_1de">#000001de</color> + <color name="i_am_color_1df">#000001df</color> + <color name="i_am_color_1e0">#000001e0</color> + <color name="i_am_color_1e1">#000001e1</color> + <color name="i_am_color_1e2">#000001e2</color> + <color name="i_am_color_1e3">#000001e3</color> + <color name="i_am_color_1e4">#000001e4</color> + <color name="i_am_color_1e5">#000001e5</color> + <color name="i_am_color_1e6">#000001e6</color> + <color name="i_am_color_1e7">#000001e7</color> + <color name="i_am_color_1e8">#000001e8</color> + <color name="i_am_color_1e9">#000001e9</color> + <color name="i_am_color_1ea">#000001ea</color> + <color name="i_am_color_1eb">#000001eb</color> + <color name="i_am_color_1ec">#000001ec</color> + <color name="i_am_color_1ed">#000001ed</color> + <color name="i_am_color_1ee">#000001ee</color> + <color name="i_am_color_1ef">#000001ef</color> + <color name="i_am_color_1f0">#000001f0</color> + <color name="i_am_color_1f1">#000001f1</color> + <color name="i_am_color_1f2">#000001f2</color> + <color name="i_am_color_1f3">#000001f3</color> + <color name="i_am_color_1f4">#000001f4</color> + <color name="i_am_color_1f5">#000001f5</color> + <color name="i_am_color_1f6">#000001f6</color> + <color name="i_am_color_1f7">#000001f7</color> + <color name="i_am_color_1f8">#000001f8</color> + <color name="i_am_color_1f9">#000001f9</color> + <color name="i_am_color_1fa">#000001fa</color> + <color name="i_am_color_1fb">#000001fb</color> + <color name="i_am_color_1fc">#000001fc</color> + <color name="i_am_color_1fd">#000001fd</color> + <color name="i_am_color_1fe">#000001fe</color> + <color name="i_am_color_1ff">#000001ff</color> + <color name="i_am_color_200">#00000200</color> + <color name="i_am_color_201">#00000201</color> + <color name="i_am_color_202">#00000202</color> + <color name="i_am_color_203">#00000203</color> + <color name="i_am_color_204">#00000204</color> + <color name="i_am_color_205">#00000205</color> + <color name="i_am_color_206">#00000206</color> + <color name="i_am_color_207">#00000207</color> + <color name="i_am_color_208">#00000208</color> + <color name="i_am_color_209">#00000209</color> + <color name="i_am_color_20a">#0000020a</color> + <color name="i_am_color_20b">#0000020b</color> + <color name="i_am_color_20c">#0000020c</color> + <color name="i_am_color_20d">#0000020d</color> + <color name="i_am_color_20e">#0000020e</color> + <color name="i_am_color_20f">#0000020f</color> + <color name="i_am_color_210">#00000210</color> + <color name="i_am_color_211">#00000211</color> + <color name="i_am_color_212">#00000212</color> + <color name="i_am_color_213">#00000213</color> + <color name="i_am_color_214">#00000214</color> + <color name="i_am_color_215">#00000215</color> + <color name="i_am_color_216">#00000216</color> + <color name="i_am_color_217">#00000217</color> + <color name="i_am_color_218">#00000218</color> + <color name="i_am_color_219">#00000219</color> + <color name="i_am_color_21a">#0000021a</color> + <color name="i_am_color_21b">#0000021b</color> + <color name="i_am_color_21c">#0000021c</color> + <color name="i_am_color_21d">#0000021d</color> + <color name="i_am_color_21e">#0000021e</color> + <color name="i_am_color_21f">#0000021f</color> + <color name="i_am_color_220">#00000220</color> + <color name="i_am_color_221">#00000221</color> + <color name="i_am_color_222">#00000222</color> + <color name="i_am_color_223">#00000223</color> + <color name="i_am_color_224">#00000224</color> + <color name="i_am_color_225">#00000225</color> + <color name="i_am_color_226">#00000226</color> + <color name="i_am_color_227">#00000227</color> + <color name="i_am_color_228">#00000228</color> + <color name="i_am_color_229">#00000229</color> + <color name="i_am_color_22a">#0000022a</color> + <color name="i_am_color_22b">#0000022b</color> + <color name="i_am_color_22c">#0000022c</color> + <color name="i_am_color_22d">#0000022d</color> + <color name="i_am_color_22e">#0000022e</color> + <color name="i_am_color_22f">#0000022f</color> + <color name="i_am_color_230">#00000230</color> + <color name="i_am_color_231">#00000231</color> + <color name="i_am_color_232">#00000232</color> + <color name="i_am_color_233">#00000233</color> + <color name="i_am_color_234">#00000234</color> + <color name="i_am_color_235">#00000235</color> + <color name="i_am_color_236">#00000236</color> + <color name="i_am_color_237">#00000237</color> + <color name="i_am_color_238">#00000238</color> + <color name="i_am_color_239">#00000239</color> + <color name="i_am_color_23a">#0000023a</color> + <color name="i_am_color_23b">#0000023b</color> + <color name="i_am_color_23c">#0000023c</color> + <color name="i_am_color_23d">#0000023d</color> + <color name="i_am_color_23e">#0000023e</color> + <color name="i_am_color_23f">#0000023f</color> + <color name="i_am_color_240">#00000240</color> + <color name="i_am_color_241">#00000241</color> + <color name="i_am_color_242">#00000242</color> + <color name="i_am_color_243">#00000243</color> + <color name="i_am_color_244">#00000244</color> + <color name="i_am_color_245">#00000245</color> + <color name="i_am_color_246">#00000246</color> + <color name="i_am_color_247">#00000247</color> + <color name="i_am_color_248">#00000248</color> + <color name="i_am_color_249">#00000249</color> + <color name="i_am_color_24a">#0000024a</color> + <color name="i_am_color_24b">#0000024b</color> + <color name="i_am_color_24c">#0000024c</color> + <color name="i_am_color_24d">#0000024d</color> + <color name="i_am_color_24e">#0000024e</color> + <color name="i_am_color_24f">#0000024f</color> + <color name="i_am_color_250">#00000250</color> + <color name="i_am_color_251">#00000251</color> + <color name="i_am_color_252">#00000252</color> + <color name="i_am_color_253">#00000253</color> + <color name="i_am_color_254">#00000254</color> + <color name="i_am_color_255">#00000255</color> + <color name="i_am_color_256">#00000256</color> + <color name="i_am_color_257">#00000257</color> + <color name="i_am_color_258">#00000258</color> + <color name="i_am_color_259">#00000259</color> + <color name="i_am_color_25a">#0000025a</color> + <color name="i_am_color_25b">#0000025b</color> + <color name="i_am_color_25c">#0000025c</color> + <color name="i_am_color_25d">#0000025d</color> + <color name="i_am_color_25e">#0000025e</color> + <color name="i_am_color_25f">#0000025f</color> + <color name="i_am_color_260">#00000260</color> + <color name="i_am_color_261">#00000261</color> + <color name="i_am_color_262">#00000262</color> + <color name="i_am_color_263">#00000263</color> + <color name="i_am_color_264">#00000264</color> + <color name="i_am_color_265">#00000265</color> + <color name="i_am_color_266">#00000266</color> + <color name="i_am_color_267">#00000267</color> + <color name="i_am_color_268">#00000268</color> + <color name="i_am_color_269">#00000269</color> + <color name="i_am_color_26a">#0000026a</color> + <color name="i_am_color_26b">#0000026b</color> + <color name="i_am_color_26c">#0000026c</color> + <color name="i_am_color_26d">#0000026d</color> + <color name="i_am_color_26e">#0000026e</color> + <color name="i_am_color_26f">#0000026f</color> + <color name="i_am_color_270">#00000270</color> + <color name="i_am_color_271">#00000271</color> + <color name="i_am_color_272">#00000272</color> + <color name="i_am_color_273">#00000273</color> + <color name="i_am_color_274">#00000274</color> + <color name="i_am_color_275">#00000275</color> + <color name="i_am_color_276">#00000276</color> + <color name="i_am_color_277">#00000277</color> + <color name="i_am_color_278">#00000278</color> + <color name="i_am_color_279">#00000279</color> + <color name="i_am_color_27a">#0000027a</color> + <color name="i_am_color_27b">#0000027b</color> + <color name="i_am_color_27c">#0000027c</color> + <color name="i_am_color_27d">#0000027d</color> + <color name="i_am_color_27e">#0000027e</color> + <color name="i_am_color_27f">#0000027f</color> + <color name="i_am_color_280">#00000280</color> + <color name="i_am_color_281">#00000281</color> + <color name="i_am_color_282">#00000282</color> + <color name="i_am_color_283">#00000283</color> + <color name="i_am_color_284">#00000284</color> + <color name="i_am_color_285">#00000285</color> + <color name="i_am_color_286">#00000286</color> + <color name="i_am_color_287">#00000287</color> + <color name="i_am_color_288">#00000288</color> + <color name="i_am_color_289">#00000289</color> + <color name="i_am_color_28a">#0000028a</color> + <color name="i_am_color_28b">#0000028b</color> + <color name="i_am_color_28c">#0000028c</color> + <color name="i_am_color_28d">#0000028d</color> + <color name="i_am_color_28e">#0000028e</color> + <color name="i_am_color_28f">#0000028f</color> + <color name="i_am_color_290">#00000290</color> + <color name="i_am_color_291">#00000291</color> + <color name="i_am_color_292">#00000292</color> + <color name="i_am_color_293">#00000293</color> + <color name="i_am_color_294">#00000294</color> + <color name="i_am_color_295">#00000295</color> + <color name="i_am_color_296">#00000296</color> + <color name="i_am_color_297">#00000297</color> + <color name="i_am_color_298">#00000298</color> + <color name="i_am_color_299">#00000299</color> + <color name="i_am_color_29a">#0000029a</color> + <color name="i_am_color_29b">#0000029b</color> + <color name="i_am_color_29c">#0000029c</color> + <color name="i_am_color_29d">#0000029d</color> + <color name="i_am_color_29e">#0000029e</color> + <color name="i_am_color_29f">#0000029f</color> + <color name="i_am_color_2a0">#000002a0</color> + <color name="i_am_color_2a1">#000002a1</color> + <color name="i_am_color_2a2">#000002a2</color> + <color name="i_am_color_2a3">#000002a3</color> + <color name="i_am_color_2a4">#000002a4</color> + <color name="i_am_color_2a5">#000002a5</color> + <color name="i_am_color_2a6">#000002a6</color> + <color name="i_am_color_2a7">#000002a7</color> + <color name="i_am_color_2a8">#000002a8</color> + <color name="i_am_color_2a9">#000002a9</color> + <color name="i_am_color_2aa">#000002aa</color> + <color name="i_am_color_2ab">#000002ab</color> + <color name="i_am_color_2ac">#000002ac</color> + <color name="i_am_color_2ad">#000002ad</color> + <color name="i_am_color_2ae">#000002ae</color> + <color name="i_am_color_2af">#000002af</color> + <color name="i_am_color_2b0">#000002b0</color> + <color name="i_am_color_2b1">#000002b1</color> + <color name="i_am_color_2b2">#000002b2</color> + <color name="i_am_color_2b3">#000002b3</color> + <color name="i_am_color_2b4">#000002b4</color> + <color name="i_am_color_2b5">#000002b5</color> + <color name="i_am_color_2b6">#000002b6</color> + <color name="i_am_color_2b7">#000002b7</color> + <color name="i_am_color_2b8">#000002b8</color> + <color name="i_am_color_2b9">#000002b9</color> + <color name="i_am_color_2ba">#000002ba</color> + <color name="i_am_color_2bb">#000002bb</color> + <color name="i_am_color_2bc">#000002bc</color> + <color name="i_am_color_2bd">#000002bd</color> + <color name="i_am_color_2be">#000002be</color> + <color name="i_am_color_2bf">#000002bf</color> + <color name="i_am_color_2c0">#000002c0</color> + <color name="i_am_color_2c1">#000002c1</color> + <color name="i_am_color_2c2">#000002c2</color> + <color name="i_am_color_2c3">#000002c3</color> + <color name="i_am_color_2c4">#000002c4</color> + <color name="i_am_color_2c5">#000002c5</color> + <color name="i_am_color_2c6">#000002c6</color> + <color name="i_am_color_2c7">#000002c7</color> + <color name="i_am_color_2c8">#000002c8</color> + <color name="i_am_color_2c9">#000002c9</color> + <color name="i_am_color_2ca">#000002ca</color> + <color name="i_am_color_2cb">#000002cb</color> + <color name="i_am_color_2cc">#000002cc</color> + <color name="i_am_color_2cd">#000002cd</color> + <color name="i_am_color_2ce">#000002ce</color> + <color name="i_am_color_2cf">#000002cf</color> + <color name="i_am_color_2d0">#000002d0</color> + <color name="i_am_color_2d1">#000002d1</color> + <color name="i_am_color_2d2">#000002d2</color> + <color name="i_am_color_2d3">#000002d3</color> + <color name="i_am_color_2d4">#000002d4</color> + <color name="i_am_color_2d5">#000002d5</color> + <color name="i_am_color_2d6">#000002d6</color> + <color name="i_am_color_2d7">#000002d7</color> + <color name="i_am_color_2d8">#000002d8</color> + <color name="i_am_color_2d9">#000002d9</color> + <color name="i_am_color_2da">#000002da</color> + <color name="i_am_color_2db">#000002db</color> + <color name="i_am_color_2dc">#000002dc</color> + <color name="i_am_color_2dd">#000002dd</color> + <color name="i_am_color_2de">#000002de</color> + <color name="i_am_color_2df">#000002df</color> + <color name="i_am_color_2e0">#000002e0</color> + <color name="i_am_color_2e1">#000002e1</color> + <color name="i_am_color_2e2">#000002e2</color> + <color name="i_am_color_2e3">#000002e3</color> + <color name="i_am_color_2e4">#000002e4</color> + <color name="i_am_color_2e5">#000002e5</color> + <color name="i_am_color_2e6">#000002e6</color> + <color name="i_am_color_2e7">#000002e7</color> + <color name="i_am_color_2e8">#000002e8</color> + <color name="i_am_color_2e9">#000002e9</color> + <color name="i_am_color_2ea">#000002ea</color> + <color name="i_am_color_2eb">#000002eb</color> + <color name="i_am_color_2ec">#000002ec</color> + <color name="i_am_color_2ed">#000002ed</color> + <color name="i_am_color_2ee">#000002ee</color> + <color name="i_am_color_2ef">#000002ef</color> + <color name="i_am_color_2f0">#000002f0</color> + <color name="i_am_color_2f1">#000002f1</color> + <color name="i_am_color_2f2">#000002f2</color> + <color name="i_am_color_2f3">#000002f3</color> + <color name="i_am_color_2f4">#000002f4</color> + <color name="i_am_color_2f5">#000002f5</color> + <color name="i_am_color_2f6">#000002f6</color> + <color name="i_am_color_2f7">#000002f7</color> + <color name="i_am_color_2f8">#000002f8</color> + <color name="i_am_color_2f9">#000002f9</color> + <color name="i_am_color_2fa">#000002fa</color> + <color name="i_am_color_2fb">#000002fb</color> + <color name="i_am_color_2fc">#000002fc</color> + <color name="i_am_color_2fd">#000002fd</color> + <color name="i_am_color_2fe">#000002fe</color> + <color name="i_am_color_2ff">#000002ff</color> + <color name="i_am_color_300">#00000300</color> + <color name="i_am_color_301">#00000301</color> + <color name="i_am_color_302">#00000302</color> + <color name="i_am_color_303">#00000303</color> + <color name="i_am_color_304">#00000304</color> + <color name="i_am_color_305">#00000305</color> + <color name="i_am_color_306">#00000306</color> + <color name="i_am_color_307">#00000307</color> + <color name="i_am_color_308">#00000308</color> + <color name="i_am_color_309">#00000309</color> + <color name="i_am_color_30a">#0000030a</color> + <color name="i_am_color_30b">#0000030b</color> + <color name="i_am_color_30c">#0000030c</color> + <color name="i_am_color_30d">#0000030d</color> + <color name="i_am_color_30e">#0000030e</color> + <color name="i_am_color_30f">#0000030f</color> + <color name="i_am_color_310">#00000310</color> + <color name="i_am_color_311">#00000311</color> + <color name="i_am_color_312">#00000312</color> + <color name="i_am_color_313">#00000313</color> + <color name="i_am_color_314">#00000314</color> + <color name="i_am_color_315">#00000315</color> + <color name="i_am_color_316">#00000316</color> + <color name="i_am_color_317">#00000317</color> + <color name="i_am_color_318">#00000318</color> + <color name="i_am_color_319">#00000319</color> + <color name="i_am_color_31a">#0000031a</color> + <color name="i_am_color_31b">#0000031b</color> + <color name="i_am_color_31c">#0000031c</color> + <color name="i_am_color_31d">#0000031d</color> + <color name="i_am_color_31e">#0000031e</color> + <color name="i_am_color_31f">#0000031f</color> + <color name="i_am_color_320">#00000320</color> + <color name="i_am_color_321">#00000321</color> + <color name="i_am_color_322">#00000322</color> + <color name="i_am_color_323">#00000323</color> + <color name="i_am_color_324">#00000324</color> + <color name="i_am_color_325">#00000325</color> + <color name="i_am_color_326">#00000326</color> + <color name="i_am_color_327">#00000327</color> + <color name="i_am_color_328">#00000328</color> + <color name="i_am_color_329">#00000329</color> + <color name="i_am_color_32a">#0000032a</color> + <color name="i_am_color_32b">#0000032b</color> + <color name="i_am_color_32c">#0000032c</color> + <color name="i_am_color_32d">#0000032d</color> + <color name="i_am_color_32e">#0000032e</color> + <color name="i_am_color_32f">#0000032f</color> + <color name="i_am_color_330">#00000330</color> + <color name="i_am_color_331">#00000331</color> + <color name="i_am_color_332">#00000332</color> + <color name="i_am_color_333">#00000333</color> + <color name="i_am_color_334">#00000334</color> + <color name="i_am_color_335">#00000335</color> + <color name="i_am_color_336">#00000336</color> + <color name="i_am_color_337">#00000337</color> + <color name="i_am_color_338">#00000338</color> + <color name="i_am_color_339">#00000339</color> + <color name="i_am_color_33a">#0000033a</color> + <color name="i_am_color_33b">#0000033b</color> + <color name="i_am_color_33c">#0000033c</color> + <color name="i_am_color_33d">#0000033d</color> + <color name="i_am_color_33e">#0000033e</color> + <color name="i_am_color_33f">#0000033f</color> + <color name="i_am_color_340">#00000340</color> + <color name="i_am_color_341">#00000341</color> + <color name="i_am_color_342">#00000342</color> + <color name="i_am_color_343">#00000343</color> + <color name="i_am_color_344">#00000344</color> + <color name="i_am_color_345">#00000345</color> + <color name="i_am_color_346">#00000346</color> + <color name="i_am_color_347">#00000347</color> + <color name="i_am_color_348">#00000348</color> + <color name="i_am_color_349">#00000349</color> + <color name="i_am_color_34a">#0000034a</color> + <color name="i_am_color_34b">#0000034b</color> + <color name="i_am_color_34c">#0000034c</color> + <color name="i_am_color_34d">#0000034d</color> + <color name="i_am_color_34e">#0000034e</color> + <color name="i_am_color_34f">#0000034f</color> + <color name="i_am_color_350">#00000350</color> + <color name="i_am_color_351">#00000351</color> + <color name="i_am_color_352">#00000352</color> + <color name="i_am_color_353">#00000353</color> + <color name="i_am_color_354">#00000354</color> + <color name="i_am_color_355">#00000355</color> + <color name="i_am_color_356">#00000356</color> + <color name="i_am_color_357">#00000357</color> + <color name="i_am_color_358">#00000358</color> + <color name="i_am_color_359">#00000359</color> + <color name="i_am_color_35a">#0000035a</color> + <color name="i_am_color_35b">#0000035b</color> + <color name="i_am_color_35c">#0000035c</color> + <color name="i_am_color_35d">#0000035d</color> + <color name="i_am_color_35e">#0000035e</color> + <color name="i_am_color_35f">#0000035f</color> + <color name="i_am_color_360">#00000360</color> + <color name="i_am_color_361">#00000361</color> + <color name="i_am_color_362">#00000362</color> + <color name="i_am_color_363">#00000363</color> + <color name="i_am_color_364">#00000364</color> + <color name="i_am_color_365">#00000365</color> + <color name="i_am_color_366">#00000366</color> + <color name="i_am_color_367">#00000367</color> + <color name="i_am_color_368">#00000368</color> + <color name="i_am_color_369">#00000369</color> + <color name="i_am_color_36a">#0000036a</color> + <color name="i_am_color_36b">#0000036b</color> + <color name="i_am_color_36c">#0000036c</color> + <color name="i_am_color_36d">#0000036d</color> + <color name="i_am_color_36e">#0000036e</color> + <color name="i_am_color_36f">#0000036f</color> + <color name="i_am_color_370">#00000370</color> + <color name="i_am_color_371">#00000371</color> + <color name="i_am_color_372">#00000372</color> + <color name="i_am_color_373">#00000373</color> + <color name="i_am_color_374">#00000374</color> + <color name="i_am_color_375">#00000375</color> + <color name="i_am_color_376">#00000376</color> + <color name="i_am_color_377">#00000377</color> + <color name="i_am_color_378">#00000378</color> + <color name="i_am_color_379">#00000379</color> + <color name="i_am_color_37a">#0000037a</color> + <color name="i_am_color_37b">#0000037b</color> + <color name="i_am_color_37c">#0000037c</color> + <color name="i_am_color_37d">#0000037d</color> + <color name="i_am_color_37e">#0000037e</color> + <color name="i_am_color_37f">#0000037f</color> + <color name="i_am_color_380">#00000380</color> + <color name="i_am_color_381">#00000381</color> + <color name="i_am_color_382">#00000382</color> + <color name="i_am_color_383">#00000383</color> + <color name="i_am_color_384">#00000384</color> + <color name="i_am_color_385">#00000385</color> + <color name="i_am_color_386">#00000386</color> + <color name="i_am_color_387">#00000387</color> + <color name="i_am_color_388">#00000388</color> + <color name="i_am_color_389">#00000389</color> + <color name="i_am_color_38a">#0000038a</color> + <color name="i_am_color_38b">#0000038b</color> + <color name="i_am_color_38c">#0000038c</color> + <color name="i_am_color_38d">#0000038d</color> + <color name="i_am_color_38e">#0000038e</color> + <color name="i_am_color_38f">#0000038f</color> + <color name="i_am_color_390">#00000390</color> + <color name="i_am_color_391">#00000391</color> + <color name="i_am_color_392">#00000392</color> + <color name="i_am_color_393">#00000393</color> + <color name="i_am_color_394">#00000394</color> + <color name="i_am_color_395">#00000395</color> + <color name="i_am_color_396">#00000396</color> + <color name="i_am_color_397">#00000397</color> + <color name="i_am_color_398">#00000398</color> + <color name="i_am_color_399">#00000399</color> + <color name="i_am_color_39a">#0000039a</color> + <color name="i_am_color_39b">#0000039b</color> + <color name="i_am_color_39c">#0000039c</color> + <color name="i_am_color_39d">#0000039d</color> + <color name="i_am_color_39e">#0000039e</color> + <color name="i_am_color_39f">#0000039f</color> + <color name="i_am_color_3a0">#000003a0</color> + <color name="i_am_color_3a1">#000003a1</color> + <color name="i_am_color_3a2">#000003a2</color> + <color name="i_am_color_3a3">#000003a3</color> + <color name="i_am_color_3a4">#000003a4</color> + <color name="i_am_color_3a5">#000003a5</color> + <color name="i_am_color_3a6">#000003a6</color> + <color name="i_am_color_3a7">#000003a7</color> + <color name="i_am_color_3a8">#000003a8</color> + <color name="i_am_color_3a9">#000003a9</color> + <color name="i_am_color_3aa">#000003aa</color> + <color name="i_am_color_3ab">#000003ab</color> + <color name="i_am_color_3ac">#000003ac</color> + <color name="i_am_color_3ad">#000003ad</color> + <color name="i_am_color_3ae">#000003ae</color> + <color name="i_am_color_3af">#000003af</color> + <color name="i_am_color_3b0">#000003b0</color> + <color name="i_am_color_3b1">#000003b1</color> + <color name="i_am_color_3b2">#000003b2</color> + <color name="i_am_color_3b3">#000003b3</color> + <color name="i_am_color_3b4">#000003b4</color> + <color name="i_am_color_3b5">#000003b5</color> + <color name="i_am_color_3b6">#000003b6</color> + <color name="i_am_color_3b7">#000003b7</color> + <color name="i_am_color_3b8">#000003b8</color> + <color name="i_am_color_3b9">#000003b9</color> + <color name="i_am_color_3ba">#000003ba</color> + <color name="i_am_color_3bb">#000003bb</color> + <color name="i_am_color_3bc">#000003bc</color> + <color name="i_am_color_3bd">#000003bd</color> + <color name="i_am_color_3be">#000003be</color> + <color name="i_am_color_3bf">#000003bf</color> + <color name="i_am_color_3c0">#000003c0</color> + <color name="i_am_color_3c1">#000003c1</color> + <color name="i_am_color_3c2">#000003c2</color> + <color name="i_am_color_3c3">#000003c3</color> + <color name="i_am_color_3c4">#000003c4</color> + <color name="i_am_color_3c5">#000003c5</color> + <color name="i_am_color_3c6">#000003c6</color> + <color name="i_am_color_3c7">#000003c7</color> + <color name="i_am_color_3c8">#000003c8</color> + <color name="i_am_color_3c9">#000003c9</color> + <color name="i_am_color_3ca">#000003ca</color> + <color name="i_am_color_3cb">#000003cb</color> + <color name="i_am_color_3cc">#000003cc</color> + <color name="i_am_color_3cd">#000003cd</color> + <color name="i_am_color_3ce">#000003ce</color> + <color name="i_am_color_3cf">#000003cf</color> + <color name="i_am_color_3d0">#000003d0</color> + <color name="i_am_color_3d1">#000003d1</color> + <color name="i_am_color_3d2">#000003d2</color> + <color name="i_am_color_3d3">#000003d3</color> + <color name="i_am_color_3d4">#000003d4</color> + <color name="i_am_color_3d5">#000003d5</color> + <color name="i_am_color_3d6">#000003d6</color> + <color name="i_am_color_3d7">#000003d7</color> + <color name="i_am_color_3d8">#000003d8</color> + <color name="i_am_color_3d9">#000003d9</color> + <color name="i_am_color_3da">#000003da</color> + <color name="i_am_color_3db">#000003db</color> + <color name="i_am_color_3dc">#000003dc</color> + <color name="i_am_color_3dd">#000003dd</color> + <color name="i_am_color_3de">#000003de</color> + <color name="i_am_color_3df">#000003df</color> + <color name="i_am_color_3e0">#000003e0</color> + <color name="i_am_color_3e1">#000003e1</color> + <color name="i_am_color_3e2">#000003e2</color> + <color name="i_am_color_3e3">#000003e3</color> + <color name="i_am_color_3e4">#000003e4</color> + <color name="i_am_color_3e5">#000003e5</color> + <color name="i_am_color_3e6">#000003e6</color> + <color name="i_am_color_3e7">#000003e7</color> + <color name="i_am_color_3e8">#000003e8</color> + <color name="i_am_color_3e9">#000003e9</color> + <color name="i_am_color_3ea">#000003ea</color> + <color name="i_am_color_3eb">#000003eb</color> + <color name="i_am_color_3ec">#000003ec</color> + <color name="i_am_color_3ed">#000003ed</color> + <color name="i_am_color_3ee">#000003ee</color> + <color name="i_am_color_3ef">#000003ef</color> + <color name="i_am_color_3f0">#000003f0</color> + <color name="i_am_color_3f1">#000003f1</color> + <color name="i_am_color_3f2">#000003f2</color> + <color name="i_am_color_3f3">#000003f3</color> + <color name="i_am_color_3f4">#000003f4</color> + <color name="i_am_color_3f5">#000003f5</color> + <color name="i_am_color_3f6">#000003f6</color> + <color name="i_am_color_3f7">#000003f7</color> + <color name="i_am_color_3f8">#000003f8</color> + <color name="i_am_color_3f9">#000003f9</color> + <color name="i_am_color_3fa">#000003fa</color> + <color name="i_am_color_3fb">#000003fb</color> + <color name="i_am_color_3fc">#000003fc</color> + <color name="i_am_color_3fd">#000003fd</color> + <color name="i_am_color_3fe">#000003fe</color> + <color name="i_am_color_3ff">#000003ff</color> + <color name="i_am_color_400">#00000400</color> + <color name="i_am_color_401">#00000401</color> + <color name="i_am_color_402">#00000402</color> + <color name="i_am_color_403">#00000403</color> + <color name="i_am_color_404">#00000404</color> + <color name="i_am_color_405">#00000405</color> + <color name="i_am_color_406">#00000406</color> + <color name="i_am_color_407">#00000407</color> + <color name="i_am_color_408">#00000408</color> + <color name="i_am_color_409">#00000409</color> + <color name="i_am_color_40a">#0000040a</color> + <color name="i_am_color_40b">#0000040b</color> + <color name="i_am_color_40c">#0000040c</color> + <color name="i_am_color_40d">#0000040d</color> + <color name="i_am_color_40e">#0000040e</color> + <color name="i_am_color_40f">#0000040f</color> + <color name="i_am_color_410">#00000410</color> + <color name="i_am_color_411">#00000411</color> + <color name="i_am_color_412">#00000412</color> + <color name="i_am_color_413">#00000413</color> + <color name="i_am_color_414">#00000414</color> + <color name="i_am_color_415">#00000415</color> + <color name="i_am_color_416">#00000416</color> + <color name="i_am_color_417">#00000417</color> + <color name="i_am_color_418">#00000418</color> + <color name="i_am_color_419">#00000419</color> + <color name="i_am_color_41a">#0000041a</color> + <color name="i_am_color_41b">#0000041b</color> + <color name="i_am_color_41c">#0000041c</color> + <color name="i_am_color_41d">#0000041d</color> + <color name="i_am_color_41e">#0000041e</color> + <color name="i_am_color_41f">#0000041f</color> + <color name="i_am_color_420">#00000420</color> + <color name="i_am_color_421">#00000421</color> + <color name="i_am_color_422">#00000422</color> + <color name="i_am_color_423">#00000423</color> + <color name="i_am_color_424">#00000424</color> + <color name="i_am_color_425">#00000425</color> + <color name="i_am_color_426">#00000426</color> + <color name="i_am_color_427">#00000427</color> + <color name="i_am_color_428">#00000428</color> + <color name="i_am_color_429">#00000429</color> + <color name="i_am_color_42a">#0000042a</color> + <color name="i_am_color_42b">#0000042b</color> + <color name="i_am_color_42c">#0000042c</color> + <color name="i_am_color_42d">#0000042d</color> + <color name="i_am_color_42e">#0000042e</color> + <color name="i_am_color_42f">#0000042f</color> + <color name="i_am_color_430">#00000430</color> + <color name="i_am_color_431">#00000431</color> + <color name="i_am_color_432">#00000432</color> + <color name="i_am_color_433">#00000433</color> + <color name="i_am_color_434">#00000434</color> + <color name="i_am_color_435">#00000435</color> + <color name="i_am_color_436">#00000436</color> + <color name="i_am_color_437">#00000437</color> + <color name="i_am_color_438">#00000438</color> + <color name="i_am_color_439">#00000439</color> + <color name="i_am_color_43a">#0000043a</color> + <color name="i_am_color_43b">#0000043b</color> + <color name="i_am_color_43c">#0000043c</color> + <color name="i_am_color_43d">#0000043d</color> + <color name="i_am_color_43e">#0000043e</color> + <color name="i_am_color_43f">#0000043f</color> + <color name="i_am_color_440">#00000440</color> + <color name="i_am_color_441">#00000441</color> + <color name="i_am_color_442">#00000442</color> + <color name="i_am_color_443">#00000443</color> + <color name="i_am_color_444">#00000444</color> + <color name="i_am_color_445">#00000445</color> + <color name="i_am_color_446">#00000446</color> + <color name="i_am_color_447">#00000447</color> + <color name="i_am_color_448">#00000448</color> + <color name="i_am_color_449">#00000449</color> + <color name="i_am_color_44a">#0000044a</color> + <color name="i_am_color_44b">#0000044b</color> + <color name="i_am_color_44c">#0000044c</color> + <color name="i_am_color_44d">#0000044d</color> + <color name="i_am_color_44e">#0000044e</color> + <color name="i_am_color_44f">#0000044f</color> + <color name="i_am_color_450">#00000450</color> + <color name="i_am_color_451">#00000451</color> + <color name="i_am_color_452">#00000452</color> + <color name="i_am_color_453">#00000453</color> + <color name="i_am_color_454">#00000454</color> + <color name="i_am_color_455">#00000455</color> + <color name="i_am_color_456">#00000456</color> + <color name="i_am_color_457">#00000457</color> + <color name="i_am_color_458">#00000458</color> + <color name="i_am_color_459">#00000459</color> + <color name="i_am_color_45a">#0000045a</color> + <color name="i_am_color_45b">#0000045b</color> + <color name="i_am_color_45c">#0000045c</color> + <color name="i_am_color_45d">#0000045d</color> + <color name="i_am_color_45e">#0000045e</color> + <color name="i_am_color_45f">#0000045f</color> + <color name="i_am_color_460">#00000460</color> + <color name="i_am_color_461">#00000461</color> + <color name="i_am_color_462">#00000462</color> + <color name="i_am_color_463">#00000463</color> + <color name="i_am_color_464">#00000464</color> + <color name="i_am_color_465">#00000465</color> + <color name="i_am_color_466">#00000466</color> + <color name="i_am_color_467">#00000467</color> + <color name="i_am_color_468">#00000468</color> + <color name="i_am_color_469">#00000469</color> + <color name="i_am_color_46a">#0000046a</color> + <color name="i_am_color_46b">#0000046b</color> + <color name="i_am_color_46c">#0000046c</color> + <color name="i_am_color_46d">#0000046d</color> + <color name="i_am_color_46e">#0000046e</color> + <color name="i_am_color_46f">#0000046f</color> + <color name="i_am_color_470">#00000470</color> + <color name="i_am_color_471">#00000471</color> + <color name="i_am_color_472">#00000472</color> + <color name="i_am_color_473">#00000473</color> + <color name="i_am_color_474">#00000474</color> + <color name="i_am_color_475">#00000475</color> + <color name="i_am_color_476">#00000476</color> + <color name="i_am_color_477">#00000477</color> + <color name="i_am_color_478">#00000478</color> + <color name="i_am_color_479">#00000479</color> + <color name="i_am_color_47a">#0000047a</color> + <color name="i_am_color_47b">#0000047b</color> + <color name="i_am_color_47c">#0000047c</color> + <color name="i_am_color_47d">#0000047d</color> + <color name="i_am_color_47e">#0000047e</color> + <color name="i_am_color_47f">#0000047f</color> + <color name="i_am_color_480">#00000480</color> + <color name="i_am_color_481">#00000481</color> + <color name="i_am_color_482">#00000482</color> + <color name="i_am_color_483">#00000483</color> + <color name="i_am_color_484">#00000484</color> + <color name="i_am_color_485">#00000485</color> + <color name="i_am_color_486">#00000486</color> + <color name="i_am_color_487">#00000487</color> + <color name="i_am_color_488">#00000488</color> + <color name="i_am_color_489">#00000489</color> + <color name="i_am_color_48a">#0000048a</color> + <color name="i_am_color_48b">#0000048b</color> + <color name="i_am_color_48c">#0000048c</color> + <color name="i_am_color_48d">#0000048d</color> + <color name="i_am_color_48e">#0000048e</color> + <color name="i_am_color_48f">#0000048f</color> + <color name="i_am_color_490">#00000490</color> + <color name="i_am_color_491">#00000491</color> + <color name="i_am_color_492">#00000492</color> + <color name="i_am_color_493">#00000493</color> + <color name="i_am_color_494">#00000494</color> + <color name="i_am_color_495">#00000495</color> + <color name="i_am_color_496">#00000496</color> + <color name="i_am_color_497">#00000497</color> + <color name="i_am_color_498">#00000498</color> + <color name="i_am_color_499">#00000499</color> + <color name="i_am_color_49a">#0000049a</color> + <color name="i_am_color_49b">#0000049b</color> + <color name="i_am_color_49c">#0000049c</color> + <color name="i_am_color_49d">#0000049d</color> + <color name="i_am_color_49e">#0000049e</color> + <color name="i_am_color_49f">#0000049f</color> + <color name="i_am_color_4a0">#000004a0</color> + <color name="i_am_color_4a1">#000004a1</color> + <color name="i_am_color_4a2">#000004a2</color> + <color name="i_am_color_4a3">#000004a3</color> + <color name="i_am_color_4a4">#000004a4</color> + <color name="i_am_color_4a5">#000004a5</color> + <color name="i_am_color_4a6">#000004a6</color> + <color name="i_am_color_4a7">#000004a7</color> + <color name="i_am_color_4a8">#000004a8</color> + <color name="i_am_color_4a9">#000004a9</color> + <color name="i_am_color_4aa">#000004aa</color> + <color name="i_am_color_4ab">#000004ab</color> + <color name="i_am_color_4ac">#000004ac</color> + <color name="i_am_color_4ad">#000004ad</color> + <color name="i_am_color_4ae">#000004ae</color> + <color name="i_am_color_4af">#000004af</color> + <color name="i_am_color_4b0">#000004b0</color> + <color name="i_am_color_4b1">#000004b1</color> + <color name="i_am_color_4b2">#000004b2</color> + <color name="i_am_color_4b3">#000004b3</color> + <color name="i_am_color_4b4">#000004b4</color> + <color name="i_am_color_4b5">#000004b5</color> + <color name="i_am_color_4b6">#000004b6</color> + <color name="i_am_color_4b7">#000004b7</color> + <color name="i_am_color_4b8">#000004b8</color> + <color name="i_am_color_4b9">#000004b9</color> + <color name="i_am_color_4ba">#000004ba</color> + <color name="i_am_color_4bb">#000004bb</color> + <color name="i_am_color_4bc">#000004bc</color> + <color name="i_am_color_4bd">#000004bd</color> + <color name="i_am_color_4be">#000004be</color> + <color name="i_am_color_4bf">#000004bf</color> + <color name="i_am_color_4c0">#000004c0</color> + <color name="i_am_color_4c1">#000004c1</color> + <color name="i_am_color_4c2">#000004c2</color> + <color name="i_am_color_4c3">#000004c3</color> + <color name="i_am_color_4c4">#000004c4</color> + <color name="i_am_color_4c5">#000004c5</color> + <color name="i_am_color_4c6">#000004c6</color> + <color name="i_am_color_4c7">#000004c7</color> + <color name="i_am_color_4c8">#000004c8</color> + <color name="i_am_color_4c9">#000004c9</color> + <color name="i_am_color_4ca">#000004ca</color> + <color name="i_am_color_4cb">#000004cb</color> + <color name="i_am_color_4cc">#000004cc</color> + <color name="i_am_color_4cd">#000004cd</color> + <color name="i_am_color_4ce">#000004ce</color> + <color name="i_am_color_4cf">#000004cf</color> + <color name="i_am_color_4d0">#000004d0</color> + <color name="i_am_color_4d1">#000004d1</color> + <color name="i_am_color_4d2">#000004d2</color> + <color name="i_am_color_4d3">#000004d3</color> + <color name="i_am_color_4d4">#000004d4</color> + <color name="i_am_color_4d5">#000004d5</color> + <color name="i_am_color_4d6">#000004d6</color> + <color name="i_am_color_4d7">#000004d7</color> + <color name="i_am_color_4d8">#000004d8</color> + <color name="i_am_color_4d9">#000004d9</color> + <color name="i_am_color_4da">#000004da</color> + <color name="i_am_color_4db">#000004db</color> + <color name="i_am_color_4dc">#000004dc</color> + <color name="i_am_color_4dd">#000004dd</color> + <color name="i_am_color_4de">#000004de</color> + <color name="i_am_color_4df">#000004df</color> + <color name="i_am_color_4e0">#000004e0</color> + <color name="i_am_color_4e1">#000004e1</color> + <color name="i_am_color_4e2">#000004e2</color> + <color name="i_am_color_4e3">#000004e3</color> + <color name="i_am_color_4e4">#000004e4</color> + <color name="i_am_color_4e5">#000004e5</color> + <color name="i_am_color_4e6">#000004e6</color> + <color name="i_am_color_4e7">#000004e7</color> + <color name="i_am_color_4e8">#000004e8</color> + <color name="i_am_color_4e9">#000004e9</color> + <color name="i_am_color_4ea">#000004ea</color> + <color name="i_am_color_4eb">#000004eb</color> + <color name="i_am_color_4ec">#000004ec</color> + <color name="i_am_color_4ed">#000004ed</color> + <color name="i_am_color_4ee">#000004ee</color> + <color name="i_am_color_4ef">#000004ef</color> + <color name="i_am_color_4f0">#000004f0</color> + <color name="i_am_color_4f1">#000004f1</color> + <color name="i_am_color_4f2">#000004f2</color> + <color name="i_am_color_4f3">#000004f3</color> + <color name="i_am_color_4f4">#000004f4</color> + <color name="i_am_color_4f5">#000004f5</color> + <color name="i_am_color_4f6">#000004f6</color> + <color name="i_am_color_4f7">#000004f7</color> + <color name="i_am_color_4f8">#000004f8</color> + <color name="i_am_color_4f9">#000004f9</color> + <color name="i_am_color_4fa">#000004fa</color> + <color name="i_am_color_4fb">#000004fb</color> + <color name="i_am_color_4fc">#000004fc</color> + <color name="i_am_color_4fd">#000004fd</color> + <color name="i_am_color_4fe">#000004fe</color> + <color name="i_am_color_4ff">#000004ff</color> + <color name="i_am_color_500">#00000500</color> + <color name="i_am_color_501">#00000501</color> + <color name="i_am_color_502">#00000502</color> + <color name="i_am_color_503">#00000503</color> + <color name="i_am_color_504">#00000504</color> + <color name="i_am_color_505">#00000505</color> + <color name="i_am_color_506">#00000506</color> + <color name="i_am_color_507">#00000507</color> + <color name="i_am_color_508">#00000508</color> + <color name="i_am_color_509">#00000509</color> + <color name="i_am_color_50a">#0000050a</color> + <color name="i_am_color_50b">#0000050b</color> + <color name="i_am_color_50c">#0000050c</color> + <color name="i_am_color_50d">#0000050d</color> + <color name="i_am_color_50e">#0000050e</color> + <color name="i_am_color_50f">#0000050f</color> + <color name="i_am_color_510">#00000510</color> + <color name="i_am_color_511">#00000511</color> + <color name="i_am_color_512">#00000512</color> + <color name="i_am_color_513">#00000513</color> + <color name="i_am_color_514">#00000514</color> + <color name="i_am_color_515">#00000515</color> + <color name="i_am_color_516">#00000516</color> + <color name="i_am_color_517">#00000517</color> + <color name="i_am_color_518">#00000518</color> + <color name="i_am_color_519">#00000519</color> + <color name="i_am_color_51a">#0000051a</color> + <color name="i_am_color_51b">#0000051b</color> + <color name="i_am_color_51c">#0000051c</color> + <color name="i_am_color_51d">#0000051d</color> + <color name="i_am_color_51e">#0000051e</color> + <color name="i_am_color_51f">#0000051f</color> + <color name="i_am_color_520">#00000520</color> + <color name="i_am_color_521">#00000521</color> + <color name="i_am_color_522">#00000522</color> + <color name="i_am_color_523">#00000523</color> + <color name="i_am_color_524">#00000524</color> + <color name="i_am_color_525">#00000525</color> + <color name="i_am_color_526">#00000526</color> + <color name="i_am_color_527">#00000527</color> + <color name="i_am_color_528">#00000528</color> + <color name="i_am_color_529">#00000529</color> + <color name="i_am_color_52a">#0000052a</color> + <color name="i_am_color_52b">#0000052b</color> + <color name="i_am_color_52c">#0000052c</color> + <color name="i_am_color_52d">#0000052d</color> + <color name="i_am_color_52e">#0000052e</color> + <color name="i_am_color_52f">#0000052f</color> + <color name="i_am_color_530">#00000530</color> + <color name="i_am_color_531">#00000531</color> + <color name="i_am_color_532">#00000532</color> + <color name="i_am_color_533">#00000533</color> + <color name="i_am_color_534">#00000534</color> + <color name="i_am_color_535">#00000535</color> + <color name="i_am_color_536">#00000536</color> + <color name="i_am_color_537">#00000537</color> + <color name="i_am_color_538">#00000538</color> + <color name="i_am_color_539">#00000539</color> + <color name="i_am_color_53a">#0000053a</color> + <color name="i_am_color_53b">#0000053b</color> + <color name="i_am_color_53c">#0000053c</color> + <color name="i_am_color_53d">#0000053d</color> + <color name="i_am_color_53e">#0000053e</color> + <color name="i_am_color_53f">#0000053f</color> + <color name="i_am_color_540">#00000540</color> + <color name="i_am_color_541">#00000541</color> + <color name="i_am_color_542">#00000542</color> + <color name="i_am_color_543">#00000543</color> + <color name="i_am_color_544">#00000544</color> + <color name="i_am_color_545">#00000545</color> + <color name="i_am_color_546">#00000546</color> + <color name="i_am_color_547">#00000547</color> + <color name="i_am_color_548">#00000548</color> + <color name="i_am_color_549">#00000549</color> + <color name="i_am_color_54a">#0000054a</color> + <color name="i_am_color_54b">#0000054b</color> + <color name="i_am_color_54c">#0000054c</color> + <color name="i_am_color_54d">#0000054d</color> + <color name="i_am_color_54e">#0000054e</color> + <color name="i_am_color_54f">#0000054f</color> + <color name="i_am_color_550">#00000550</color> + <color name="i_am_color_551">#00000551</color> + <color name="i_am_color_552">#00000552</color> + <color name="i_am_color_553">#00000553</color> + <color name="i_am_color_554">#00000554</color> + <color name="i_am_color_555">#00000555</color> + <color name="i_am_color_556">#00000556</color> + <color name="i_am_color_557">#00000557</color> + <color name="i_am_color_558">#00000558</color> + <color name="i_am_color_559">#00000559</color> + <color name="i_am_color_55a">#0000055a</color> + <color name="i_am_color_55b">#0000055b</color> + <color name="i_am_color_55c">#0000055c</color> + <color name="i_am_color_55d">#0000055d</color> + <color name="i_am_color_55e">#0000055e</color> + <color name="i_am_color_55f">#0000055f</color> + <color name="i_am_color_560">#00000560</color> + <color name="i_am_color_561">#00000561</color> + <color name="i_am_color_562">#00000562</color> + <color name="i_am_color_563">#00000563</color> + <color name="i_am_color_564">#00000564</color> + <color name="i_am_color_565">#00000565</color> + <color name="i_am_color_566">#00000566</color> + <color name="i_am_color_567">#00000567</color> + <color name="i_am_color_568">#00000568</color> + <color name="i_am_color_569">#00000569</color> + <color name="i_am_color_56a">#0000056a</color> + <color name="i_am_color_56b">#0000056b</color> + <color name="i_am_color_56c">#0000056c</color> + <color name="i_am_color_56d">#0000056d</color> + <color name="i_am_color_56e">#0000056e</color> + <color name="i_am_color_56f">#0000056f</color> + <color name="i_am_color_570">#00000570</color> + <color name="i_am_color_571">#00000571</color> + <color name="i_am_color_572">#00000572</color> + <color name="i_am_color_573">#00000573</color> + <color name="i_am_color_574">#00000574</color> + <color name="i_am_color_575">#00000575</color> + <color name="i_am_color_576">#00000576</color> + <color name="i_am_color_577">#00000577</color> + <color name="i_am_color_578">#00000578</color> + <color name="i_am_color_579">#00000579</color> + <color name="i_am_color_57a">#0000057a</color> + <color name="i_am_color_57b">#0000057b</color> + <color name="i_am_color_57c">#0000057c</color> + <color name="i_am_color_57d">#0000057d</color> + <color name="i_am_color_57e">#0000057e</color> + <color name="i_am_color_57f">#0000057f</color> + <color name="i_am_color_580">#00000580</color> + <color name="i_am_color_581">#00000581</color> + <color name="i_am_color_582">#00000582</color> + <color name="i_am_color_583">#00000583</color> + <color name="i_am_color_584">#00000584</color> + <color name="i_am_color_585">#00000585</color> + <color name="i_am_color_586">#00000586</color> + <color name="i_am_color_587">#00000587</color> + <color name="i_am_color_588">#00000588</color> + <color name="i_am_color_589">#00000589</color> + <color name="i_am_color_58a">#0000058a</color> + <color name="i_am_color_58b">#0000058b</color> + <color name="i_am_color_58c">#0000058c</color> + <color name="i_am_color_58d">#0000058d</color> + <color name="i_am_color_58e">#0000058e</color> + <color name="i_am_color_58f">#0000058f</color> + <color name="i_am_color_590">#00000590</color> + <color name="i_am_color_591">#00000591</color> + <color name="i_am_color_592">#00000592</color> + <color name="i_am_color_593">#00000593</color> + <color name="i_am_color_594">#00000594</color> + <color name="i_am_color_595">#00000595</color> + <color name="i_am_color_596">#00000596</color> + <color name="i_am_color_597">#00000597</color> + <color name="i_am_color_598">#00000598</color> + <color name="i_am_color_599">#00000599</color> + <color name="i_am_color_59a">#0000059a</color> + <color name="i_am_color_59b">#0000059b</color> + <color name="i_am_color_59c">#0000059c</color> + <color name="i_am_color_59d">#0000059d</color> + <color name="i_am_color_59e">#0000059e</color> + <color name="i_am_color_59f">#0000059f</color> + <color name="i_am_color_5a0">#000005a0</color> + <color name="i_am_color_5a1">#000005a1</color> + <color name="i_am_color_5a2">#000005a2</color> + <color name="i_am_color_5a3">#000005a3</color> + <color name="i_am_color_5a4">#000005a4</color> + <color name="i_am_color_5a5">#000005a5</color> + <color name="i_am_color_5a6">#000005a6</color> + <color name="i_am_color_5a7">#000005a7</color> + <color name="i_am_color_5a8">#000005a8</color> + <color name="i_am_color_5a9">#000005a9</color> + <color name="i_am_color_5aa">#000005aa</color> + <color name="i_am_color_5ab">#000005ab</color> + <color name="i_am_color_5ac">#000005ac</color> + <color name="i_am_color_5ad">#000005ad</color> + <color name="i_am_color_5ae">#000005ae</color> + <color name="i_am_color_5af">#000005af</color> + <color name="i_am_color_5b0">#000005b0</color> + <color name="i_am_color_5b1">#000005b1</color> + <color name="i_am_color_5b2">#000005b2</color> + <color name="i_am_color_5b3">#000005b3</color> + <color name="i_am_color_5b4">#000005b4</color> + <color name="i_am_color_5b5">#000005b5</color> + <color name="i_am_color_5b6">#000005b6</color> + <color name="i_am_color_5b7">#000005b7</color> + <color name="i_am_color_5b8">#000005b8</color> + <color name="i_am_color_5b9">#000005b9</color> + <color name="i_am_color_5ba">#000005ba</color> + <color name="i_am_color_5bb">#000005bb</color> + <color name="i_am_color_5bc">#000005bc</color> + <color name="i_am_color_5bd">#000005bd</color> + <color name="i_am_color_5be">#000005be</color> + <color name="i_am_color_5bf">#000005bf</color> + <color name="i_am_color_5c0">#000005c0</color> + <color name="i_am_color_5c1">#000005c1</color> + <color name="i_am_color_5c2">#000005c2</color> + <color name="i_am_color_5c3">#000005c3</color> + <color name="i_am_color_5c4">#000005c4</color> + <color name="i_am_color_5c5">#000005c5</color> + <color name="i_am_color_5c6">#000005c6</color> + <color name="i_am_color_5c7">#000005c7</color> + <color name="i_am_color_5c8">#000005c8</color> + <color name="i_am_color_5c9">#000005c9</color> + <color name="i_am_color_5ca">#000005ca</color> + <color name="i_am_color_5cb">#000005cb</color> + <color name="i_am_color_5cc">#000005cc</color> + <color name="i_am_color_5cd">#000005cd</color> + <color name="i_am_color_5ce">#000005ce</color> + <color name="i_am_color_5cf">#000005cf</color> + <color name="i_am_color_5d0">#000005d0</color> + <color name="i_am_color_5d1">#000005d1</color> + <color name="i_am_color_5d2">#000005d2</color> + <color name="i_am_color_5d3">#000005d3</color> + <color name="i_am_color_5d4">#000005d4</color> + <color name="i_am_color_5d5">#000005d5</color> + <color name="i_am_color_5d6">#000005d6</color> + <color name="i_am_color_5d7">#000005d7</color> + <color name="i_am_color_5d8">#000005d8</color> + <color name="i_am_color_5d9">#000005d9</color> + <color name="i_am_color_5da">#000005da</color> + <color name="i_am_color_5db">#000005db</color> + <color name="i_am_color_5dc">#000005dc</color> + <color name="i_am_color_5dd">#000005dd</color> + <color name="i_am_color_5de">#000005de</color> + <color name="i_am_color_5df">#000005df</color> + <color name="i_am_color_5e0">#000005e0</color> + <color name="i_am_color_5e1">#000005e1</color> + <color name="i_am_color_5e2">#000005e2</color> + <color name="i_am_color_5e3">#000005e3</color> + <color name="i_am_color_5e4">#000005e4</color> + <color name="i_am_color_5e5">#000005e5</color> + <color name="i_am_color_5e6">#000005e6</color> + <color name="i_am_color_5e7">#000005e7</color> + <color name="i_am_color_5e8">#000005e8</color> + <color name="i_am_color_5e9">#000005e9</color> + <color name="i_am_color_5ea">#000005ea</color> + <color name="i_am_color_5eb">#000005eb</color> + <color name="i_am_color_5ec">#000005ec</color> + <color name="i_am_color_5ed">#000005ed</color> + <color name="i_am_color_5ee">#000005ee</color> + <color name="i_am_color_5ef">#000005ef</color> + <color name="i_am_color_5f0">#000005f0</color> + <color name="i_am_color_5f1">#000005f1</color> + <color name="i_am_color_5f2">#000005f2</color> + <color name="i_am_color_5f3">#000005f3</color> + <color name="i_am_color_5f4">#000005f4</color> + <color name="i_am_color_5f5">#000005f5</color> + <color name="i_am_color_5f6">#000005f6</color> + <color name="i_am_color_5f7">#000005f7</color> + <color name="i_am_color_5f8">#000005f8</color> + <color name="i_am_color_5f9">#000005f9</color> + <color name="i_am_color_5fa">#000005fa</color> + <color name="i_am_color_5fb">#000005fb</color> + <color name="i_am_color_5fc">#000005fc</color> + <color name="i_am_color_5fd">#000005fd</color> + <color name="i_am_color_5fe">#000005fe</color> + <color name="i_am_color_5ff">#000005ff</color> + <color name="i_am_color_600">#00000600</color> + <color name="i_am_color_601">#00000601</color> + <color name="i_am_color_602">#00000602</color> + <color name="i_am_color_603">#00000603</color> + <color name="i_am_color_604">#00000604</color> + <color name="i_am_color_605">#00000605</color> + <color name="i_am_color_606">#00000606</color> + <color name="i_am_color_607">#00000607</color> + <color name="i_am_color_608">#00000608</color> + <color name="i_am_color_609">#00000609</color> + <color name="i_am_color_60a">#0000060a</color> + <color name="i_am_color_60b">#0000060b</color> + <color name="i_am_color_60c">#0000060c</color> + <color name="i_am_color_60d">#0000060d</color> + <color name="i_am_color_60e">#0000060e</color> + <color name="i_am_color_60f">#0000060f</color> + <color name="i_am_color_610">#00000610</color> + <color name="i_am_color_611">#00000611</color> + <color name="i_am_color_612">#00000612</color> + <color name="i_am_color_613">#00000613</color> + <color name="i_am_color_614">#00000614</color> + <color name="i_am_color_615">#00000615</color> + <color name="i_am_color_616">#00000616</color> + <color name="i_am_color_617">#00000617</color> + <color name="i_am_color_618">#00000618</color> + <color name="i_am_color_619">#00000619</color> + <color name="i_am_color_61a">#0000061a</color> + <color name="i_am_color_61b">#0000061b</color> + <color name="i_am_color_61c">#0000061c</color> + <color name="i_am_color_61d">#0000061d</color> + <color name="i_am_color_61e">#0000061e</color> + <color name="i_am_color_61f">#0000061f</color> + <color name="i_am_color_620">#00000620</color> + <color name="i_am_color_621">#00000621</color> + <color name="i_am_color_622">#00000622</color> + <color name="i_am_color_623">#00000623</color> + <color name="i_am_color_624">#00000624</color> + <color name="i_am_color_625">#00000625</color> + <color name="i_am_color_626">#00000626</color> + <color name="i_am_color_627">#00000627</color> + <color name="i_am_color_628">#00000628</color> + <color name="i_am_color_629">#00000629</color> + <color name="i_am_color_62a">#0000062a</color> + <color name="i_am_color_62b">#0000062b</color> + <color name="i_am_color_62c">#0000062c</color> + <color name="i_am_color_62d">#0000062d</color> + <color name="i_am_color_62e">#0000062e</color> + <color name="i_am_color_62f">#0000062f</color> + <color name="i_am_color_630">#00000630</color> + <color name="i_am_color_631">#00000631</color> + <color name="i_am_color_632">#00000632</color> + <color name="i_am_color_633">#00000633</color> + <color name="i_am_color_634">#00000634</color> + <color name="i_am_color_635">#00000635</color> + <color name="i_am_color_636">#00000636</color> + <color name="i_am_color_637">#00000637</color> + <color name="i_am_color_638">#00000638</color> + <color name="i_am_color_639">#00000639</color> + <color name="i_am_color_63a">#0000063a</color> + <color name="i_am_color_63b">#0000063b</color> + <color name="i_am_color_63c">#0000063c</color> + <color name="i_am_color_63d">#0000063d</color> + <color name="i_am_color_63e">#0000063e</color> + <color name="i_am_color_63f">#0000063f</color> + <color name="i_am_color_640">#00000640</color> + <color name="i_am_color_641">#00000641</color> + <color name="i_am_color_642">#00000642</color> + <color name="i_am_color_643">#00000643</color> + <color name="i_am_color_644">#00000644</color> + <color name="i_am_color_645">#00000645</color> + <color name="i_am_color_646">#00000646</color> + <color name="i_am_color_647">#00000647</color> + <color name="i_am_color_648">#00000648</color> + <color name="i_am_color_649">#00000649</color> + <color name="i_am_color_64a">#0000064a</color> + <color name="i_am_color_64b">#0000064b</color> + <color name="i_am_color_64c">#0000064c</color> + <color name="i_am_color_64d">#0000064d</color> + <color name="i_am_color_64e">#0000064e</color> + <color name="i_am_color_64f">#0000064f</color> + <color name="i_am_color_650">#00000650</color> + <color name="i_am_color_651">#00000651</color> + <color name="i_am_color_652">#00000652</color> + <color name="i_am_color_653">#00000653</color> + <color name="i_am_color_654">#00000654</color> + <color name="i_am_color_655">#00000655</color> + <color name="i_am_color_656">#00000656</color> + <color name="i_am_color_657">#00000657</color> + <color name="i_am_color_658">#00000658</color> + <color name="i_am_color_659">#00000659</color> + <color name="i_am_color_65a">#0000065a</color> + <color name="i_am_color_65b">#0000065b</color> + <color name="i_am_color_65c">#0000065c</color> + <color name="i_am_color_65d">#0000065d</color> + <color name="i_am_color_65e">#0000065e</color> + <color name="i_am_color_65f">#0000065f</color> + <color name="i_am_color_660">#00000660</color> + <color name="i_am_color_661">#00000661</color> + <color name="i_am_color_662">#00000662</color> + <color name="i_am_color_663">#00000663</color> + <color name="i_am_color_664">#00000664</color> + <color name="i_am_color_665">#00000665</color> + <color name="i_am_color_666">#00000666</color> + <color name="i_am_color_667">#00000667</color> + <color name="i_am_color_668">#00000668</color> + <color name="i_am_color_669">#00000669</color> + <color name="i_am_color_66a">#0000066a</color> + <color name="i_am_color_66b">#0000066b</color> + <color name="i_am_color_66c">#0000066c</color> + <color name="i_am_color_66d">#0000066d</color> + <color name="i_am_color_66e">#0000066e</color> + <color name="i_am_color_66f">#0000066f</color> + <color name="i_am_color_670">#00000670</color> + <color name="i_am_color_671">#00000671</color> + <color name="i_am_color_672">#00000672</color> + <color name="i_am_color_673">#00000673</color> + <color name="i_am_color_674">#00000674</color> + <color name="i_am_color_675">#00000675</color> + <color name="i_am_color_676">#00000676</color> + <color name="i_am_color_677">#00000677</color> + <color name="i_am_color_678">#00000678</color> + <color name="i_am_color_679">#00000679</color> + <color name="i_am_color_67a">#0000067a</color> + <color name="i_am_color_67b">#0000067b</color> + <color name="i_am_color_67c">#0000067c</color> + <color name="i_am_color_67d">#0000067d</color> + <color name="i_am_color_67e">#0000067e</color> + <color name="i_am_color_67f">#0000067f</color> + <color name="i_am_color_680">#00000680</color> + <color name="i_am_color_681">#00000681</color> + <color name="i_am_color_682">#00000682</color> + <color name="i_am_color_683">#00000683</color> + <color name="i_am_color_684">#00000684</color> + <color name="i_am_color_685">#00000685</color> + <color name="i_am_color_686">#00000686</color> + <color name="i_am_color_687">#00000687</color> + <color name="i_am_color_688">#00000688</color> + <color name="i_am_color_689">#00000689</color> + <color name="i_am_color_68a">#0000068a</color> + <color name="i_am_color_68b">#0000068b</color> + <color name="i_am_color_68c">#0000068c</color> + <color name="i_am_color_68d">#0000068d</color> + <color name="i_am_color_68e">#0000068e</color> + <color name="i_am_color_68f">#0000068f</color> + <color name="i_am_color_690">#00000690</color> + <color name="i_am_color_691">#00000691</color> + <color name="i_am_color_692">#00000692</color> + <color name="i_am_color_693">#00000693</color> + <color name="i_am_color_694">#00000694</color> + <color name="i_am_color_695">#00000695</color> + <color name="i_am_color_696">#00000696</color> + <color name="i_am_color_697">#00000697</color> + <color name="i_am_color_698">#00000698</color> + <color name="i_am_color_699">#00000699</color> + <color name="i_am_color_69a">#0000069a</color> + <color name="i_am_color_69b">#0000069b</color> + <color name="i_am_color_69c">#0000069c</color> + <color name="i_am_color_69d">#0000069d</color> + <color name="i_am_color_69e">#0000069e</color> + <color name="i_am_color_69f">#0000069f</color> + <color name="i_am_color_6a0">#000006a0</color> + <color name="i_am_color_6a1">#000006a1</color> + <color name="i_am_color_6a2">#000006a2</color> + <color name="i_am_color_6a3">#000006a3</color> + <color name="i_am_color_6a4">#000006a4</color> + <color name="i_am_color_6a5">#000006a5</color> + <color name="i_am_color_6a6">#000006a6</color> + <color name="i_am_color_6a7">#000006a7</color> + <color name="i_am_color_6a8">#000006a8</color> + <color name="i_am_color_6a9">#000006a9</color> + <color name="i_am_color_6aa">#000006aa</color> + <color name="i_am_color_6ab">#000006ab</color> + <color name="i_am_color_6ac">#000006ac</color> + <color name="i_am_color_6ad">#000006ad</color> + <color name="i_am_color_6ae">#000006ae</color> + <color name="i_am_color_6af">#000006af</color> + <color name="i_am_color_6b0">#000006b0</color> + <color name="i_am_color_6b1">#000006b1</color> + <color name="i_am_color_6b2">#000006b2</color> + <color name="i_am_color_6b3">#000006b3</color> + <color name="i_am_color_6b4">#000006b4</color> + <color name="i_am_color_6b5">#000006b5</color> + <color name="i_am_color_6b6">#000006b6</color> + <color name="i_am_color_6b7">#000006b7</color> + <color name="i_am_color_6b8">#000006b8</color> + <color name="i_am_color_6b9">#000006b9</color> + <color name="i_am_color_6ba">#000006ba</color> + <color name="i_am_color_6bb">#000006bb</color> + <color name="i_am_color_6bc">#000006bc</color> + <color name="i_am_color_6bd">#000006bd</color> + <color name="i_am_color_6be">#000006be</color> + <color name="i_am_color_6bf">#000006bf</color> + <color name="i_am_color_6c0">#000006c0</color> + <color name="i_am_color_6c1">#000006c1</color> + <color name="i_am_color_6c2">#000006c2</color> + <color name="i_am_color_6c3">#000006c3</color> + <color name="i_am_color_6c4">#000006c4</color> + <color name="i_am_color_6c5">#000006c5</color> + <color name="i_am_color_6c6">#000006c6</color> + <color name="i_am_color_6c7">#000006c7</color> + <color name="i_am_color_6c8">#000006c8</color> + <color name="i_am_color_6c9">#000006c9</color> + <color name="i_am_color_6ca">#000006ca</color> + <color name="i_am_color_6cb">#000006cb</color> + <color name="i_am_color_6cc">#000006cc</color> + <color name="i_am_color_6cd">#000006cd</color> + <color name="i_am_color_6ce">#000006ce</color> + <color name="i_am_color_6cf">#000006cf</color> + <color name="i_am_color_6d0">#000006d0</color> + <color name="i_am_color_6d1">#000006d1</color> + <color name="i_am_color_6d2">#000006d2</color> + <color name="i_am_color_6d3">#000006d3</color> + <color name="i_am_color_6d4">#000006d4</color> + <color name="i_am_color_6d5">#000006d5</color> + <color name="i_am_color_6d6">#000006d6</color> + <color name="i_am_color_6d7">#000006d7</color> + <color name="i_am_color_6d8">#000006d8</color> + <color name="i_am_color_6d9">#000006d9</color> + <color name="i_am_color_6da">#000006da</color> + <color name="i_am_color_6db">#000006db</color> + <color name="i_am_color_6dc">#000006dc</color> + <color name="i_am_color_6dd">#000006dd</color> + <color name="i_am_color_6de">#000006de</color> + <color name="i_am_color_6df">#000006df</color> + <color name="i_am_color_6e0">#000006e0</color> + <color name="i_am_color_6e1">#000006e1</color> + <color name="i_am_color_6e2">#000006e2</color> + <color name="i_am_color_6e3">#000006e3</color> + <color name="i_am_color_6e4">#000006e4</color> + <color name="i_am_color_6e5">#000006e5</color> + <color name="i_am_color_6e6">#000006e6</color> + <color name="i_am_color_6e7">#000006e7</color> + <color name="i_am_color_6e8">#000006e8</color> + <color name="i_am_color_6e9">#000006e9</color> + <color name="i_am_color_6ea">#000006ea</color> + <color name="i_am_color_6eb">#000006eb</color> + <color name="i_am_color_6ec">#000006ec</color> + <color name="i_am_color_6ed">#000006ed</color> + <color name="i_am_color_6ee">#000006ee</color> + <color name="i_am_color_6ef">#000006ef</color> + <color name="i_am_color_6f0">#000006f0</color> + <color name="i_am_color_6f1">#000006f1</color> + <color name="i_am_color_6f2">#000006f2</color> + <color name="i_am_color_6f3">#000006f3</color> + <color name="i_am_color_6f4">#000006f4</color> + <color name="i_am_color_6f5">#000006f5</color> + <color name="i_am_color_6f6">#000006f6</color> + <color name="i_am_color_6f7">#000006f7</color> + <color name="i_am_color_6f8">#000006f8</color> + <color name="i_am_color_6f9">#000006f9</color> + <color name="i_am_color_6fa">#000006fa</color> + <color name="i_am_color_6fb">#000006fb</color> + <color name="i_am_color_6fc">#000006fc</color> + <color name="i_am_color_6fd">#000006fd</color> + <color name="i_am_color_6fe">#000006fe</color> + <color name="i_am_color_6ff">#000006ff</color> + <color name="i_am_color_700">#00000700</color> + <color name="i_am_color_701">#00000701</color> + <color name="i_am_color_702">#00000702</color> + <color name="i_am_color_703">#00000703</color> + <color name="i_am_color_704">#00000704</color> + <color name="i_am_color_705">#00000705</color> + <color name="i_am_color_706">#00000706</color> + <color name="i_am_color_707">#00000707</color> + <color name="i_am_color_708">#00000708</color> + <color name="i_am_color_709">#00000709</color> + <color name="i_am_color_70a">#0000070a</color> + <color name="i_am_color_70b">#0000070b</color> + <color name="i_am_color_70c">#0000070c</color> + <color name="i_am_color_70d">#0000070d</color> + <color name="i_am_color_70e">#0000070e</color> + <color name="i_am_color_70f">#0000070f</color> + <color name="i_am_color_710">#00000710</color> + <color name="i_am_color_711">#00000711</color> + <color name="i_am_color_712">#00000712</color> + <color name="i_am_color_713">#00000713</color> + <color name="i_am_color_714">#00000714</color> + <color name="i_am_color_715">#00000715</color> + <color name="i_am_color_716">#00000716</color> + <color name="i_am_color_717">#00000717</color> + <color name="i_am_color_718">#00000718</color> + <color name="i_am_color_719">#00000719</color> + <color name="i_am_color_71a">#0000071a</color> + <color name="i_am_color_71b">#0000071b</color> + <color name="i_am_color_71c">#0000071c</color> + <color name="i_am_color_71d">#0000071d</color> + <color name="i_am_color_71e">#0000071e</color> + <color name="i_am_color_71f">#0000071f</color> + <color name="i_am_color_720">#00000720</color> + <color name="i_am_color_721">#00000721</color> + <color name="i_am_color_722">#00000722</color> + <color name="i_am_color_723">#00000723</color> + <color name="i_am_color_724">#00000724</color> + <color name="i_am_color_725">#00000725</color> + <color name="i_am_color_726">#00000726</color> + <color name="i_am_color_727">#00000727</color> + <color name="i_am_color_728">#00000728</color> + <color name="i_am_color_729">#00000729</color> + <color name="i_am_color_72a">#0000072a</color> + <color name="i_am_color_72b">#0000072b</color> + <color name="i_am_color_72c">#0000072c</color> + <color name="i_am_color_72d">#0000072d</color> + <color name="i_am_color_72e">#0000072e</color> + <color name="i_am_color_72f">#0000072f</color> + <color name="i_am_color_730">#00000730</color> + <color name="i_am_color_731">#00000731</color> + <color name="i_am_color_732">#00000732</color> + <color name="i_am_color_733">#00000733</color> + <color name="i_am_color_734">#00000734</color> + <color name="i_am_color_735">#00000735</color> + <color name="i_am_color_736">#00000736</color> + <color name="i_am_color_737">#00000737</color> + <color name="i_am_color_738">#00000738</color> + <color name="i_am_color_739">#00000739</color> + <color name="i_am_color_73a">#0000073a</color> + <color name="i_am_color_73b">#0000073b</color> + <color name="i_am_color_73c">#0000073c</color> + <color name="i_am_color_73d">#0000073d</color> + <color name="i_am_color_73e">#0000073e</color> + <color name="i_am_color_73f">#0000073f</color> + <color name="i_am_color_740">#00000740</color> + <color name="i_am_color_741">#00000741</color> + <color name="i_am_color_742">#00000742</color> + <color name="i_am_color_743">#00000743</color> + <color name="i_am_color_744">#00000744</color> + <color name="i_am_color_745">#00000745</color> + <color name="i_am_color_746">#00000746</color> + <color name="i_am_color_747">#00000747</color> + <color name="i_am_color_748">#00000748</color> + <color name="i_am_color_749">#00000749</color> + <color name="i_am_color_74a">#0000074a</color> + <color name="i_am_color_74b">#0000074b</color> + <color name="i_am_color_74c">#0000074c</color> + <color name="i_am_color_74d">#0000074d</color> + <color name="i_am_color_74e">#0000074e</color> + <color name="i_am_color_74f">#0000074f</color> + <color name="i_am_color_750">#00000750</color> + <color name="i_am_color_751">#00000751</color> + <color name="i_am_color_752">#00000752</color> + <color name="i_am_color_753">#00000753</color> + <color name="i_am_color_754">#00000754</color> + <color name="i_am_color_755">#00000755</color> + <color name="i_am_color_756">#00000756</color> + <color name="i_am_color_757">#00000757</color> + <color name="i_am_color_758">#00000758</color> + <color name="i_am_color_759">#00000759</color> + <color name="i_am_color_75a">#0000075a</color> + <color name="i_am_color_75b">#0000075b</color> + <color name="i_am_color_75c">#0000075c</color> + <color name="i_am_color_75d">#0000075d</color> + <color name="i_am_color_75e">#0000075e</color> + <color name="i_am_color_75f">#0000075f</color> + <color name="i_am_color_760">#00000760</color> + <color name="i_am_color_761">#00000761</color> + <color name="i_am_color_762">#00000762</color> + <color name="i_am_color_763">#00000763</color> + <color name="i_am_color_764">#00000764</color> + <color name="i_am_color_765">#00000765</color> + <color name="i_am_color_766">#00000766</color> + <color name="i_am_color_767">#00000767</color> + <color name="i_am_color_768">#00000768</color> + <color name="i_am_color_769">#00000769</color> + <color name="i_am_color_76a">#0000076a</color> + <color name="i_am_color_76b">#0000076b</color> + <color name="i_am_color_76c">#0000076c</color> + <color name="i_am_color_76d">#0000076d</color> + <color name="i_am_color_76e">#0000076e</color> + <color name="i_am_color_76f">#0000076f</color> + <color name="i_am_color_770">#00000770</color> + <color name="i_am_color_771">#00000771</color> + <color name="i_am_color_772">#00000772</color> + <color name="i_am_color_773">#00000773</color> + <color name="i_am_color_774">#00000774</color> + <color name="i_am_color_775">#00000775</color> + <color name="i_am_color_776">#00000776</color> + <color name="i_am_color_777">#00000777</color> + <color name="i_am_color_778">#00000778</color> + <color name="i_am_color_779">#00000779</color> + <color name="i_am_color_77a">#0000077a</color> + <color name="i_am_color_77b">#0000077b</color> + <color name="i_am_color_77c">#0000077c</color> + <color name="i_am_color_77d">#0000077d</color> + <color name="i_am_color_77e">#0000077e</color> + <color name="i_am_color_77f">#0000077f</color> + <color name="i_am_color_780">#00000780</color> + <color name="i_am_color_781">#00000781</color> + <color name="i_am_color_782">#00000782</color> + <color name="i_am_color_783">#00000783</color> + <color name="i_am_color_784">#00000784</color> + <color name="i_am_color_785">#00000785</color> + <color name="i_am_color_786">#00000786</color> + <color name="i_am_color_787">#00000787</color> + <color name="i_am_color_788">#00000788</color> + <color name="i_am_color_789">#00000789</color> + <color name="i_am_color_78a">#0000078a</color> + <color name="i_am_color_78b">#0000078b</color> + <color name="i_am_color_78c">#0000078c</color> + <color name="i_am_color_78d">#0000078d</color> + <color name="i_am_color_78e">#0000078e</color> + <color name="i_am_color_78f">#0000078f</color> + <color name="i_am_color_790">#00000790</color> + <color name="i_am_color_791">#00000791</color> + <color name="i_am_color_792">#00000792</color> + <color name="i_am_color_793">#00000793</color> + <color name="i_am_color_794">#00000794</color> + <color name="i_am_color_795">#00000795</color> + <color name="i_am_color_796">#00000796</color> + <color name="i_am_color_797">#00000797</color> + <color name="i_am_color_798">#00000798</color> + <color name="i_am_color_799">#00000799</color> + <color name="i_am_color_79a">#0000079a</color> + <color name="i_am_color_79b">#0000079b</color> + <color name="i_am_color_79c">#0000079c</color> + <color name="i_am_color_79d">#0000079d</color> + <color name="i_am_color_79e">#0000079e</color> + <color name="i_am_color_79f">#0000079f</color> + <color name="i_am_color_7a0">#000007a0</color> + <color name="i_am_color_7a1">#000007a1</color> + <color name="i_am_color_7a2">#000007a2</color> + <color name="i_am_color_7a3">#000007a3</color> + <color name="i_am_color_7a4">#000007a4</color> + <color name="i_am_color_7a5">#000007a5</color> + <color name="i_am_color_7a6">#000007a6</color> + <color name="i_am_color_7a7">#000007a7</color> + <color name="i_am_color_7a8">#000007a8</color> + <color name="i_am_color_7a9">#000007a9</color> + <color name="i_am_color_7aa">#000007aa</color> + <color name="i_am_color_7ab">#000007ab</color> + <color name="i_am_color_7ac">#000007ac</color> + <color name="i_am_color_7ad">#000007ad</color> + <color name="i_am_color_7ae">#000007ae</color> + <color name="i_am_color_7af">#000007af</color> + <color name="i_am_color_7b0">#000007b0</color> + <color name="i_am_color_7b1">#000007b1</color> + <color name="i_am_color_7b2">#000007b2</color> + <color name="i_am_color_7b3">#000007b3</color> + <color name="i_am_color_7b4">#000007b4</color> + <color name="i_am_color_7b5">#000007b5</color> + <color name="i_am_color_7b6">#000007b6</color> + <color name="i_am_color_7b7">#000007b7</color> + <color name="i_am_color_7b8">#000007b8</color> + <color name="i_am_color_7b9">#000007b9</color> + <color name="i_am_color_7ba">#000007ba</color> + <color name="i_am_color_7bb">#000007bb</color> + <color name="i_am_color_7bc">#000007bc</color> + <color name="i_am_color_7bd">#000007bd</color> + <color name="i_am_color_7be">#000007be</color> + <color name="i_am_color_7bf">#000007bf</color> + <color name="i_am_color_7c0">#000007c0</color> + <color name="i_am_color_7c1">#000007c1</color> + <color name="i_am_color_7c2">#000007c2</color> + <color name="i_am_color_7c3">#000007c3</color> + <color name="i_am_color_7c4">#000007c4</color> + <color name="i_am_color_7c5">#000007c5</color> + <color name="i_am_color_7c6">#000007c6</color> + <color name="i_am_color_7c7">#000007c7</color> + <color name="i_am_color_7c8">#000007c8</color> + <color name="i_am_color_7c9">#000007c9</color> + <color name="i_am_color_7ca">#000007ca</color> + <color name="i_am_color_7cb">#000007cb</color> + <color name="i_am_color_7cc">#000007cc</color> + <color name="i_am_color_7cd">#000007cd</color> + <color name="i_am_color_7ce">#000007ce</color> + <color name="i_am_color_7cf">#000007cf</color> + <color name="i_am_color_7d0">#000007d0</color> + <color name="i_am_color_7d1">#000007d1</color> + <color name="i_am_color_7d2">#000007d2</color> + <color name="i_am_color_7d3">#000007d3</color> + <color name="i_am_color_7d4">#000007d4</color> + <color name="i_am_color_7d5">#000007d5</color> + <color name="i_am_color_7d6">#000007d6</color> + <color name="i_am_color_7d7">#000007d7</color> + <color name="i_am_color_7d8">#000007d8</color> + <color name="i_am_color_7d9">#000007d9</color> + <color name="i_am_color_7da">#000007da</color> + <color name="i_am_color_7db">#000007db</color> + <color name="i_am_color_7dc">#000007dc</color> + <color name="i_am_color_7dd">#000007dd</color> + <color name="i_am_color_7de">#000007de</color> + <color name="i_am_color_7df">#000007df</color> + <color name="i_am_color_7e0">#000007e0</color> + <color name="i_am_color_7e1">#000007e1</color> + <color name="i_am_color_7e2">#000007e2</color> + <color name="i_am_color_7e3">#000007e3</color> + <color name="i_am_color_7e4">#000007e4</color> + <color name="i_am_color_7e5">#000007e5</color> + <color name="i_am_color_7e6">#000007e6</color> + <color name="i_am_color_7e7">#000007e7</color> + <color name="i_am_color_7e8">#000007e8</color> + <color name="i_am_color_7e9">#000007e9</color> + <color name="i_am_color_7ea">#000007ea</color> + <color name="i_am_color_7eb">#000007eb</color> + <color name="i_am_color_7ec">#000007ec</color> + <color name="i_am_color_7ed">#000007ed</color> + <color name="i_am_color_7ee">#000007ee</color> + <color name="i_am_color_7ef">#000007ef</color> + <color name="i_am_color_7f0">#000007f0</color> + <color name="i_am_color_7f1">#000007f1</color> + <color name="i_am_color_7f2">#000007f2</color> + <color name="i_am_color_7f3">#000007f3</color> + <color name="i_am_color_7f4">#000007f4</color> + <color name="i_am_color_7f5">#000007f5</color> + <color name="i_am_color_7f6">#000007f6</color> + <color name="i_am_color_7f7">#000007f7</color> + <color name="i_am_color_7f8">#000007f8</color> + <color name="i_am_color_7f9">#000007f9</color> + <color name="i_am_color_7fa">#000007fa</color> + <color name="i_am_color_7fb">#000007fb</color> + <color name="i_am_color_7fc">#000007fc</color> + <color name="i_am_color_7fd">#000007fd</color> + <color name="i_am_color_7fe">#000007fe</color> + <color name="i_am_color_7ff">#000007ff</color> + <color name="i_am_color_800">#00000800</color> + <color name="i_am_color_801">#00000801</color> + <color name="i_am_color_802">#00000802</color> + <color name="i_am_color_803">#00000803</color> + <color name="i_am_color_804">#00000804</color> + <color name="i_am_color_805">#00000805</color> + <color name="i_am_color_806">#00000806</color> + <color name="i_am_color_807">#00000807</color> + <color name="i_am_color_808">#00000808</color> + <color name="i_am_color_809">#00000809</color> + <color name="i_am_color_80a">#0000080a</color> + <color name="i_am_color_80b">#0000080b</color> + <color name="i_am_color_80c">#0000080c</color> + <color name="i_am_color_80d">#0000080d</color> + <color name="i_am_color_80e">#0000080e</color> + <color name="i_am_color_80f">#0000080f</color> + <color name="i_am_color_810">#00000810</color> + <color name="i_am_color_811">#00000811</color> + <color name="i_am_color_812">#00000812</color> + <color name="i_am_color_813">#00000813</color> + <color name="i_am_color_814">#00000814</color> + <color name="i_am_color_815">#00000815</color> + <color name="i_am_color_816">#00000816</color> + <color name="i_am_color_817">#00000817</color> + <color name="i_am_color_818">#00000818</color> + <color name="i_am_color_819">#00000819</color> + <color name="i_am_color_81a">#0000081a</color> + <color name="i_am_color_81b">#0000081b</color> + <color name="i_am_color_81c">#0000081c</color> + <color name="i_am_color_81d">#0000081d</color> + <color name="i_am_color_81e">#0000081e</color> + <color name="i_am_color_81f">#0000081f</color> + <color name="i_am_color_820">#00000820</color> + <color name="i_am_color_821">#00000821</color> + <color name="i_am_color_822">#00000822</color> + <color name="i_am_color_823">#00000823</color> + <color name="i_am_color_824">#00000824</color> + <color name="i_am_color_825">#00000825</color> + <color name="i_am_color_826">#00000826</color> + <color name="i_am_color_827">#00000827</color> + <color name="i_am_color_828">#00000828</color> + <color name="i_am_color_829">#00000829</color> + <color name="i_am_color_82a">#0000082a</color> + <color name="i_am_color_82b">#0000082b</color> + <color name="i_am_color_82c">#0000082c</color> + <color name="i_am_color_82d">#0000082d</color> + <color name="i_am_color_82e">#0000082e</color> + <color name="i_am_color_82f">#0000082f</color> + <color name="i_am_color_830">#00000830</color> + <color name="i_am_color_831">#00000831</color> + <color name="i_am_color_832">#00000832</color> + <color name="i_am_color_833">#00000833</color> + <color name="i_am_color_834">#00000834</color> + <color name="i_am_color_835">#00000835</color> + <color name="i_am_color_836">#00000836</color> + <color name="i_am_color_837">#00000837</color> + <color name="i_am_color_838">#00000838</color> + <color name="i_am_color_839">#00000839</color> + <color name="i_am_color_83a">#0000083a</color> + <color name="i_am_color_83b">#0000083b</color> + <color name="i_am_color_83c">#0000083c</color> + <color name="i_am_color_83d">#0000083d</color> + <color name="i_am_color_83e">#0000083e</color> + <color name="i_am_color_83f">#0000083f</color> + <color name="i_am_color_840">#00000840</color> + <color name="i_am_color_841">#00000841</color> + <color name="i_am_color_842">#00000842</color> + <color name="i_am_color_843">#00000843</color> + <color name="i_am_color_844">#00000844</color> + <color name="i_am_color_845">#00000845</color> + <color name="i_am_color_846">#00000846</color> + <color name="i_am_color_847">#00000847</color> + <color name="i_am_color_848">#00000848</color> + <color name="i_am_color_849">#00000849</color> + <color name="i_am_color_84a">#0000084a</color> + <color name="i_am_color_84b">#0000084b</color> + <color name="i_am_color_84c">#0000084c</color> + <color name="i_am_color_84d">#0000084d</color> + <color name="i_am_color_84e">#0000084e</color> + <color name="i_am_color_84f">#0000084f</color> + <color name="i_am_color_850">#00000850</color> + <color name="i_am_color_851">#00000851</color> + <color name="i_am_color_852">#00000852</color> + <color name="i_am_color_853">#00000853</color> + <color name="i_am_color_854">#00000854</color> + <color name="i_am_color_855">#00000855</color> + <color name="i_am_color_856">#00000856</color> + <color name="i_am_color_857">#00000857</color> + <color name="i_am_color_858">#00000858</color> + <color name="i_am_color_859">#00000859</color> + <color name="i_am_color_85a">#0000085a</color> + <color name="i_am_color_85b">#0000085b</color> + <color name="i_am_color_85c">#0000085c</color> + <color name="i_am_color_85d">#0000085d</color> + <color name="i_am_color_85e">#0000085e</color> + <color name="i_am_color_85f">#0000085f</color> + <color name="i_am_color_860">#00000860</color> + <color name="i_am_color_861">#00000861</color> + <color name="i_am_color_862">#00000862</color> + <color name="i_am_color_863">#00000863</color> + <color name="i_am_color_864">#00000864</color> + <color name="i_am_color_865">#00000865</color> + <color name="i_am_color_866">#00000866</color> + <color name="i_am_color_867">#00000867</color> + <color name="i_am_color_868">#00000868</color> + <color name="i_am_color_869">#00000869</color> + <color name="i_am_color_86a">#0000086a</color> + <color name="i_am_color_86b">#0000086b</color> + <color name="i_am_color_86c">#0000086c</color> + <color name="i_am_color_86d">#0000086d</color> + <color name="i_am_color_86e">#0000086e</color> + <color name="i_am_color_86f">#0000086f</color> + <color name="i_am_color_870">#00000870</color> + <color name="i_am_color_871">#00000871</color> + <color name="i_am_color_872">#00000872</color> + <color name="i_am_color_873">#00000873</color> + <color name="i_am_color_874">#00000874</color> + <color name="i_am_color_875">#00000875</color> + <color name="i_am_color_876">#00000876</color> + <color name="i_am_color_877">#00000877</color> + <color name="i_am_color_878">#00000878</color> + <color name="i_am_color_879">#00000879</color> + <color name="i_am_color_87a">#0000087a</color> + <color name="i_am_color_87b">#0000087b</color> + <color name="i_am_color_87c">#0000087c</color> + <color name="i_am_color_87d">#0000087d</color> + <color name="i_am_color_87e">#0000087e</color> + <color name="i_am_color_87f">#0000087f</color> + <color name="i_am_color_880">#00000880</color> + <color name="i_am_color_881">#00000881</color> + <color name="i_am_color_882">#00000882</color> + <color name="i_am_color_883">#00000883</color> + <color name="i_am_color_884">#00000884</color> + <color name="i_am_color_885">#00000885</color> + <color name="i_am_color_886">#00000886</color> + <color name="i_am_color_887">#00000887</color> + <color name="i_am_color_888">#00000888</color> + <color name="i_am_color_889">#00000889</color> + <color name="i_am_color_88a">#0000088a</color> + <color name="i_am_color_88b">#0000088b</color> + <color name="i_am_color_88c">#0000088c</color> + <color name="i_am_color_88d">#0000088d</color> + <color name="i_am_color_88e">#0000088e</color> + <color name="i_am_color_88f">#0000088f</color> + <color name="i_am_color_890">#00000890</color> + <color name="i_am_color_891">#00000891</color> + <color name="i_am_color_892">#00000892</color> + <color name="i_am_color_893">#00000893</color> + <color name="i_am_color_894">#00000894</color> + <color name="i_am_color_895">#00000895</color> + <color name="i_am_color_896">#00000896</color> + <color name="i_am_color_897">#00000897</color> + <color name="i_am_color_898">#00000898</color> + <color name="i_am_color_899">#00000899</color> + <color name="i_am_color_89a">#0000089a</color> + <color name="i_am_color_89b">#0000089b</color> + <color name="i_am_color_89c">#0000089c</color> + <color name="i_am_color_89d">#0000089d</color> + <color name="i_am_color_89e">#0000089e</color> + <color name="i_am_color_89f">#0000089f</color> + <color name="i_am_color_8a0">#000008a0</color> + <color name="i_am_color_8a1">#000008a1</color> + <color name="i_am_color_8a2">#000008a2</color> + <color name="i_am_color_8a3">#000008a3</color> + <color name="i_am_color_8a4">#000008a4</color> + <color name="i_am_color_8a5">#000008a5</color> + <color name="i_am_color_8a6">#000008a6</color> + <color name="i_am_color_8a7">#000008a7</color> + <color name="i_am_color_8a8">#000008a8</color> + <color name="i_am_color_8a9">#000008a9</color> + <color name="i_am_color_8aa">#000008aa</color> + <color name="i_am_color_8ab">#000008ab</color> + <color name="i_am_color_8ac">#000008ac</color> + <color name="i_am_color_8ad">#000008ad</color> + <color name="i_am_color_8ae">#000008ae</color> + <color name="i_am_color_8af">#000008af</color> + <color name="i_am_color_8b0">#000008b0</color> + <color name="i_am_color_8b1">#000008b1</color> + <color name="i_am_color_8b2">#000008b2</color> + <color name="i_am_color_8b3">#000008b3</color> + <color name="i_am_color_8b4">#000008b4</color> + <color name="i_am_color_8b5">#000008b5</color> + <color name="i_am_color_8b6">#000008b6</color> + <color name="i_am_color_8b7">#000008b7</color> + <color name="i_am_color_8b8">#000008b8</color> + <color name="i_am_color_8b9">#000008b9</color> + <color name="i_am_color_8ba">#000008ba</color> + <color name="i_am_color_8bb">#000008bb</color> + <color name="i_am_color_8bc">#000008bc</color> + <color name="i_am_color_8bd">#000008bd</color> + <color name="i_am_color_8be">#000008be</color> + <color name="i_am_color_8bf">#000008bf</color> + <color name="i_am_color_8c0">#000008c0</color> + <color name="i_am_color_8c1">#000008c1</color> + <color name="i_am_color_8c2">#000008c2</color> + <color name="i_am_color_8c3">#000008c3</color> + <color name="i_am_color_8c4">#000008c4</color> + <color name="i_am_color_8c5">#000008c5</color> + <color name="i_am_color_8c6">#000008c6</color> + <color name="i_am_color_8c7">#000008c7</color> + <color name="i_am_color_8c8">#000008c8</color> + <color name="i_am_color_8c9">#000008c9</color> + <color name="i_am_color_8ca">#000008ca</color> + <color name="i_am_color_8cb">#000008cb</color> + <color name="i_am_color_8cc">#000008cc</color> + <color name="i_am_color_8cd">#000008cd</color> + <color name="i_am_color_8ce">#000008ce</color> + <color name="i_am_color_8cf">#000008cf</color> + <color name="i_am_color_8d0">#000008d0</color> + <color name="i_am_color_8d1">#000008d1</color> + <color name="i_am_color_8d2">#000008d2</color> + <color name="i_am_color_8d3">#000008d3</color> + <color name="i_am_color_8d4">#000008d4</color> + <color name="i_am_color_8d5">#000008d5</color> + <color name="i_am_color_8d6">#000008d6</color> + <color name="i_am_color_8d7">#000008d7</color> + <color name="i_am_color_8d8">#000008d8</color> + <color name="i_am_color_8d9">#000008d9</color> + <color name="i_am_color_8da">#000008da</color> + <color name="i_am_color_8db">#000008db</color> + <color name="i_am_color_8dc">#000008dc</color> + <color name="i_am_color_8dd">#000008dd</color> + <color name="i_am_color_8de">#000008de</color> + <color name="i_am_color_8df">#000008df</color> + <color name="i_am_color_8e0">#000008e0</color> + <color name="i_am_color_8e1">#000008e1</color> + <color name="i_am_color_8e2">#000008e2</color> + <color name="i_am_color_8e3">#000008e3</color> + <color name="i_am_color_8e4">#000008e4</color> + <color name="i_am_color_8e5">#000008e5</color> + <color name="i_am_color_8e6">#000008e6</color> + <color name="i_am_color_8e7">#000008e7</color> + <color name="i_am_color_8e8">#000008e8</color> + <color name="i_am_color_8e9">#000008e9</color> + <color name="i_am_color_8ea">#000008ea</color> + <color name="i_am_color_8eb">#000008eb</color> + <color name="i_am_color_8ec">#000008ec</color> + <color name="i_am_color_8ed">#000008ed</color> + <color name="i_am_color_8ee">#000008ee</color> + <color name="i_am_color_8ef">#000008ef</color> + <color name="i_am_color_8f0">#000008f0</color> + <color name="i_am_color_8f1">#000008f1</color> + <color name="i_am_color_8f2">#000008f2</color> + <color name="i_am_color_8f3">#000008f3</color> + <color name="i_am_color_8f4">#000008f4</color> + <color name="i_am_color_8f5">#000008f5</color> + <color name="i_am_color_8f6">#000008f6</color> + <color name="i_am_color_8f7">#000008f7</color> + <color name="i_am_color_8f8">#000008f8</color> + <color name="i_am_color_8f9">#000008f9</color> + <color name="i_am_color_8fa">#000008fa</color> + <color name="i_am_color_8fb">#000008fb</color> + <color name="i_am_color_8fc">#000008fc</color> + <color name="i_am_color_8fd">#000008fd</color> + <color name="i_am_color_8fe">#000008fe</color> + <color name="i_am_color_8ff">#000008ff</color> + <color name="i_am_color_900">#00000900</color> + <color name="i_am_color_901">#00000901</color> + <color name="i_am_color_902">#00000902</color> + <color name="i_am_color_903">#00000903</color> + <color name="i_am_color_904">#00000904</color> + <color name="i_am_color_905">#00000905</color> + <color name="i_am_color_906">#00000906</color> + <color name="i_am_color_907">#00000907</color> + <color name="i_am_color_908">#00000908</color> + <color name="i_am_color_909">#00000909</color> + <color name="i_am_color_90a">#0000090a</color> + <color name="i_am_color_90b">#0000090b</color> + <color name="i_am_color_90c">#0000090c</color> + <color name="i_am_color_90d">#0000090d</color> + <color name="i_am_color_90e">#0000090e</color> + <color name="i_am_color_90f">#0000090f</color> + <color name="i_am_color_910">#00000910</color> + <color name="i_am_color_911">#00000911</color> + <color name="i_am_color_912">#00000912</color> + <color name="i_am_color_913">#00000913</color> + <color name="i_am_color_914">#00000914</color> + <color name="i_am_color_915">#00000915</color> + <color name="i_am_color_916">#00000916</color> + <color name="i_am_color_917">#00000917</color> + <color name="i_am_color_918">#00000918</color> + <color name="i_am_color_919">#00000919</color> + <color name="i_am_color_91a">#0000091a</color> + <color name="i_am_color_91b">#0000091b</color> + <color name="i_am_color_91c">#0000091c</color> + <color name="i_am_color_91d">#0000091d</color> + <color name="i_am_color_91e">#0000091e</color> + <color name="i_am_color_91f">#0000091f</color> + <color name="i_am_color_920">#00000920</color> + <color name="i_am_color_921">#00000921</color> + <color name="i_am_color_922">#00000922</color> + <color name="i_am_color_923">#00000923</color> + <color name="i_am_color_924">#00000924</color> + <color name="i_am_color_925">#00000925</color> + <color name="i_am_color_926">#00000926</color> + <color name="i_am_color_927">#00000927</color> + <color name="i_am_color_928">#00000928</color> + <color name="i_am_color_929">#00000929</color> + <color name="i_am_color_92a">#0000092a</color> + <color name="i_am_color_92b">#0000092b</color> + <color name="i_am_color_92c">#0000092c</color> + <color name="i_am_color_92d">#0000092d</color> + <color name="i_am_color_92e">#0000092e</color> + <color name="i_am_color_92f">#0000092f</color> + <color name="i_am_color_930">#00000930</color> + <color name="i_am_color_931">#00000931</color> + <color name="i_am_color_932">#00000932</color> + <color name="i_am_color_933">#00000933</color> + <color name="i_am_color_934">#00000934</color> + <color name="i_am_color_935">#00000935</color> + <color name="i_am_color_936">#00000936</color> + <color name="i_am_color_937">#00000937</color> + <color name="i_am_color_938">#00000938</color> + <color name="i_am_color_939">#00000939</color> + <color name="i_am_color_93a">#0000093a</color> + <color name="i_am_color_93b">#0000093b</color> + <color name="i_am_color_93c">#0000093c</color> + <color name="i_am_color_93d">#0000093d</color> + <color name="i_am_color_93e">#0000093e</color> + <color name="i_am_color_93f">#0000093f</color> + <color name="i_am_color_940">#00000940</color> + <color name="i_am_color_941">#00000941</color> + <color name="i_am_color_942">#00000942</color> + <color name="i_am_color_943">#00000943</color> + <color name="i_am_color_944">#00000944</color> + <color name="i_am_color_945">#00000945</color> + <color name="i_am_color_946">#00000946</color> + <color name="i_am_color_947">#00000947</color> + <color name="i_am_color_948">#00000948</color> + <color name="i_am_color_949">#00000949</color> + <color name="i_am_color_94a">#0000094a</color> + <color name="i_am_color_94b">#0000094b</color> + <color name="i_am_color_94c">#0000094c</color> + <color name="i_am_color_94d">#0000094d</color> + <color name="i_am_color_94e">#0000094e</color> + <color name="i_am_color_94f">#0000094f</color> + <color name="i_am_color_950">#00000950</color> + <color name="i_am_color_951">#00000951</color> + <color name="i_am_color_952">#00000952</color> + <color name="i_am_color_953">#00000953</color> + <color name="i_am_color_954">#00000954</color> + <color name="i_am_color_955">#00000955</color> + <color name="i_am_color_956">#00000956</color> + <color name="i_am_color_957">#00000957</color> + <color name="i_am_color_958">#00000958</color> + <color name="i_am_color_959">#00000959</color> + <color name="i_am_color_95a">#0000095a</color> + <color name="i_am_color_95b">#0000095b</color> + <color name="i_am_color_95c">#0000095c</color> + <color name="i_am_color_95d">#0000095d</color> + <color name="i_am_color_95e">#0000095e</color> + <color name="i_am_color_95f">#0000095f</color> + <color name="i_am_color_960">#00000960</color> + <color name="i_am_color_961">#00000961</color> + <color name="i_am_color_962">#00000962</color> + <color name="i_am_color_963">#00000963</color> + <color name="i_am_color_964">#00000964</color> + <color name="i_am_color_965">#00000965</color> + <color name="i_am_color_966">#00000966</color> + <color name="i_am_color_967">#00000967</color> + <color name="i_am_color_968">#00000968</color> + <color name="i_am_color_969">#00000969</color> + <color name="i_am_color_96a">#0000096a</color> + <color name="i_am_color_96b">#0000096b</color> + <color name="i_am_color_96c">#0000096c</color> + <color name="i_am_color_96d">#0000096d</color> + <color name="i_am_color_96e">#0000096e</color> + <color name="i_am_color_96f">#0000096f</color> + <color name="i_am_color_970">#00000970</color> + <color name="i_am_color_971">#00000971</color> + <color name="i_am_color_972">#00000972</color> + <color name="i_am_color_973">#00000973</color> + <color name="i_am_color_974">#00000974</color> + <color name="i_am_color_975">#00000975</color> + <color name="i_am_color_976">#00000976</color> + <color name="i_am_color_977">#00000977</color> + <color name="i_am_color_978">#00000978</color> + <color name="i_am_color_979">#00000979</color> + <color name="i_am_color_97a">#0000097a</color> + <color name="i_am_color_97b">#0000097b</color> + <color name="i_am_color_97c">#0000097c</color> + <color name="i_am_color_97d">#0000097d</color> + <color name="i_am_color_97e">#0000097e</color> + <color name="i_am_color_97f">#0000097f</color> + <color name="i_am_color_980">#00000980</color> + <color name="i_am_color_981">#00000981</color> + <color name="i_am_color_982">#00000982</color> + <color name="i_am_color_983">#00000983</color> + <color name="i_am_color_984">#00000984</color> + <color name="i_am_color_985">#00000985</color> + <color name="i_am_color_986">#00000986</color> + <color name="i_am_color_987">#00000987</color> + <color name="i_am_color_988">#00000988</color> + <color name="i_am_color_989">#00000989</color> + <color name="i_am_color_98a">#0000098a</color> + <color name="i_am_color_98b">#0000098b</color> + <color name="i_am_color_98c">#0000098c</color> + <color name="i_am_color_98d">#0000098d</color> + <color name="i_am_color_98e">#0000098e</color> + <color name="i_am_color_98f">#0000098f</color> + <color name="i_am_color_990">#00000990</color> + <color name="i_am_color_991">#00000991</color> + <color name="i_am_color_992">#00000992</color> + <color name="i_am_color_993">#00000993</color> + <color name="i_am_color_994">#00000994</color> + <color name="i_am_color_995">#00000995</color> + <color name="i_am_color_996">#00000996</color> + <color name="i_am_color_997">#00000997</color> + <color name="i_am_color_998">#00000998</color> + <color name="i_am_color_999">#00000999</color> + <color name="i_am_color_99a">#0000099a</color> + <color name="i_am_color_99b">#0000099b</color> + <color name="i_am_color_99c">#0000099c</color> + <color name="i_am_color_99d">#0000099d</color> + <color name="i_am_color_99e">#0000099e</color> + <color name="i_am_color_99f">#0000099f</color> + <color name="i_am_color_9a0">#000009a0</color> + <color name="i_am_color_9a1">#000009a1</color> + <color name="i_am_color_9a2">#000009a2</color> + <color name="i_am_color_9a3">#000009a3</color> + <color name="i_am_color_9a4">#000009a4</color> + <color name="i_am_color_9a5">#000009a5</color> + <color name="i_am_color_9a6">#000009a6</color> + <color name="i_am_color_9a7">#000009a7</color> + <color name="i_am_color_9a8">#000009a8</color> + <color name="i_am_color_9a9">#000009a9</color> + <color name="i_am_color_9aa">#000009aa</color> + <color name="i_am_color_9ab">#000009ab</color> + <color name="i_am_color_9ac">#000009ac</color> + <color name="i_am_color_9ad">#000009ad</color> + <color name="i_am_color_9ae">#000009ae</color> + <color name="i_am_color_9af">#000009af</color> + <color name="i_am_color_9b0">#000009b0</color> + <color name="i_am_color_9b1">#000009b1</color> + <color name="i_am_color_9b2">#000009b2</color> + <color name="i_am_color_9b3">#000009b3</color> + <color name="i_am_color_9b4">#000009b4</color> + <color name="i_am_color_9b5">#000009b5</color> + <color name="i_am_color_9b6">#000009b6</color> + <color name="i_am_color_9b7">#000009b7</color> + <color name="i_am_color_9b8">#000009b8</color> + <color name="i_am_color_9b9">#000009b9</color> + <color name="i_am_color_9ba">#000009ba</color> + <color name="i_am_color_9bb">#000009bb</color> + <color name="i_am_color_9bc">#000009bc</color> + <color name="i_am_color_9bd">#000009bd</color> + <color name="i_am_color_9be">#000009be</color> + <color name="i_am_color_9bf">#000009bf</color> + <color name="i_am_color_9c0">#000009c0</color> + <color name="i_am_color_9c1">#000009c1</color> + <color name="i_am_color_9c2">#000009c2</color> + <color name="i_am_color_9c3">#000009c3</color> + <color name="i_am_color_9c4">#000009c4</color> + <color name="i_am_color_9c5">#000009c5</color> + <color name="i_am_color_9c6">#000009c6</color> + <color name="i_am_color_9c7">#000009c7</color> + <color name="i_am_color_9c8">#000009c8</color> + <color name="i_am_color_9c9">#000009c9</color> + <color name="i_am_color_9ca">#000009ca</color> + <color name="i_am_color_9cb">#000009cb</color> + <color name="i_am_color_9cc">#000009cc</color> + <color name="i_am_color_9cd">#000009cd</color> + <color name="i_am_color_9ce">#000009ce</color> + <color name="i_am_color_9cf">#000009cf</color> + <color name="i_am_color_9d0">#000009d0</color> + <color name="i_am_color_9d1">#000009d1</color> + <color name="i_am_color_9d2">#000009d2</color> + <color name="i_am_color_9d3">#000009d3</color> + <color name="i_am_color_9d4">#000009d4</color> + <color name="i_am_color_9d5">#000009d5</color> + <color name="i_am_color_9d6">#000009d6</color> + <color name="i_am_color_9d7">#000009d7</color> + <color name="i_am_color_9d8">#000009d8</color> + <color name="i_am_color_9d9">#000009d9</color> + <color name="i_am_color_9da">#000009da</color> + <color name="i_am_color_9db">#000009db</color> + <color name="i_am_color_9dc">#000009dc</color> + <color name="i_am_color_9dd">#000009dd</color> + <color name="i_am_color_9de">#000009de</color> + <color name="i_am_color_9df">#000009df</color> + <color name="i_am_color_9e0">#000009e0</color> + <color name="i_am_color_9e1">#000009e1</color> + <color name="i_am_color_9e2">#000009e2</color> + <color name="i_am_color_9e3">#000009e3</color> + <color name="i_am_color_9e4">#000009e4</color> + <color name="i_am_color_9e5">#000009e5</color> + <color name="i_am_color_9e6">#000009e6</color> + <color name="i_am_color_9e7">#000009e7</color> + <color name="i_am_color_9e8">#000009e8</color> + <color name="i_am_color_9e9">#000009e9</color> + <color name="i_am_color_9ea">#000009ea</color> + <color name="i_am_color_9eb">#000009eb</color> + <color name="i_am_color_9ec">#000009ec</color> + <color name="i_am_color_9ed">#000009ed</color> + <color name="i_am_color_9ee">#000009ee</color> + <color name="i_am_color_9ef">#000009ef</color> + <color name="i_am_color_9f0">#000009f0</color> + <color name="i_am_color_9f1">#000009f1</color> + <color name="i_am_color_9f2">#000009f2</color> + <color name="i_am_color_9f3">#000009f3</color> + <color name="i_am_color_9f4">#000009f4</color> + <color name="i_am_color_9f5">#000009f5</color> + <color name="i_am_color_9f6">#000009f6</color> + <color name="i_am_color_9f7">#000009f7</color> + <color name="i_am_color_9f8">#000009f8</color> + <color name="i_am_color_9f9">#000009f9</color> + <color name="i_am_color_9fa">#000009fa</color> + <color name="i_am_color_9fb">#000009fb</color> + <color name="i_am_color_9fc">#000009fc</color> + <color name="i_am_color_9fd">#000009fd</color> + <color name="i_am_color_9fe">#000009fe</color> + <color name="i_am_color_9ff">#000009ff</color> + <color name="i_am_color_a00">#00000a00</color> + <color name="i_am_color_a01">#00000a01</color> + <color name="i_am_color_a02">#00000a02</color> + <color name="i_am_color_a03">#00000a03</color> + <color name="i_am_color_a04">#00000a04</color> + <color name="i_am_color_a05">#00000a05</color> + <color name="i_am_color_a06">#00000a06</color> + <color name="i_am_color_a07">#00000a07</color> + <color name="i_am_color_a08">#00000a08</color> + <color name="i_am_color_a09">#00000a09</color> + <color name="i_am_color_a0a">#00000a0a</color> + <color name="i_am_color_a0b">#00000a0b</color> + <color name="i_am_color_a0c">#00000a0c</color> + <color name="i_am_color_a0d">#00000a0d</color> + <color name="i_am_color_a0e">#00000a0e</color> + <color name="i_am_color_a0f">#00000a0f</color> + <color name="i_am_color_a10">#00000a10</color> + <color name="i_am_color_a11">#00000a11</color> + <color name="i_am_color_a12">#00000a12</color> + <color name="i_am_color_a13">#00000a13</color> + <color name="i_am_color_a14">#00000a14</color> + <color name="i_am_color_a15">#00000a15</color> + <color name="i_am_color_a16">#00000a16</color> + <color name="i_am_color_a17">#00000a17</color> + <color name="i_am_color_a18">#00000a18</color> + <color name="i_am_color_a19">#00000a19</color> + <color name="i_am_color_a1a">#00000a1a</color> + <color name="i_am_color_a1b">#00000a1b</color> + <color name="i_am_color_a1c">#00000a1c</color> + <color name="i_am_color_a1d">#00000a1d</color> + <color name="i_am_color_a1e">#00000a1e</color> + <color name="i_am_color_a1f">#00000a1f</color> + <color name="i_am_color_a20">#00000a20</color> + <color name="i_am_color_a21">#00000a21</color> + <color name="i_am_color_a22">#00000a22</color> + <color name="i_am_color_a23">#00000a23</color> + <color name="i_am_color_a24">#00000a24</color> + <color name="i_am_color_a25">#00000a25</color> + <color name="i_am_color_a26">#00000a26</color> + <color name="i_am_color_a27">#00000a27</color> + <color name="i_am_color_a28">#00000a28</color> + <color name="i_am_color_a29">#00000a29</color> + <color name="i_am_color_a2a">#00000a2a</color> + <color name="i_am_color_a2b">#00000a2b</color> + <color name="i_am_color_a2c">#00000a2c</color> + <color name="i_am_color_a2d">#00000a2d</color> + <color name="i_am_color_a2e">#00000a2e</color> + <color name="i_am_color_a2f">#00000a2f</color> + <color name="i_am_color_a30">#00000a30</color> + <color name="i_am_color_a31">#00000a31</color> + <color name="i_am_color_a32">#00000a32</color> + <color name="i_am_color_a33">#00000a33</color> + <color name="i_am_color_a34">#00000a34</color> + <color name="i_am_color_a35">#00000a35</color> + <color name="i_am_color_a36">#00000a36</color> + <color name="i_am_color_a37">#00000a37</color> + <color name="i_am_color_a38">#00000a38</color> + <color name="i_am_color_a39">#00000a39</color> + <color name="i_am_color_a3a">#00000a3a</color> + <color name="i_am_color_a3b">#00000a3b</color> + <color name="i_am_color_a3c">#00000a3c</color> + <color name="i_am_color_a3d">#00000a3d</color> + <color name="i_am_color_a3e">#00000a3e</color> + <color name="i_am_color_a3f">#00000a3f</color> + <color name="i_am_color_a40">#00000a40</color> + <color name="i_am_color_a41">#00000a41</color> + <color name="i_am_color_a42">#00000a42</color> + <color name="i_am_color_a43">#00000a43</color> + <color name="i_am_color_a44">#00000a44</color> + <color name="i_am_color_a45">#00000a45</color> + <color name="i_am_color_a46">#00000a46</color> + <color name="i_am_color_a47">#00000a47</color> + <color name="i_am_color_a48">#00000a48</color> + <color name="i_am_color_a49">#00000a49</color> + <color name="i_am_color_a4a">#00000a4a</color> + <color name="i_am_color_a4b">#00000a4b</color> + <color name="i_am_color_a4c">#00000a4c</color> + <color name="i_am_color_a4d">#00000a4d</color> + <color name="i_am_color_a4e">#00000a4e</color> + <color name="i_am_color_a4f">#00000a4f</color> + <color name="i_am_color_a50">#00000a50</color> + <color name="i_am_color_a51">#00000a51</color> + <color name="i_am_color_a52">#00000a52</color> + <color name="i_am_color_a53">#00000a53</color> + <color name="i_am_color_a54">#00000a54</color> + <color name="i_am_color_a55">#00000a55</color> + <color name="i_am_color_a56">#00000a56</color> + <color name="i_am_color_a57">#00000a57</color> + <color name="i_am_color_a58">#00000a58</color> + <color name="i_am_color_a59">#00000a59</color> + <color name="i_am_color_a5a">#00000a5a</color> + <color name="i_am_color_a5b">#00000a5b</color> + <color name="i_am_color_a5c">#00000a5c</color> + <color name="i_am_color_a5d">#00000a5d</color> + <color name="i_am_color_a5e">#00000a5e</color> + <color name="i_am_color_a5f">#00000a5f</color> + <color name="i_am_color_a60">#00000a60</color> + <color name="i_am_color_a61">#00000a61</color> + <color name="i_am_color_a62">#00000a62</color> + <color name="i_am_color_a63">#00000a63</color> + <color name="i_am_color_a64">#00000a64</color> + <color name="i_am_color_a65">#00000a65</color> + <color name="i_am_color_a66">#00000a66</color> + <color name="i_am_color_a67">#00000a67</color> + <color name="i_am_color_a68">#00000a68</color> + <color name="i_am_color_a69">#00000a69</color> + <color name="i_am_color_a6a">#00000a6a</color> + <color name="i_am_color_a6b">#00000a6b</color> + <color name="i_am_color_a6c">#00000a6c</color> + <color name="i_am_color_a6d">#00000a6d</color> + <color name="i_am_color_a6e">#00000a6e</color> + <color name="i_am_color_a6f">#00000a6f</color> + <color name="i_am_color_a70">#00000a70</color> + <color name="i_am_color_a71">#00000a71</color> + <color name="i_am_color_a72">#00000a72</color> + <color name="i_am_color_a73">#00000a73</color> + <color name="i_am_color_a74">#00000a74</color> + <color name="i_am_color_a75">#00000a75</color> + <color name="i_am_color_a76">#00000a76</color> + <color name="i_am_color_a77">#00000a77</color> + <color name="i_am_color_a78">#00000a78</color> + <color name="i_am_color_a79">#00000a79</color> + <color name="i_am_color_a7a">#00000a7a</color> + <color name="i_am_color_a7b">#00000a7b</color> + <color name="i_am_color_a7c">#00000a7c</color> + <color name="i_am_color_a7d">#00000a7d</color> + <color name="i_am_color_a7e">#00000a7e</color> + <color name="i_am_color_a7f">#00000a7f</color> + <color name="i_am_color_a80">#00000a80</color> + <color name="i_am_color_a81">#00000a81</color> + <color name="i_am_color_a82">#00000a82</color> + <color name="i_am_color_a83">#00000a83</color> + <color name="i_am_color_a84">#00000a84</color> + <color name="i_am_color_a85">#00000a85</color> + <color name="i_am_color_a86">#00000a86</color> + <color name="i_am_color_a87">#00000a87</color> + <color name="i_am_color_a88">#00000a88</color> + <color name="i_am_color_a89">#00000a89</color> + <color name="i_am_color_a8a">#00000a8a</color> + <color name="i_am_color_a8b">#00000a8b</color> + <color name="i_am_color_a8c">#00000a8c</color> + <color name="i_am_color_a8d">#00000a8d</color> + <color name="i_am_color_a8e">#00000a8e</color> + <color name="i_am_color_a8f">#00000a8f</color> + <color name="i_am_color_a90">#00000a90</color> + <color name="i_am_color_a91">#00000a91</color> + <color name="i_am_color_a92">#00000a92</color> + <color name="i_am_color_a93">#00000a93</color> + <color name="i_am_color_a94">#00000a94</color> + <color name="i_am_color_a95">#00000a95</color> + <color name="i_am_color_a96">#00000a96</color> + <color name="i_am_color_a97">#00000a97</color> + <color name="i_am_color_a98">#00000a98</color> + <color name="i_am_color_a99">#00000a99</color> + <color name="i_am_color_a9a">#00000a9a</color> + <color name="i_am_color_a9b">#00000a9b</color> + <color name="i_am_color_a9c">#00000a9c</color> + <color name="i_am_color_a9d">#00000a9d</color> + <color name="i_am_color_a9e">#00000a9e</color> + <color name="i_am_color_a9f">#00000a9f</color> + <color name="i_am_color_aa0">#00000aa0</color> + <color name="i_am_color_aa1">#00000aa1</color> + <color name="i_am_color_aa2">#00000aa2</color> + <color name="i_am_color_aa3">#00000aa3</color> + <color name="i_am_color_aa4">#00000aa4</color> + <color name="i_am_color_aa5">#00000aa5</color> + <color name="i_am_color_aa6">#00000aa6</color> + <color name="i_am_color_aa7">#00000aa7</color> + <color name="i_am_color_aa8">#00000aa8</color> + <color name="i_am_color_aa9">#00000aa9</color> + <color name="i_am_color_aaa">#00000aaa</color> + <color name="i_am_color_aab">#00000aab</color> + <color name="i_am_color_aac">#00000aac</color> + <color name="i_am_color_aad">#00000aad</color> + <color name="i_am_color_aae">#00000aae</color> + <color name="i_am_color_aaf">#00000aaf</color> + <color name="i_am_color_ab0">#00000ab0</color> + <color name="i_am_color_ab1">#00000ab1</color> + <color name="i_am_color_ab2">#00000ab2</color> + <color name="i_am_color_ab3">#00000ab3</color> + <color name="i_am_color_ab4">#00000ab4</color> + <color name="i_am_color_ab5">#00000ab5</color> + <color name="i_am_color_ab6">#00000ab6</color> + <color name="i_am_color_ab7">#00000ab7</color> + <color name="i_am_color_ab8">#00000ab8</color> + <color name="i_am_color_ab9">#00000ab9</color> + <color name="i_am_color_aba">#00000aba</color> + <color name="i_am_color_abb">#00000abb</color> + <color name="i_am_color_abc">#00000abc</color> + <color name="i_am_color_abd">#00000abd</color> + <color name="i_am_color_abe">#00000abe</color> + <color name="i_am_color_abf">#00000abf</color> + <color name="i_am_color_ac0">#00000ac0</color> + <color name="i_am_color_ac1">#00000ac1</color> + <color name="i_am_color_ac2">#00000ac2</color> + <color name="i_am_color_ac3">#00000ac3</color> + <color name="i_am_color_ac4">#00000ac4</color> + <color name="i_am_color_ac5">#00000ac5</color> + <color name="i_am_color_ac6">#00000ac6</color> + <color name="i_am_color_ac7">#00000ac7</color> + <color name="i_am_color_ac8">#00000ac8</color> + <color name="i_am_color_ac9">#00000ac9</color> + <color name="i_am_color_aca">#00000aca</color> + <color name="i_am_color_acb">#00000acb</color> + <color name="i_am_color_acc">#00000acc</color> + <color name="i_am_color_acd">#00000acd</color> + <color name="i_am_color_ace">#00000ace</color> + <color name="i_am_color_acf">#00000acf</color> + <color name="i_am_color_ad0">#00000ad0</color> + <color name="i_am_color_ad1">#00000ad1</color> + <color name="i_am_color_ad2">#00000ad2</color> + <color name="i_am_color_ad3">#00000ad3</color> + <color name="i_am_color_ad4">#00000ad4</color> + <color name="i_am_color_ad5">#00000ad5</color> + <color name="i_am_color_ad6">#00000ad6</color> + <color name="i_am_color_ad7">#00000ad7</color> + <color name="i_am_color_ad8">#00000ad8</color> + <color name="i_am_color_ad9">#00000ad9</color> + <color name="i_am_color_ada">#00000ada</color> + <color name="i_am_color_adb">#00000adb</color> + <color name="i_am_color_adc">#00000adc</color> + <color name="i_am_color_add">#00000add</color> + <color name="i_am_color_ade">#00000ade</color> + <color name="i_am_color_adf">#00000adf</color> + <color name="i_am_color_ae0">#00000ae0</color> + <color name="i_am_color_ae1">#00000ae1</color> + <color name="i_am_color_ae2">#00000ae2</color> + <color name="i_am_color_ae3">#00000ae3</color> + <color name="i_am_color_ae4">#00000ae4</color> + <color name="i_am_color_ae5">#00000ae5</color> + <color name="i_am_color_ae6">#00000ae6</color> + <color name="i_am_color_ae7">#00000ae7</color> + <color name="i_am_color_ae8">#00000ae8</color> + <color name="i_am_color_ae9">#00000ae9</color> + <color name="i_am_color_aea">#00000aea</color> + <color name="i_am_color_aeb">#00000aeb</color> + <color name="i_am_color_aec">#00000aec</color> + <color name="i_am_color_aed">#00000aed</color> + <color name="i_am_color_aee">#00000aee</color> + <color name="i_am_color_aef">#00000aef</color> + <color name="i_am_color_af0">#00000af0</color> + <color name="i_am_color_af1">#00000af1</color> + <color name="i_am_color_af2">#00000af2</color> + <color name="i_am_color_af3">#00000af3</color> + <color name="i_am_color_af4">#00000af4</color> + <color name="i_am_color_af5">#00000af5</color> + <color name="i_am_color_af6">#00000af6</color> + <color name="i_am_color_af7">#00000af7</color> + <color name="i_am_color_af8">#00000af8</color> + <color name="i_am_color_af9">#00000af9</color> + <color name="i_am_color_afa">#00000afa</color> + <color name="i_am_color_afb">#00000afb</color> + <color name="i_am_color_afc">#00000afc</color> + <color name="i_am_color_afd">#00000afd</color> + <color name="i_am_color_afe">#00000afe</color> + <color name="i_am_color_aff">#00000aff</color> + <color name="i_am_color_b00">#00000b00</color> + <color name="i_am_color_b01">#00000b01</color> + <color name="i_am_color_b02">#00000b02</color> + <color name="i_am_color_b03">#00000b03</color> + <color name="i_am_color_b04">#00000b04</color> + <color name="i_am_color_b05">#00000b05</color> + <color name="i_am_color_b06">#00000b06</color> + <color name="i_am_color_b07">#00000b07</color> + <color name="i_am_color_b08">#00000b08</color> + <color name="i_am_color_b09">#00000b09</color> + <color name="i_am_color_b0a">#00000b0a</color> + <color name="i_am_color_b0b">#00000b0b</color> + <color name="i_am_color_b0c">#00000b0c</color> + <color name="i_am_color_b0d">#00000b0d</color> + <color name="i_am_color_b0e">#00000b0e</color> + <color name="i_am_color_b0f">#00000b0f</color> + <color name="i_am_color_b10">#00000b10</color> + <color name="i_am_color_b11">#00000b11</color> + <color name="i_am_color_b12">#00000b12</color> + <color name="i_am_color_b13">#00000b13</color> + <color name="i_am_color_b14">#00000b14</color> + <color name="i_am_color_b15">#00000b15</color> + <color name="i_am_color_b16">#00000b16</color> + <color name="i_am_color_b17">#00000b17</color> + <color name="i_am_color_b18">#00000b18</color> + <color name="i_am_color_b19">#00000b19</color> + <color name="i_am_color_b1a">#00000b1a</color> + <color name="i_am_color_b1b">#00000b1b</color> + <color name="i_am_color_b1c">#00000b1c</color> + <color name="i_am_color_b1d">#00000b1d</color> + <color name="i_am_color_b1e">#00000b1e</color> + <color name="i_am_color_b1f">#00000b1f</color> + <color name="i_am_color_b20">#00000b20</color> + <color name="i_am_color_b21">#00000b21</color> + <color name="i_am_color_b22">#00000b22</color> + <color name="i_am_color_b23">#00000b23</color> + <color name="i_am_color_b24">#00000b24</color> + <color name="i_am_color_b25">#00000b25</color> + <color name="i_am_color_b26">#00000b26</color> + <color name="i_am_color_b27">#00000b27</color> + <color name="i_am_color_b28">#00000b28</color> + <color name="i_am_color_b29">#00000b29</color> + <color name="i_am_color_b2a">#00000b2a</color> + <color name="i_am_color_b2b">#00000b2b</color> + <color name="i_am_color_b2c">#00000b2c</color> + <color name="i_am_color_b2d">#00000b2d</color> + <color name="i_am_color_b2e">#00000b2e</color> + <color name="i_am_color_b2f">#00000b2f</color> + <color name="i_am_color_b30">#00000b30</color> + <color name="i_am_color_b31">#00000b31</color> + <color name="i_am_color_b32">#00000b32</color> + <color name="i_am_color_b33">#00000b33</color> + <color name="i_am_color_b34">#00000b34</color> + <color name="i_am_color_b35">#00000b35</color> + <color name="i_am_color_b36">#00000b36</color> + <color name="i_am_color_b37">#00000b37</color> + <color name="i_am_color_b38">#00000b38</color> + <color name="i_am_color_b39">#00000b39</color> + <color name="i_am_color_b3a">#00000b3a</color> + <color name="i_am_color_b3b">#00000b3b</color> + <color name="i_am_color_b3c">#00000b3c</color> + <color name="i_am_color_b3d">#00000b3d</color> + <color name="i_am_color_b3e">#00000b3e</color> + <color name="i_am_color_b3f">#00000b3f</color> + <color name="i_am_color_b40">#00000b40</color> + <color name="i_am_color_b41">#00000b41</color> + <color name="i_am_color_b42">#00000b42</color> + <color name="i_am_color_b43">#00000b43</color> + <color name="i_am_color_b44">#00000b44</color> + <color name="i_am_color_b45">#00000b45</color> + <color name="i_am_color_b46">#00000b46</color> + <color name="i_am_color_b47">#00000b47</color> + <color name="i_am_color_b48">#00000b48</color> + <color name="i_am_color_b49">#00000b49</color> + <color name="i_am_color_b4a">#00000b4a</color> + <color name="i_am_color_b4b">#00000b4b</color> + <color name="i_am_color_b4c">#00000b4c</color> + <color name="i_am_color_b4d">#00000b4d</color> + <color name="i_am_color_b4e">#00000b4e</color> + <color name="i_am_color_b4f">#00000b4f</color> + <color name="i_am_color_b50">#00000b50</color> + <color name="i_am_color_b51">#00000b51</color> + <color name="i_am_color_b52">#00000b52</color> + <color name="i_am_color_b53">#00000b53</color> + <color name="i_am_color_b54">#00000b54</color> + <color name="i_am_color_b55">#00000b55</color> + <color name="i_am_color_b56">#00000b56</color> + <color name="i_am_color_b57">#00000b57</color> + <color name="i_am_color_b58">#00000b58</color> + <color name="i_am_color_b59">#00000b59</color> + <color name="i_am_color_b5a">#00000b5a</color> + <color name="i_am_color_b5b">#00000b5b</color> + <color name="i_am_color_b5c">#00000b5c</color> + <color name="i_am_color_b5d">#00000b5d</color> + <color name="i_am_color_b5e">#00000b5e</color> + <color name="i_am_color_b5f">#00000b5f</color> + <color name="i_am_color_b60">#00000b60</color> + <color name="i_am_color_b61">#00000b61</color> + <color name="i_am_color_b62">#00000b62</color> + <color name="i_am_color_b63">#00000b63</color> + <color name="i_am_color_b64">#00000b64</color> + <color name="i_am_color_b65">#00000b65</color> + <color name="i_am_color_b66">#00000b66</color> + <color name="i_am_color_b67">#00000b67</color> + <color name="i_am_color_b68">#00000b68</color> + <color name="i_am_color_b69">#00000b69</color> + <color name="i_am_color_b6a">#00000b6a</color> + <color name="i_am_color_b6b">#00000b6b</color> + <color name="i_am_color_b6c">#00000b6c</color> + <color name="i_am_color_b6d">#00000b6d</color> + <color name="i_am_color_b6e">#00000b6e</color> + <color name="i_am_color_b6f">#00000b6f</color> + <color name="i_am_color_b70">#00000b70</color> + <color name="i_am_color_b71">#00000b71</color> + <color name="i_am_color_b72">#00000b72</color> + <color name="i_am_color_b73">#00000b73</color> + <color name="i_am_color_b74">#00000b74</color> + <color name="i_am_color_b75">#00000b75</color> + <color name="i_am_color_b76">#00000b76</color> + <color name="i_am_color_b77">#00000b77</color> + <color name="i_am_color_b78">#00000b78</color> + <color name="i_am_color_b79">#00000b79</color> + <color name="i_am_color_b7a">#00000b7a</color> + <color name="i_am_color_b7b">#00000b7b</color> + <color name="i_am_color_b7c">#00000b7c</color> + <color name="i_am_color_b7d">#00000b7d</color> + <color name="i_am_color_b7e">#00000b7e</color> + <color name="i_am_color_b7f">#00000b7f</color> + <color name="i_am_color_b80">#00000b80</color> + <color name="i_am_color_b81">#00000b81</color> + <color name="i_am_color_b82">#00000b82</color> + <color name="i_am_color_b83">#00000b83</color> + <color name="i_am_color_b84">#00000b84</color> + <color name="i_am_color_b85">#00000b85</color> + <color name="i_am_color_b86">#00000b86</color> + <color name="i_am_color_b87">#00000b87</color> + <color name="i_am_color_b88">#00000b88</color> + <color name="i_am_color_b89">#00000b89</color> + <color name="i_am_color_b8a">#00000b8a</color> + <color name="i_am_color_b8b">#00000b8b</color> + <color name="i_am_color_b8c">#00000b8c</color> + <color name="i_am_color_b8d">#00000b8d</color> + <color name="i_am_color_b8e">#00000b8e</color> + <color name="i_am_color_b8f">#00000b8f</color> + <color name="i_am_color_b90">#00000b90</color> + <color name="i_am_color_b91">#00000b91</color> + <color name="i_am_color_b92">#00000b92</color> + <color name="i_am_color_b93">#00000b93</color> + <color name="i_am_color_b94">#00000b94</color> + <color name="i_am_color_b95">#00000b95</color> + <color name="i_am_color_b96">#00000b96</color> + <color name="i_am_color_b97">#00000b97</color> + <color name="i_am_color_b98">#00000b98</color> + <color name="i_am_color_b99">#00000b99</color> + <color name="i_am_color_b9a">#00000b9a</color> + <color name="i_am_color_b9b">#00000b9b</color> + <color name="i_am_color_b9c">#00000b9c</color> + <color name="i_am_color_b9d">#00000b9d</color> + <color name="i_am_color_b9e">#00000b9e</color> + <color name="i_am_color_b9f">#00000b9f</color> + <color name="i_am_color_ba0">#00000ba0</color> + <color name="i_am_color_ba1">#00000ba1</color> + <color name="i_am_color_ba2">#00000ba2</color> + <color name="i_am_color_ba3">#00000ba3</color> + <color name="i_am_color_ba4">#00000ba4</color> + <color name="i_am_color_ba5">#00000ba5</color> + <color name="i_am_color_ba6">#00000ba6</color> + <color name="i_am_color_ba7">#00000ba7</color> + <color name="i_am_color_ba8">#00000ba8</color> + <color name="i_am_color_ba9">#00000ba9</color> + <color name="i_am_color_baa">#00000baa</color> + <color name="i_am_color_bab">#00000bab</color> + <color name="i_am_color_bac">#00000bac</color> + <color name="i_am_color_bad">#00000bad</color> + <color name="i_am_color_bae">#00000bae</color> + <color name="i_am_color_baf">#00000baf</color> + <color name="i_am_color_bb0">#00000bb0</color> + <color name="i_am_color_bb1">#00000bb1</color> + <color name="i_am_color_bb2">#00000bb2</color> + <color name="i_am_color_bb3">#00000bb3</color> + <color name="i_am_color_bb4">#00000bb4</color> + <color name="i_am_color_bb5">#00000bb5</color> + <color name="i_am_color_bb6">#00000bb6</color> + <color name="i_am_color_bb7">#00000bb7</color> + <color name="i_am_color_bb8">#00000bb8</color> + <color name="i_am_color_bb9">#00000bb9</color> + <color name="i_am_color_bba">#00000bba</color> + <color name="i_am_color_bbb">#00000bbb</color> + <color name="i_am_color_bbc">#00000bbc</color> + <color name="i_am_color_bbd">#00000bbd</color> + <color name="i_am_color_bbe">#00000bbe</color> + <color name="i_am_color_bbf">#00000bbf</color> + <color name="i_am_color_bc0">#00000bc0</color> + <color name="i_am_color_bc1">#00000bc1</color> + <color name="i_am_color_bc2">#00000bc2</color> + <color name="i_am_color_bc3">#00000bc3</color> + <color name="i_am_color_bc4">#00000bc4</color> + <color name="i_am_color_bc5">#00000bc5</color> + <color name="i_am_color_bc6">#00000bc6</color> + <color name="i_am_color_bc7">#00000bc7</color> + <color name="i_am_color_bc8">#00000bc8</color> + <color name="i_am_color_bc9">#00000bc9</color> + <color name="i_am_color_bca">#00000bca</color> + <color name="i_am_color_bcb">#00000bcb</color> + <color name="i_am_color_bcc">#00000bcc</color> + <color name="i_am_color_bcd">#00000bcd</color> + <color name="i_am_color_bce">#00000bce</color> + <color name="i_am_color_bcf">#00000bcf</color> + <color name="i_am_color_bd0">#00000bd0</color> + <color name="i_am_color_bd1">#00000bd1</color> + <color name="i_am_color_bd2">#00000bd2</color> + <color name="i_am_color_bd3">#00000bd3</color> + <color name="i_am_color_bd4">#00000bd4</color> + <color name="i_am_color_bd5">#00000bd5</color> + <color name="i_am_color_bd6">#00000bd6</color> + <color name="i_am_color_bd7">#00000bd7</color> + <color name="i_am_color_bd8">#00000bd8</color> + <color name="i_am_color_bd9">#00000bd9</color> + <color name="i_am_color_bda">#00000bda</color> + <color name="i_am_color_bdb">#00000bdb</color> + <color name="i_am_color_bdc">#00000bdc</color> + <color name="i_am_color_bdd">#00000bdd</color> + <color name="i_am_color_bde">#00000bde</color> + <color name="i_am_color_bdf">#00000bdf</color> + <color name="i_am_color_be0">#00000be0</color> + <color name="i_am_color_be1">#00000be1</color> + <color name="i_am_color_be2">#00000be2</color> + <color name="i_am_color_be3">#00000be3</color> + <color name="i_am_color_be4">#00000be4</color> + <color name="i_am_color_be5">#00000be5</color> + <color name="i_am_color_be6">#00000be6</color> + <color name="i_am_color_be7">#00000be7</color> + <color name="i_am_color_be8">#00000be8</color> + <color name="i_am_color_be9">#00000be9</color> + <color name="i_am_color_bea">#00000bea</color> + <color name="i_am_color_beb">#00000beb</color> + <color name="i_am_color_bec">#00000bec</color> + <color name="i_am_color_bed">#00000bed</color> + <color name="i_am_color_bee">#00000bee</color> + <color name="i_am_color_bef">#00000bef</color> + <color name="i_am_color_bf0">#00000bf0</color> + <color name="i_am_color_bf1">#00000bf1</color> + <color name="i_am_color_bf2">#00000bf2</color> + <color name="i_am_color_bf3">#00000bf3</color> + <color name="i_am_color_bf4">#00000bf4</color> + <color name="i_am_color_bf5">#00000bf5</color> + <color name="i_am_color_bf6">#00000bf6</color> + <color name="i_am_color_bf7">#00000bf7</color> + <color name="i_am_color_bf8">#00000bf8</color> + <color name="i_am_color_bf9">#00000bf9</color> + <color name="i_am_color_bfa">#00000bfa</color> + <color name="i_am_color_bfb">#00000bfb</color> + <color name="i_am_color_bfc">#00000bfc</color> + <color name="i_am_color_bfd">#00000bfd</color> + <color name="i_am_color_bfe">#00000bfe</color> + <color name="i_am_color_bff">#00000bff</color> + <color name="i_am_color_c00">#00000c00</color> + <color name="i_am_color_c01">#00000c01</color> + <color name="i_am_color_c02">#00000c02</color> + <color name="i_am_color_c03">#00000c03</color> + <color name="i_am_color_c04">#00000c04</color> + <color name="i_am_color_c05">#00000c05</color> + <color name="i_am_color_c06">#00000c06</color> + <color name="i_am_color_c07">#00000c07</color> + <color name="i_am_color_c08">#00000c08</color> + <color name="i_am_color_c09">#00000c09</color> + <color name="i_am_color_c0a">#00000c0a</color> + <color name="i_am_color_c0b">#00000c0b</color> + <color name="i_am_color_c0c">#00000c0c</color> + <color name="i_am_color_c0d">#00000c0d</color> + <color name="i_am_color_c0e">#00000c0e</color> + <color name="i_am_color_c0f">#00000c0f</color> + <color name="i_am_color_c10">#00000c10</color> + <color name="i_am_color_c11">#00000c11</color> + <color name="i_am_color_c12">#00000c12</color> + <color name="i_am_color_c13">#00000c13</color> + <color name="i_am_color_c14">#00000c14</color> + <color name="i_am_color_c15">#00000c15</color> + <color name="i_am_color_c16">#00000c16</color> + <color name="i_am_color_c17">#00000c17</color> + <color name="i_am_color_c18">#00000c18</color> + <color name="i_am_color_c19">#00000c19</color> + <color name="i_am_color_c1a">#00000c1a</color> + <color name="i_am_color_c1b">#00000c1b</color> + <color name="i_am_color_c1c">#00000c1c</color> + <color name="i_am_color_c1d">#00000c1d</color> + <color name="i_am_color_c1e">#00000c1e</color> + <color name="i_am_color_c1f">#00000c1f</color> + <color name="i_am_color_c20">#00000c20</color> + <color name="i_am_color_c21">#00000c21</color> + <color name="i_am_color_c22">#00000c22</color> + <color name="i_am_color_c23">#00000c23</color> + <color name="i_am_color_c24">#00000c24</color> + <color name="i_am_color_c25">#00000c25</color> + <color name="i_am_color_c26">#00000c26</color> + <color name="i_am_color_c27">#00000c27</color> + <color name="i_am_color_c28">#00000c28</color> + <color name="i_am_color_c29">#00000c29</color> + <color name="i_am_color_c2a">#00000c2a</color> + <color name="i_am_color_c2b">#00000c2b</color> + <color name="i_am_color_c2c">#00000c2c</color> + <color name="i_am_color_c2d">#00000c2d</color> + <color name="i_am_color_c2e">#00000c2e</color> + <color name="i_am_color_c2f">#00000c2f</color> + <color name="i_am_color_c30">#00000c30</color> + <color name="i_am_color_c31">#00000c31</color> + <color name="i_am_color_c32">#00000c32</color> + <color name="i_am_color_c33">#00000c33</color> + <color name="i_am_color_c34">#00000c34</color> + <color name="i_am_color_c35">#00000c35</color> + <color name="i_am_color_c36">#00000c36</color> + <color name="i_am_color_c37">#00000c37</color> + <color name="i_am_color_c38">#00000c38</color> + <color name="i_am_color_c39">#00000c39</color> + <color name="i_am_color_c3a">#00000c3a</color> + <color name="i_am_color_c3b">#00000c3b</color> + <color name="i_am_color_c3c">#00000c3c</color> + <color name="i_am_color_c3d">#00000c3d</color> + <color name="i_am_color_c3e">#00000c3e</color> + <color name="i_am_color_c3f">#00000c3f</color> + <color name="i_am_color_c40">#00000c40</color> + <color name="i_am_color_c41">#00000c41</color> + <color name="i_am_color_c42">#00000c42</color> + <color name="i_am_color_c43">#00000c43</color> + <color name="i_am_color_c44">#00000c44</color> + <color name="i_am_color_c45">#00000c45</color> + <color name="i_am_color_c46">#00000c46</color> + <color name="i_am_color_c47">#00000c47</color> + <color name="i_am_color_c48">#00000c48</color> + <color name="i_am_color_c49">#00000c49</color> + <color name="i_am_color_c4a">#00000c4a</color> + <color name="i_am_color_c4b">#00000c4b</color> + <color name="i_am_color_c4c">#00000c4c</color> + <color name="i_am_color_c4d">#00000c4d</color> + <color name="i_am_color_c4e">#00000c4e</color> + <color name="i_am_color_c4f">#00000c4f</color> + <color name="i_am_color_c50">#00000c50</color> + <color name="i_am_color_c51">#00000c51</color> + <color name="i_am_color_c52">#00000c52</color> + <color name="i_am_color_c53">#00000c53</color> + <color name="i_am_color_c54">#00000c54</color> + <color name="i_am_color_c55">#00000c55</color> + <color name="i_am_color_c56">#00000c56</color> + <color name="i_am_color_c57">#00000c57</color> + <color name="i_am_color_c58">#00000c58</color> + <color name="i_am_color_c59">#00000c59</color> + <color name="i_am_color_c5a">#00000c5a</color> + <color name="i_am_color_c5b">#00000c5b</color> + <color name="i_am_color_c5c">#00000c5c</color> + <color name="i_am_color_c5d">#00000c5d</color> + <color name="i_am_color_c5e">#00000c5e</color> + <color name="i_am_color_c5f">#00000c5f</color> + <color name="i_am_color_c60">#00000c60</color> + <color name="i_am_color_c61">#00000c61</color> + <color name="i_am_color_c62">#00000c62</color> + <color name="i_am_color_c63">#00000c63</color> + <color name="i_am_color_c64">#00000c64</color> + <color name="i_am_color_c65">#00000c65</color> + <color name="i_am_color_c66">#00000c66</color> + <color name="i_am_color_c67">#00000c67</color> + <color name="i_am_color_c68">#00000c68</color> + <color name="i_am_color_c69">#00000c69</color> + <color name="i_am_color_c6a">#00000c6a</color> + <color name="i_am_color_c6b">#00000c6b</color> + <color name="i_am_color_c6c">#00000c6c</color> + <color name="i_am_color_c6d">#00000c6d</color> + <color name="i_am_color_c6e">#00000c6e</color> + <color name="i_am_color_c6f">#00000c6f</color> + <color name="i_am_color_c70">#00000c70</color> + <color name="i_am_color_c71">#00000c71</color> + <color name="i_am_color_c72">#00000c72</color> + <color name="i_am_color_c73">#00000c73</color> + <color name="i_am_color_c74">#00000c74</color> + <color name="i_am_color_c75">#00000c75</color> + <color name="i_am_color_c76">#00000c76</color> + <color name="i_am_color_c77">#00000c77</color> + <color name="i_am_color_c78">#00000c78</color> + <color name="i_am_color_c79">#00000c79</color> + <color name="i_am_color_c7a">#00000c7a</color> + <color name="i_am_color_c7b">#00000c7b</color> + <color name="i_am_color_c7c">#00000c7c</color> + <color name="i_am_color_c7d">#00000c7d</color> + <color name="i_am_color_c7e">#00000c7e</color> + <color name="i_am_color_c7f">#00000c7f</color> + <color name="i_am_color_c80">#00000c80</color> + <color name="i_am_color_c81">#00000c81</color> + <color name="i_am_color_c82">#00000c82</color> + <color name="i_am_color_c83">#00000c83</color> + <color name="i_am_color_c84">#00000c84</color> + <color name="i_am_color_c85">#00000c85</color> + <color name="i_am_color_c86">#00000c86</color> + <color name="i_am_color_c87">#00000c87</color> + <color name="i_am_color_c88">#00000c88</color> + <color name="i_am_color_c89">#00000c89</color> + <color name="i_am_color_c8a">#00000c8a</color> + <color name="i_am_color_c8b">#00000c8b</color> + <color name="i_am_color_c8c">#00000c8c</color> + <color name="i_am_color_c8d">#00000c8d</color> + <color name="i_am_color_c8e">#00000c8e</color> + <color name="i_am_color_c8f">#00000c8f</color> + <color name="i_am_color_c90">#00000c90</color> + <color name="i_am_color_c91">#00000c91</color> + <color name="i_am_color_c92">#00000c92</color> + <color name="i_am_color_c93">#00000c93</color> + <color name="i_am_color_c94">#00000c94</color> + <color name="i_am_color_c95">#00000c95</color> + <color name="i_am_color_c96">#00000c96</color> + <color name="i_am_color_c97">#00000c97</color> + <color name="i_am_color_c98">#00000c98</color> + <color name="i_am_color_c99">#00000c99</color> + <color name="i_am_color_c9a">#00000c9a</color> + <color name="i_am_color_c9b">#00000c9b</color> + <color name="i_am_color_c9c">#00000c9c</color> + <color name="i_am_color_c9d">#00000c9d</color> + <color name="i_am_color_c9e">#00000c9e</color> + <color name="i_am_color_c9f">#00000c9f</color> + <color name="i_am_color_ca0">#00000ca0</color> + <color name="i_am_color_ca1">#00000ca1</color> + <color name="i_am_color_ca2">#00000ca2</color> + <color name="i_am_color_ca3">#00000ca3</color> + <color name="i_am_color_ca4">#00000ca4</color> + <color name="i_am_color_ca5">#00000ca5</color> + <color name="i_am_color_ca6">#00000ca6</color> + <color name="i_am_color_ca7">#00000ca7</color> + <color name="i_am_color_ca8">#00000ca8</color> + <color name="i_am_color_ca9">#00000ca9</color> + <color name="i_am_color_caa">#00000caa</color> + <color name="i_am_color_cab">#00000cab</color> + <color name="i_am_color_cac">#00000cac</color> + <color name="i_am_color_cad">#00000cad</color> + <color name="i_am_color_cae">#00000cae</color> + <color name="i_am_color_caf">#00000caf</color> + <color name="i_am_color_cb0">#00000cb0</color> + <color name="i_am_color_cb1">#00000cb1</color> + <color name="i_am_color_cb2">#00000cb2</color> + <color name="i_am_color_cb3">#00000cb3</color> + <color name="i_am_color_cb4">#00000cb4</color> + <color name="i_am_color_cb5">#00000cb5</color> + <color name="i_am_color_cb6">#00000cb6</color> + <color name="i_am_color_cb7">#00000cb7</color> + <color name="i_am_color_cb8">#00000cb8</color> + <color name="i_am_color_cb9">#00000cb9</color> + <color name="i_am_color_cba">#00000cba</color> + <color name="i_am_color_cbb">#00000cbb</color> + <color name="i_am_color_cbc">#00000cbc</color> + <color name="i_am_color_cbd">#00000cbd</color> + <color name="i_am_color_cbe">#00000cbe</color> + <color name="i_am_color_cbf">#00000cbf</color> + <color name="i_am_color_cc0">#00000cc0</color> + <color name="i_am_color_cc1">#00000cc1</color> + <color name="i_am_color_cc2">#00000cc2</color> + <color name="i_am_color_cc3">#00000cc3</color> + <color name="i_am_color_cc4">#00000cc4</color> + <color name="i_am_color_cc5">#00000cc5</color> + <color name="i_am_color_cc6">#00000cc6</color> + <color name="i_am_color_cc7">#00000cc7</color> + <color name="i_am_color_cc8">#00000cc8</color> + <color name="i_am_color_cc9">#00000cc9</color> + <color name="i_am_color_cca">#00000cca</color> + <color name="i_am_color_ccb">#00000ccb</color> + <color name="i_am_color_ccc">#00000ccc</color> + <color name="i_am_color_ccd">#00000ccd</color> + <color name="i_am_color_cce">#00000cce</color> + <color name="i_am_color_ccf">#00000ccf</color> + <color name="i_am_color_cd0">#00000cd0</color> + <color name="i_am_color_cd1">#00000cd1</color> + <color name="i_am_color_cd2">#00000cd2</color> + <color name="i_am_color_cd3">#00000cd3</color> + <color name="i_am_color_cd4">#00000cd4</color> + <color name="i_am_color_cd5">#00000cd5</color> + <color name="i_am_color_cd6">#00000cd6</color> + <color name="i_am_color_cd7">#00000cd7</color> + <color name="i_am_color_cd8">#00000cd8</color> + <color name="i_am_color_cd9">#00000cd9</color> + <color name="i_am_color_cda">#00000cda</color> + <color name="i_am_color_cdb">#00000cdb</color> + <color name="i_am_color_cdc">#00000cdc</color> + <color name="i_am_color_cdd">#00000cdd</color> + <color name="i_am_color_cde">#00000cde</color> + <color name="i_am_color_cdf">#00000cdf</color> + <color name="i_am_color_ce0">#00000ce0</color> + <color name="i_am_color_ce1">#00000ce1</color> + <color name="i_am_color_ce2">#00000ce2</color> + <color name="i_am_color_ce3">#00000ce3</color> + <color name="i_am_color_ce4">#00000ce4</color> + <color name="i_am_color_ce5">#00000ce5</color> + <color name="i_am_color_ce6">#00000ce6</color> + <color name="i_am_color_ce7">#00000ce7</color> + <color name="i_am_color_ce8">#00000ce8</color> + <color name="i_am_color_ce9">#00000ce9</color> + <color name="i_am_color_cea">#00000cea</color> + <color name="i_am_color_ceb">#00000ceb</color> + <color name="i_am_color_cec">#00000cec</color> + <color name="i_am_color_ced">#00000ced</color> + <color name="i_am_color_cee">#00000cee</color> + <color name="i_am_color_cef">#00000cef</color> + <color name="i_am_color_cf0">#00000cf0</color> + <color name="i_am_color_cf1">#00000cf1</color> + <color name="i_am_color_cf2">#00000cf2</color> + <color name="i_am_color_cf3">#00000cf3</color> + <color name="i_am_color_cf4">#00000cf4</color> + <color name="i_am_color_cf5">#00000cf5</color> + <color name="i_am_color_cf6">#00000cf6</color> + <color name="i_am_color_cf7">#00000cf7</color> + <color name="i_am_color_cf8">#00000cf8</color> + <color name="i_am_color_cf9">#00000cf9</color> + <color name="i_am_color_cfa">#00000cfa</color> + <color name="i_am_color_cfb">#00000cfb</color> + <color name="i_am_color_cfc">#00000cfc</color> + <color name="i_am_color_cfd">#00000cfd</color> + <color name="i_am_color_cfe">#00000cfe</color> + <color name="i_am_color_cff">#00000cff</color> + <color name="i_am_color_d00">#00000d00</color> + <color name="i_am_color_d01">#00000d01</color> + <color name="i_am_color_d02">#00000d02</color> + <color name="i_am_color_d03">#00000d03</color> + <color name="i_am_color_d04">#00000d04</color> + <color name="i_am_color_d05">#00000d05</color> + <color name="i_am_color_d06">#00000d06</color> + <color name="i_am_color_d07">#00000d07</color> + <color name="i_am_color_d08">#00000d08</color> + <color name="i_am_color_d09">#00000d09</color> + <color name="i_am_color_d0a">#00000d0a</color> + <color name="i_am_color_d0b">#00000d0b</color> + <color name="i_am_color_d0c">#00000d0c</color> + <color name="i_am_color_d0d">#00000d0d</color> + <color name="i_am_color_d0e">#00000d0e</color> + <color name="i_am_color_d0f">#00000d0f</color> + <color name="i_am_color_d10">#00000d10</color> + <color name="i_am_color_d11">#00000d11</color> + <color name="i_am_color_d12">#00000d12</color> + <color name="i_am_color_d13">#00000d13</color> + <color name="i_am_color_d14">#00000d14</color> + <color name="i_am_color_d15">#00000d15</color> + <color name="i_am_color_d16">#00000d16</color> + <color name="i_am_color_d17">#00000d17</color> + <color name="i_am_color_d18">#00000d18</color> + <color name="i_am_color_d19">#00000d19</color> + <color name="i_am_color_d1a">#00000d1a</color> + <color name="i_am_color_d1b">#00000d1b</color> + <color name="i_am_color_d1c">#00000d1c</color> + <color name="i_am_color_d1d">#00000d1d</color> + <color name="i_am_color_d1e">#00000d1e</color> + <color name="i_am_color_d1f">#00000d1f</color> + <color name="i_am_color_d20">#00000d20</color> + <color name="i_am_color_d21">#00000d21</color> + <color name="i_am_color_d22">#00000d22</color> + <color name="i_am_color_d23">#00000d23</color> + <color name="i_am_color_d24">#00000d24</color> + <color name="i_am_color_d25">#00000d25</color> + <color name="i_am_color_d26">#00000d26</color> + <color name="i_am_color_d27">#00000d27</color> + <color name="i_am_color_d28">#00000d28</color> + <color name="i_am_color_d29">#00000d29</color> + <color name="i_am_color_d2a">#00000d2a</color> + <color name="i_am_color_d2b">#00000d2b</color> + <color name="i_am_color_d2c">#00000d2c</color> + <color name="i_am_color_d2d">#00000d2d</color> + <color name="i_am_color_d2e">#00000d2e</color> + <color name="i_am_color_d2f">#00000d2f</color> + <color name="i_am_color_d30">#00000d30</color> + <color name="i_am_color_d31">#00000d31</color> + <color name="i_am_color_d32">#00000d32</color> + <color name="i_am_color_d33">#00000d33</color> + <color name="i_am_color_d34">#00000d34</color> + <color name="i_am_color_d35">#00000d35</color> + <color name="i_am_color_d36">#00000d36</color> + <color name="i_am_color_d37">#00000d37</color> + <color name="i_am_color_d38">#00000d38</color> + <color name="i_am_color_d39">#00000d39</color> + <color name="i_am_color_d3a">#00000d3a</color> + <color name="i_am_color_d3b">#00000d3b</color> + <color name="i_am_color_d3c">#00000d3c</color> + <color name="i_am_color_d3d">#00000d3d</color> + <color name="i_am_color_d3e">#00000d3e</color> + <color name="i_am_color_d3f">#00000d3f</color> + <color name="i_am_color_d40">#00000d40</color> + <color name="i_am_color_d41">#00000d41</color> + <color name="i_am_color_d42">#00000d42</color> + <color name="i_am_color_d43">#00000d43</color> + <color name="i_am_color_d44">#00000d44</color> + <color name="i_am_color_d45">#00000d45</color> + <color name="i_am_color_d46">#00000d46</color> + <color name="i_am_color_d47">#00000d47</color> + <color name="i_am_color_d48">#00000d48</color> + <color name="i_am_color_d49">#00000d49</color> + <color name="i_am_color_d4a">#00000d4a</color> + <color name="i_am_color_d4b">#00000d4b</color> + <color name="i_am_color_d4c">#00000d4c</color> + <color name="i_am_color_d4d">#00000d4d</color> + <color name="i_am_color_d4e">#00000d4e</color> + <color name="i_am_color_d4f">#00000d4f</color> + <color name="i_am_color_d50">#00000d50</color> + <color name="i_am_color_d51">#00000d51</color> + <color name="i_am_color_d52">#00000d52</color> + <color name="i_am_color_d53">#00000d53</color> + <color name="i_am_color_d54">#00000d54</color> + <color name="i_am_color_d55">#00000d55</color> + <color name="i_am_color_d56">#00000d56</color> + <color name="i_am_color_d57">#00000d57</color> + <color name="i_am_color_d58">#00000d58</color> + <color name="i_am_color_d59">#00000d59</color> + <color name="i_am_color_d5a">#00000d5a</color> + <color name="i_am_color_d5b">#00000d5b</color> + <color name="i_am_color_d5c">#00000d5c</color> + <color name="i_am_color_d5d">#00000d5d</color> + <color name="i_am_color_d5e">#00000d5e</color> + <color name="i_am_color_d5f">#00000d5f</color> + <color name="i_am_color_d60">#00000d60</color> + <color name="i_am_color_d61">#00000d61</color> + <color name="i_am_color_d62">#00000d62</color> + <color name="i_am_color_d63">#00000d63</color> + <color name="i_am_color_d64">#00000d64</color> + <color name="i_am_color_d65">#00000d65</color> + <color name="i_am_color_d66">#00000d66</color> + <color name="i_am_color_d67">#00000d67</color> + <color name="i_am_color_d68">#00000d68</color> + <color name="i_am_color_d69">#00000d69</color> + <color name="i_am_color_d6a">#00000d6a</color> + <color name="i_am_color_d6b">#00000d6b</color> + <color name="i_am_color_d6c">#00000d6c</color> + <color name="i_am_color_d6d">#00000d6d</color> + <color name="i_am_color_d6e">#00000d6e</color> + <color name="i_am_color_d6f">#00000d6f</color> + <color name="i_am_color_d70">#00000d70</color> + <color name="i_am_color_d71">#00000d71</color> + <color name="i_am_color_d72">#00000d72</color> + <color name="i_am_color_d73">#00000d73</color> + <color name="i_am_color_d74">#00000d74</color> + <color name="i_am_color_d75">#00000d75</color> + <color name="i_am_color_d76">#00000d76</color> + <color name="i_am_color_d77">#00000d77</color> + <color name="i_am_color_d78">#00000d78</color> + <color name="i_am_color_d79">#00000d79</color> + <color name="i_am_color_d7a">#00000d7a</color> + <color name="i_am_color_d7b">#00000d7b</color> + <color name="i_am_color_d7c">#00000d7c</color> + <color name="i_am_color_d7d">#00000d7d</color> + <color name="i_am_color_d7e">#00000d7e</color> + <color name="i_am_color_d7f">#00000d7f</color> + <color name="i_am_color_d80">#00000d80</color> + <color name="i_am_color_d81">#00000d81</color> + <color name="i_am_color_d82">#00000d82</color> + <color name="i_am_color_d83">#00000d83</color> + <color name="i_am_color_d84">#00000d84</color> + <color name="i_am_color_d85">#00000d85</color> + <color name="i_am_color_d86">#00000d86</color> + <color name="i_am_color_d87">#00000d87</color> + <color name="i_am_color_d88">#00000d88</color> + <color name="i_am_color_d89">#00000d89</color> + <color name="i_am_color_d8a">#00000d8a</color> + <color name="i_am_color_d8b">#00000d8b</color> + <color name="i_am_color_d8c">#00000d8c</color> + <color name="i_am_color_d8d">#00000d8d</color> + <color name="i_am_color_d8e">#00000d8e</color> + <color name="i_am_color_d8f">#00000d8f</color> + <color name="i_am_color_d90">#00000d90</color> + <color name="i_am_color_d91">#00000d91</color> + <color name="i_am_color_d92">#00000d92</color> + <color name="i_am_color_d93">#00000d93</color> + <color name="i_am_color_d94">#00000d94</color> + <color name="i_am_color_d95">#00000d95</color> + <color name="i_am_color_d96">#00000d96</color> + <color name="i_am_color_d97">#00000d97</color> + <color name="i_am_color_d98">#00000d98</color> + <color name="i_am_color_d99">#00000d99</color> + <color name="i_am_color_d9a">#00000d9a</color> + <color name="i_am_color_d9b">#00000d9b</color> + <color name="i_am_color_d9c">#00000d9c</color> + <color name="i_am_color_d9d">#00000d9d</color> + <color name="i_am_color_d9e">#00000d9e</color> + <color name="i_am_color_d9f">#00000d9f</color> + <color name="i_am_color_da0">#00000da0</color> + <color name="i_am_color_da1">#00000da1</color> + <color name="i_am_color_da2">#00000da2</color> + <color name="i_am_color_da3">#00000da3</color> + <color name="i_am_color_da4">#00000da4</color> + <color name="i_am_color_da5">#00000da5</color> + <color name="i_am_color_da6">#00000da6</color> + <color name="i_am_color_da7">#00000da7</color> + <color name="i_am_color_da8">#00000da8</color> + <color name="i_am_color_da9">#00000da9</color> + <color name="i_am_color_daa">#00000daa</color> + <color name="i_am_color_dab">#00000dab</color> + <color name="i_am_color_dac">#00000dac</color> + <color name="i_am_color_dad">#00000dad</color> + <color name="i_am_color_dae">#00000dae</color> + <color name="i_am_color_daf">#00000daf</color> + <color name="i_am_color_db0">#00000db0</color> + <color name="i_am_color_db1">#00000db1</color> + <color name="i_am_color_db2">#00000db2</color> + <color name="i_am_color_db3">#00000db3</color> + <color name="i_am_color_db4">#00000db4</color> + <color name="i_am_color_db5">#00000db5</color> + <color name="i_am_color_db6">#00000db6</color> + <color name="i_am_color_db7">#00000db7</color> + <color name="i_am_color_db8">#00000db8</color> + <color name="i_am_color_db9">#00000db9</color> + <color name="i_am_color_dba">#00000dba</color> + <color name="i_am_color_dbb">#00000dbb</color> + <color name="i_am_color_dbc">#00000dbc</color> + <color name="i_am_color_dbd">#00000dbd</color> + <color name="i_am_color_dbe">#00000dbe</color> + <color name="i_am_color_dbf">#00000dbf</color> + <color name="i_am_color_dc0">#00000dc0</color> + <color name="i_am_color_dc1">#00000dc1</color> + <color name="i_am_color_dc2">#00000dc2</color> + <color name="i_am_color_dc3">#00000dc3</color> + <color name="i_am_color_dc4">#00000dc4</color> + <color name="i_am_color_dc5">#00000dc5</color> + <color name="i_am_color_dc6">#00000dc6</color> + <color name="i_am_color_dc7">#00000dc7</color> + <color name="i_am_color_dc8">#00000dc8</color> + <color name="i_am_color_dc9">#00000dc9</color> + <color name="i_am_color_dca">#00000dca</color> + <color name="i_am_color_dcb">#00000dcb</color> + <color name="i_am_color_dcc">#00000dcc</color> + <color name="i_am_color_dcd">#00000dcd</color> + <color name="i_am_color_dce">#00000dce</color> + <color name="i_am_color_dcf">#00000dcf</color> + <color name="i_am_color_dd0">#00000dd0</color> + <color name="i_am_color_dd1">#00000dd1</color> + <color name="i_am_color_dd2">#00000dd2</color> + <color name="i_am_color_dd3">#00000dd3</color> + <color name="i_am_color_dd4">#00000dd4</color> + <color name="i_am_color_dd5">#00000dd5</color> + <color name="i_am_color_dd6">#00000dd6</color> + <color name="i_am_color_dd7">#00000dd7</color> + <color name="i_am_color_dd8">#00000dd8</color> + <color name="i_am_color_dd9">#00000dd9</color> + <color name="i_am_color_dda">#00000dda</color> + <color name="i_am_color_ddb">#00000ddb</color> + <color name="i_am_color_ddc">#00000ddc</color> + <color name="i_am_color_ddd">#00000ddd</color> + <color name="i_am_color_dde">#00000dde</color> + <color name="i_am_color_ddf">#00000ddf</color> + <color name="i_am_color_de0">#00000de0</color> + <color name="i_am_color_de1">#00000de1</color> + <color name="i_am_color_de2">#00000de2</color> + <color name="i_am_color_de3">#00000de3</color> + <color name="i_am_color_de4">#00000de4</color> + <color name="i_am_color_de5">#00000de5</color> + <color name="i_am_color_de6">#00000de6</color> + <color name="i_am_color_de7">#00000de7</color> + <color name="i_am_color_de8">#00000de8</color> + <color name="i_am_color_de9">#00000de9</color> + <color name="i_am_color_dea">#00000dea</color> + <color name="i_am_color_deb">#00000deb</color> + <color name="i_am_color_dec">#00000dec</color> + <color name="i_am_color_ded">#00000ded</color> + <color name="i_am_color_dee">#00000dee</color> + <color name="i_am_color_def">#00000def</color> + <color name="i_am_color_df0">#00000df0</color> + <color name="i_am_color_df1">#00000df1</color> + <color name="i_am_color_df2">#00000df2</color> + <color name="i_am_color_df3">#00000df3</color> + <color name="i_am_color_df4">#00000df4</color> + <color name="i_am_color_df5">#00000df5</color> + <color name="i_am_color_df6">#00000df6</color> + <color name="i_am_color_df7">#00000df7</color> + <color name="i_am_color_df8">#00000df8</color> + <color name="i_am_color_df9">#00000df9</color> + <color name="i_am_color_dfa">#00000dfa</color> + <color name="i_am_color_dfb">#00000dfb</color> + <color name="i_am_color_dfc">#00000dfc</color> + <color name="i_am_color_dfd">#00000dfd</color> + <color name="i_am_color_dfe">#00000dfe</color> + <color name="i_am_color_dff">#00000dff</color> + <color name="i_am_color_e00">#00000e00</color> + <color name="i_am_color_e01">#00000e01</color> + <color name="i_am_color_e02">#00000e02</color> + <color name="i_am_color_e03">#00000e03</color> + <color name="i_am_color_e04">#00000e04</color> + <color name="i_am_color_e05">#00000e05</color> + <color name="i_am_color_e06">#00000e06</color> + <color name="i_am_color_e07">#00000e07</color> + <color name="i_am_color_e08">#00000e08</color> + <color name="i_am_color_e09">#00000e09</color> + <color name="i_am_color_e0a">#00000e0a</color> + <color name="i_am_color_e0b">#00000e0b</color> + <color name="i_am_color_e0c">#00000e0c</color> + <color name="i_am_color_e0d">#00000e0d</color> + <color name="i_am_color_e0e">#00000e0e</color> + <color name="i_am_color_e0f">#00000e0f</color> + <color name="i_am_color_e10">#00000e10</color> + <color name="i_am_color_e11">#00000e11</color> + <color name="i_am_color_e12">#00000e12</color> + <color name="i_am_color_e13">#00000e13</color> + <color name="i_am_color_e14">#00000e14</color> + <color name="i_am_color_e15">#00000e15</color> + <color name="i_am_color_e16">#00000e16</color> + <color name="i_am_color_e17">#00000e17</color> + <color name="i_am_color_e18">#00000e18</color> + <color name="i_am_color_e19">#00000e19</color> + <color name="i_am_color_e1a">#00000e1a</color> + <color name="i_am_color_e1b">#00000e1b</color> + <color name="i_am_color_e1c">#00000e1c</color> + <color name="i_am_color_e1d">#00000e1d</color> + <color name="i_am_color_e1e">#00000e1e</color> + <color name="i_am_color_e1f">#00000e1f</color> + <color name="i_am_color_e20">#00000e20</color> + <color name="i_am_color_e21">#00000e21</color> + <color name="i_am_color_e22">#00000e22</color> + <color name="i_am_color_e23">#00000e23</color> + <color name="i_am_color_e24">#00000e24</color> + <color name="i_am_color_e25">#00000e25</color> + <color name="i_am_color_e26">#00000e26</color> + <color name="i_am_color_e27">#00000e27</color> + <color name="i_am_color_e28">#00000e28</color> + <color name="i_am_color_e29">#00000e29</color> + <color name="i_am_color_e2a">#00000e2a</color> + <color name="i_am_color_e2b">#00000e2b</color> + <color name="i_am_color_e2c">#00000e2c</color> + <color name="i_am_color_e2d">#00000e2d</color> + <color name="i_am_color_e2e">#00000e2e</color> + <color name="i_am_color_e2f">#00000e2f</color> + <color name="i_am_color_e30">#00000e30</color> + <color name="i_am_color_e31">#00000e31</color> + <color name="i_am_color_e32">#00000e32</color> + <color name="i_am_color_e33">#00000e33</color> + <color name="i_am_color_e34">#00000e34</color> + <color name="i_am_color_e35">#00000e35</color> + <color name="i_am_color_e36">#00000e36</color> + <color name="i_am_color_e37">#00000e37</color> + <color name="i_am_color_e38">#00000e38</color> + <color name="i_am_color_e39">#00000e39</color> + <color name="i_am_color_e3a">#00000e3a</color> + <color name="i_am_color_e3b">#00000e3b</color> + <color name="i_am_color_e3c">#00000e3c</color> + <color name="i_am_color_e3d">#00000e3d</color> + <color name="i_am_color_e3e">#00000e3e</color> + <color name="i_am_color_e3f">#00000e3f</color> + <color name="i_am_color_e40">#00000e40</color> + <color name="i_am_color_e41">#00000e41</color> + <color name="i_am_color_e42">#00000e42</color> + <color name="i_am_color_e43">#00000e43</color> + <color name="i_am_color_e44">#00000e44</color> + <color name="i_am_color_e45">#00000e45</color> + <color name="i_am_color_e46">#00000e46</color> + <color name="i_am_color_e47">#00000e47</color> + <color name="i_am_color_e48">#00000e48</color> + <color name="i_am_color_e49">#00000e49</color> + <color name="i_am_color_e4a">#00000e4a</color> + <color name="i_am_color_e4b">#00000e4b</color> + <color name="i_am_color_e4c">#00000e4c</color> + <color name="i_am_color_e4d">#00000e4d</color> + <color name="i_am_color_e4e">#00000e4e</color> + <color name="i_am_color_e4f">#00000e4f</color> + <color name="i_am_color_e50">#00000e50</color> + <color name="i_am_color_e51">#00000e51</color> + <color name="i_am_color_e52">#00000e52</color> + <color name="i_am_color_e53">#00000e53</color> + <color name="i_am_color_e54">#00000e54</color> + <color name="i_am_color_e55">#00000e55</color> + <color name="i_am_color_e56">#00000e56</color> + <color name="i_am_color_e57">#00000e57</color> + <color name="i_am_color_e58">#00000e58</color> + <color name="i_am_color_e59">#00000e59</color> + <color name="i_am_color_e5a">#00000e5a</color> + <color name="i_am_color_e5b">#00000e5b</color> + <color name="i_am_color_e5c">#00000e5c</color> + <color name="i_am_color_e5d">#00000e5d</color> + <color name="i_am_color_e5e">#00000e5e</color> + <color name="i_am_color_e5f">#00000e5f</color> + <color name="i_am_color_e60">#00000e60</color> + <color name="i_am_color_e61">#00000e61</color> + <color name="i_am_color_e62">#00000e62</color> + <color name="i_am_color_e63">#00000e63</color> + <color name="i_am_color_e64">#00000e64</color> + <color name="i_am_color_e65">#00000e65</color> + <color name="i_am_color_e66">#00000e66</color> + <color name="i_am_color_e67">#00000e67</color> + <color name="i_am_color_e68">#00000e68</color> + <color name="i_am_color_e69">#00000e69</color> + <color name="i_am_color_e6a">#00000e6a</color> + <color name="i_am_color_e6b">#00000e6b</color> + <color name="i_am_color_e6c">#00000e6c</color> + <color name="i_am_color_e6d">#00000e6d</color> + <color name="i_am_color_e6e">#00000e6e</color> + <color name="i_am_color_e6f">#00000e6f</color> + <color name="i_am_color_e70">#00000e70</color> + <color name="i_am_color_e71">#00000e71</color> + <color name="i_am_color_e72">#00000e72</color> + <color name="i_am_color_e73">#00000e73</color> + <color name="i_am_color_e74">#00000e74</color> + <color name="i_am_color_e75">#00000e75</color> + <color name="i_am_color_e76">#00000e76</color> + <color name="i_am_color_e77">#00000e77</color> + <color name="i_am_color_e78">#00000e78</color> + <color name="i_am_color_e79">#00000e79</color> + <color name="i_am_color_e7a">#00000e7a</color> + <color name="i_am_color_e7b">#00000e7b</color> + <color name="i_am_color_e7c">#00000e7c</color> + <color name="i_am_color_e7d">#00000e7d</color> + <color name="i_am_color_e7e">#00000e7e</color> + <color name="i_am_color_e7f">#00000e7f</color> + <color name="i_am_color_e80">#00000e80</color> + <color name="i_am_color_e81">#00000e81</color> + <color name="i_am_color_e82">#00000e82</color> + <color name="i_am_color_e83">#00000e83</color> + <color name="i_am_color_e84">#00000e84</color> + <color name="i_am_color_e85">#00000e85</color> + <color name="i_am_color_e86">#00000e86</color> + <color name="i_am_color_e87">#00000e87</color> + <color name="i_am_color_e88">#00000e88</color> + <color name="i_am_color_e89">#00000e89</color> + <color name="i_am_color_e8a">#00000e8a</color> + <color name="i_am_color_e8b">#00000e8b</color> + <color name="i_am_color_e8c">#00000e8c</color> + <color name="i_am_color_e8d">#00000e8d</color> + <color name="i_am_color_e8e">#00000e8e</color> + <color name="i_am_color_e8f">#00000e8f</color> + <color name="i_am_color_e90">#00000e90</color> + <color name="i_am_color_e91">#00000e91</color> + <color name="i_am_color_e92">#00000e92</color> + <color name="i_am_color_e93">#00000e93</color> + <color name="i_am_color_e94">#00000e94</color> + <color name="i_am_color_e95">#00000e95</color> + <color name="i_am_color_e96">#00000e96</color> + <color name="i_am_color_e97">#00000e97</color> + <color name="i_am_color_e98">#00000e98</color> + <color name="i_am_color_e99">#00000e99</color> + <color name="i_am_color_e9a">#00000e9a</color> + <color name="i_am_color_e9b">#00000e9b</color> + <color name="i_am_color_e9c">#00000e9c</color> + <color name="i_am_color_e9d">#00000e9d</color> + <color name="i_am_color_e9e">#00000e9e</color> + <color name="i_am_color_e9f">#00000e9f</color> + <color name="i_am_color_ea0">#00000ea0</color> + <color name="i_am_color_ea1">#00000ea1</color> + <color name="i_am_color_ea2">#00000ea2</color> + <color name="i_am_color_ea3">#00000ea3</color> + <color name="i_am_color_ea4">#00000ea4</color> + <color name="i_am_color_ea5">#00000ea5</color> + <color name="i_am_color_ea6">#00000ea6</color> + <color name="i_am_color_ea7">#00000ea7</color> + <color name="i_am_color_ea8">#00000ea8</color> + <color name="i_am_color_ea9">#00000ea9</color> + <color name="i_am_color_eaa">#00000eaa</color> + <color name="i_am_color_eab">#00000eab</color> + <color name="i_am_color_eac">#00000eac</color> + <color name="i_am_color_ead">#00000ead</color> + <color name="i_am_color_eae">#00000eae</color> + <color name="i_am_color_eaf">#00000eaf</color> + <color name="i_am_color_eb0">#00000eb0</color> + <color name="i_am_color_eb1">#00000eb1</color> + <color name="i_am_color_eb2">#00000eb2</color> + <color name="i_am_color_eb3">#00000eb3</color> + <color name="i_am_color_eb4">#00000eb4</color> + <color name="i_am_color_eb5">#00000eb5</color> + <color name="i_am_color_eb6">#00000eb6</color> + <color name="i_am_color_eb7">#00000eb7</color> + <color name="i_am_color_eb8">#00000eb8</color> + <color name="i_am_color_eb9">#00000eb9</color> + <color name="i_am_color_eba">#00000eba</color> + <color name="i_am_color_ebb">#00000ebb</color> + <color name="i_am_color_ebc">#00000ebc</color> + <color name="i_am_color_ebd">#00000ebd</color> + <color name="i_am_color_ebe">#00000ebe</color> + <color name="i_am_color_ebf">#00000ebf</color> + <color name="i_am_color_ec0">#00000ec0</color> + <color name="i_am_color_ec1">#00000ec1</color> + <color name="i_am_color_ec2">#00000ec2</color> + <color name="i_am_color_ec3">#00000ec3</color> + <color name="i_am_color_ec4">#00000ec4</color> + <color name="i_am_color_ec5">#00000ec5</color> + <color name="i_am_color_ec6">#00000ec6</color> + <color name="i_am_color_ec7">#00000ec7</color> + <color name="i_am_color_ec8">#00000ec8</color> + <color name="i_am_color_ec9">#00000ec9</color> + <color name="i_am_color_eca">#00000eca</color> + <color name="i_am_color_ecb">#00000ecb</color> + <color name="i_am_color_ecc">#00000ecc</color> + <color name="i_am_color_ecd">#00000ecd</color> + <color name="i_am_color_ece">#00000ece</color> + <color name="i_am_color_ecf">#00000ecf</color> + <color name="i_am_color_ed0">#00000ed0</color> + <color name="i_am_color_ed1">#00000ed1</color> + <color name="i_am_color_ed2">#00000ed2</color> + <color name="i_am_color_ed3">#00000ed3</color> + <color name="i_am_color_ed4">#00000ed4</color> + <color name="i_am_color_ed5">#00000ed5</color> + <color name="i_am_color_ed6">#00000ed6</color> + <color name="i_am_color_ed7">#00000ed7</color> + <color name="i_am_color_ed8">#00000ed8</color> + <color name="i_am_color_ed9">#00000ed9</color> + <color name="i_am_color_eda">#00000eda</color> + <color name="i_am_color_edb">#00000edb</color> + <color name="i_am_color_edc">#00000edc</color> + <color name="i_am_color_edd">#00000edd</color> + <color name="i_am_color_ede">#00000ede</color> + <color name="i_am_color_edf">#00000edf</color> + <color name="i_am_color_ee0">#00000ee0</color> + <color name="i_am_color_ee1">#00000ee1</color> + <color name="i_am_color_ee2">#00000ee2</color> + <color name="i_am_color_ee3">#00000ee3</color> + <color name="i_am_color_ee4">#00000ee4</color> + <color name="i_am_color_ee5">#00000ee5</color> + <color name="i_am_color_ee6">#00000ee6</color> + <color name="i_am_color_ee7">#00000ee7</color> + <color name="i_am_color_ee8">#00000ee8</color> + <color name="i_am_color_ee9">#00000ee9</color> + <color name="i_am_color_eea">#00000eea</color> + <color name="i_am_color_eeb">#00000eeb</color> + <color name="i_am_color_eec">#00000eec</color> + <color name="i_am_color_eed">#00000eed</color> + <color name="i_am_color_eee">#00000eee</color> + <color name="i_am_color_eef">#00000eef</color> + <color name="i_am_color_ef0">#00000ef0</color> + <color name="i_am_color_ef1">#00000ef1</color> + <color name="i_am_color_ef2">#00000ef2</color> + <color name="i_am_color_ef3">#00000ef3</color> + <color name="i_am_color_ef4">#00000ef4</color> + <color name="i_am_color_ef5">#00000ef5</color> + <color name="i_am_color_ef6">#00000ef6</color> + <color name="i_am_color_ef7">#00000ef7</color> + <color name="i_am_color_ef8">#00000ef8</color> + <color name="i_am_color_ef9">#00000ef9</color> + <color name="i_am_color_efa">#00000efa</color> + <color name="i_am_color_efb">#00000efb</color> + <color name="i_am_color_efc">#00000efc</color> + <color name="i_am_color_efd">#00000efd</color> + <color name="i_am_color_efe">#00000efe</color> + <color name="i_am_color_eff">#00000eff</color> + <color name="i_am_color_f00">#00000f00</color> + <color name="i_am_color_f01">#00000f01</color> + <color name="i_am_color_f02">#00000f02</color> + <color name="i_am_color_f03">#00000f03</color> + <color name="i_am_color_f04">#00000f04</color> + <color name="i_am_color_f05">#00000f05</color> + <color name="i_am_color_f06">#00000f06</color> + <color name="i_am_color_f07">#00000f07</color> + <color name="i_am_color_f08">#00000f08</color> + <color name="i_am_color_f09">#00000f09</color> + <color name="i_am_color_f0a">#00000f0a</color> + <color name="i_am_color_f0b">#00000f0b</color> + <color name="i_am_color_f0c">#00000f0c</color> + <color name="i_am_color_f0d">#00000f0d</color> + <color name="i_am_color_f0e">#00000f0e</color> + <color name="i_am_color_f0f">#00000f0f</color> + <color name="i_am_color_f10">#00000f10</color> + <color name="i_am_color_f11">#00000f11</color> + <color name="i_am_color_f12">#00000f12</color> + <color name="i_am_color_f13">#00000f13</color> + <color name="i_am_color_f14">#00000f14</color> + <color name="i_am_color_f15">#00000f15</color> + <color name="i_am_color_f16">#00000f16</color> + <color name="i_am_color_f17">#00000f17</color> + <color name="i_am_color_f18">#00000f18</color> + <color name="i_am_color_f19">#00000f19</color> + <color name="i_am_color_f1a">#00000f1a</color> + <color name="i_am_color_f1b">#00000f1b</color> + <color name="i_am_color_f1c">#00000f1c</color> + <color name="i_am_color_f1d">#00000f1d</color> + <color name="i_am_color_f1e">#00000f1e</color> + <color name="i_am_color_f1f">#00000f1f</color> + <color name="i_am_color_f20">#00000f20</color> + <color name="i_am_color_f21">#00000f21</color> + <color name="i_am_color_f22">#00000f22</color> + <color name="i_am_color_f23">#00000f23</color> + <color name="i_am_color_f24">#00000f24</color> + <color name="i_am_color_f25">#00000f25</color> + <color name="i_am_color_f26">#00000f26</color> + <color name="i_am_color_f27">#00000f27</color> + <color name="i_am_color_f28">#00000f28</color> + <color name="i_am_color_f29">#00000f29</color> + <color name="i_am_color_f2a">#00000f2a</color> + <color name="i_am_color_f2b">#00000f2b</color> + <color name="i_am_color_f2c">#00000f2c</color> + <color name="i_am_color_f2d">#00000f2d</color> + <color name="i_am_color_f2e">#00000f2e</color> + <color name="i_am_color_f2f">#00000f2f</color> + <color name="i_am_color_f30">#00000f30</color> + <color name="i_am_color_f31">#00000f31</color> + <color name="i_am_color_f32">#00000f32</color> + <color name="i_am_color_f33">#00000f33</color> + <color name="i_am_color_f34">#00000f34</color> + <color name="i_am_color_f35">#00000f35</color> + <color name="i_am_color_f36">#00000f36</color> + <color name="i_am_color_f37">#00000f37</color> + <color name="i_am_color_f38">#00000f38</color> + <color name="i_am_color_f39">#00000f39</color> + <color name="i_am_color_f3a">#00000f3a</color> + <color name="i_am_color_f3b">#00000f3b</color> + <color name="i_am_color_f3c">#00000f3c</color> + <color name="i_am_color_f3d">#00000f3d</color> + <color name="i_am_color_f3e">#00000f3e</color> + <color name="i_am_color_f3f">#00000f3f</color> + <color name="i_am_color_f40">#00000f40</color> + <color name="i_am_color_f41">#00000f41</color> + <color name="i_am_color_f42">#00000f42</color> + <color name="i_am_color_f43">#00000f43</color> + <color name="i_am_color_f44">#00000f44</color> + <color name="i_am_color_f45">#00000f45</color> + <color name="i_am_color_f46">#00000f46</color> + <color name="i_am_color_f47">#00000f47</color> + <color name="i_am_color_f48">#00000f48</color> + <color name="i_am_color_f49">#00000f49</color> + <color name="i_am_color_f4a">#00000f4a</color> + <color name="i_am_color_f4b">#00000f4b</color> + <color name="i_am_color_f4c">#00000f4c</color> + <color name="i_am_color_f4d">#00000f4d</color> + <color name="i_am_color_f4e">#00000f4e</color> + <color name="i_am_color_f4f">#00000f4f</color> + <color name="i_am_color_f50">#00000f50</color> + <color name="i_am_color_f51">#00000f51</color> + <color name="i_am_color_f52">#00000f52</color> + <color name="i_am_color_f53">#00000f53</color> + <color name="i_am_color_f54">#00000f54</color> + <color name="i_am_color_f55">#00000f55</color> + <color name="i_am_color_f56">#00000f56</color> + <color name="i_am_color_f57">#00000f57</color> + <color name="i_am_color_f58">#00000f58</color> + <color name="i_am_color_f59">#00000f59</color> + <color name="i_am_color_f5a">#00000f5a</color> + <color name="i_am_color_f5b">#00000f5b</color> + <color name="i_am_color_f5c">#00000f5c</color> + <color name="i_am_color_f5d">#00000f5d</color> + <color name="i_am_color_f5e">#00000f5e</color> + <color name="i_am_color_f5f">#00000f5f</color> + <color name="i_am_color_f60">#00000f60</color> + <color name="i_am_color_f61">#00000f61</color> + <color name="i_am_color_f62">#00000f62</color> + <color name="i_am_color_f63">#00000f63</color> + <color name="i_am_color_f64">#00000f64</color> + <color name="i_am_color_f65">#00000f65</color> + <color name="i_am_color_f66">#00000f66</color> + <color name="i_am_color_f67">#00000f67</color> + <color name="i_am_color_f68">#00000f68</color> + <color name="i_am_color_f69">#00000f69</color> + <color name="i_am_color_f6a">#00000f6a</color> + <color name="i_am_color_f6b">#00000f6b</color> + <color name="i_am_color_f6c">#00000f6c</color> + <color name="i_am_color_f6d">#00000f6d</color> + <color name="i_am_color_f6e">#00000f6e</color> + <color name="i_am_color_f6f">#00000f6f</color> + <color name="i_am_color_f70">#00000f70</color> + <color name="i_am_color_f71">#00000f71</color> + <color name="i_am_color_f72">#00000f72</color> + <color name="i_am_color_f73">#00000f73</color> + <color name="i_am_color_f74">#00000f74</color> + <color name="i_am_color_f75">#00000f75</color> + <color name="i_am_color_f76">#00000f76</color> + <color name="i_am_color_f77">#00000f77</color> + <color name="i_am_color_f78">#00000f78</color> + <color name="i_am_color_f79">#00000f79</color> + <color name="i_am_color_f7a">#00000f7a</color> + <color name="i_am_color_f7b">#00000f7b</color> + <color name="i_am_color_f7c">#00000f7c</color> + <color name="i_am_color_f7d">#00000f7d</color> + <color name="i_am_color_f7e">#00000f7e</color> + <color name="i_am_color_f7f">#00000f7f</color> + <color name="i_am_color_f80">#00000f80</color> + <color name="i_am_color_f81">#00000f81</color> + <color name="i_am_color_f82">#00000f82</color> + <color name="i_am_color_f83">#00000f83</color> + <color name="i_am_color_f84">#00000f84</color> + <color name="i_am_color_f85">#00000f85</color> + <color name="i_am_color_f86">#00000f86</color> + <color name="i_am_color_f87">#00000f87</color> + <color name="i_am_color_f88">#00000f88</color> + <color name="i_am_color_f89">#00000f89</color> + <color name="i_am_color_f8a">#00000f8a</color> + <color name="i_am_color_f8b">#00000f8b</color> + <color name="i_am_color_f8c">#00000f8c</color> + <color name="i_am_color_f8d">#00000f8d</color> + <color name="i_am_color_f8e">#00000f8e</color> + <color name="i_am_color_f8f">#00000f8f</color> + <color name="i_am_color_f90">#00000f90</color> + <color name="i_am_color_f91">#00000f91</color> + <color name="i_am_color_f92">#00000f92</color> + <color name="i_am_color_f93">#00000f93</color> + <color name="i_am_color_f94">#00000f94</color> + <color name="i_am_color_f95">#00000f95</color> + <color name="i_am_color_f96">#00000f96</color> + <color name="i_am_color_f97">#00000f97</color> + <color name="i_am_color_f98">#00000f98</color> + <color name="i_am_color_f99">#00000f99</color> + <color name="i_am_color_f9a">#00000f9a</color> + <color name="i_am_color_f9b">#00000f9b</color> + <color name="i_am_color_f9c">#00000f9c</color> + <color name="i_am_color_f9d">#00000f9d</color> + <color name="i_am_color_f9e">#00000f9e</color> + <color name="i_am_color_f9f">#00000f9f</color> + <color name="i_am_color_fa0">#00000fa0</color> + <color name="i_am_color_fa1">#00000fa1</color> + <color name="i_am_color_fa2">#00000fa2</color> + <color name="i_am_color_fa3">#00000fa3</color> + <color name="i_am_color_fa4">#00000fa4</color> + <color name="i_am_color_fa5">#00000fa5</color> + <color name="i_am_color_fa6">#00000fa6</color> + <color name="i_am_color_fa7">#00000fa7</color> + <color name="i_am_color_fa8">#00000fa8</color> + <color name="i_am_color_fa9">#00000fa9</color> + <color name="i_am_color_faa">#00000faa</color> + <color name="i_am_color_fab">#00000fab</color> + <color name="i_am_color_fac">#00000fac</color> + <color name="i_am_color_fad">#00000fad</color> + <color name="i_am_color_fae">#00000fae</color> + <color name="i_am_color_faf">#00000faf</color> + <color name="i_am_color_fb0">#00000fb0</color> + <color name="i_am_color_fb1">#00000fb1</color> + <color name="i_am_color_fb2">#00000fb2</color> + <color name="i_am_color_fb3">#00000fb3</color> + <color name="i_am_color_fb4">#00000fb4</color> + <color name="i_am_color_fb5">#00000fb5</color> + <color name="i_am_color_fb6">#00000fb6</color> + <color name="i_am_color_fb7">#00000fb7</color> + <color name="i_am_color_fb8">#00000fb8</color> + <color name="i_am_color_fb9">#00000fb9</color> + <color name="i_am_color_fba">#00000fba</color> + <color name="i_am_color_fbb">#00000fbb</color> + <color name="i_am_color_fbc">#00000fbc</color> + <color name="i_am_color_fbd">#00000fbd</color> + <color name="i_am_color_fbe">#00000fbe</color> + <color name="i_am_color_fbf">#00000fbf</color> + <color name="i_am_color_fc0">#00000fc0</color> + <color name="i_am_color_fc1">#00000fc1</color> + <color name="i_am_color_fc2">#00000fc2</color> + <color name="i_am_color_fc3">#00000fc3</color> + <color name="i_am_color_fc4">#00000fc4</color> + <color name="i_am_color_fc5">#00000fc5</color> + <color name="i_am_color_fc6">#00000fc6</color> + <color name="i_am_color_fc7">#00000fc7</color> + <color name="i_am_color_fc8">#00000fc8</color> + <color name="i_am_color_fc9">#00000fc9</color> + <color name="i_am_color_fca">#00000fca</color> + <color name="i_am_color_fcb">#00000fcb</color> + <color name="i_am_color_fcc">#00000fcc</color> + <color name="i_am_color_fcd">#00000fcd</color> + <color name="i_am_color_fce">#00000fce</color> + <color name="i_am_color_fcf">#00000fcf</color> + <color name="i_am_color_fd0">#00000fd0</color> + <color name="i_am_color_fd1">#00000fd1</color> + <color name="i_am_color_fd2">#00000fd2</color> + <color name="i_am_color_fd3">#00000fd3</color> + <color name="i_am_color_fd4">#00000fd4</color> + <color name="i_am_color_fd5">#00000fd5</color> + <color name="i_am_color_fd6">#00000fd6</color> + <color name="i_am_color_fd7">#00000fd7</color> + <color name="i_am_color_fd8">#00000fd8</color> + <color name="i_am_color_fd9">#00000fd9</color> + <color name="i_am_color_fda">#00000fda</color> + <color name="i_am_color_fdb">#00000fdb</color> + <color name="i_am_color_fdc">#00000fdc</color> + <color name="i_am_color_fdd">#00000fdd</color> + <color name="i_am_color_fde">#00000fde</color> + <color name="i_am_color_fdf">#00000fdf</color> + <color name="i_am_color_fe0">#00000fe0</color> + <color name="i_am_color_fe1">#00000fe1</color> + <color name="i_am_color_fe2">#00000fe2</color> + <color name="i_am_color_fe3">#00000fe3</color> + <color name="i_am_color_fe4">#00000fe4</color> + <color name="i_am_color_fe5">#00000fe5</color> + <color name="i_am_color_fe6">#00000fe6</color> + <color name="i_am_color_fe7">#00000fe7</color> + <color name="i_am_color_fe8">#00000fe8</color> + <color name="i_am_color_fe9">#00000fe9</color> + <color name="i_am_color_fea">#00000fea</color> + <color name="i_am_color_feb">#00000feb</color> + <color name="i_am_color_fec">#00000fec</color> + <color name="i_am_color_fed">#00000fed</color> + <color name="i_am_color_fee">#00000fee</color> + <color name="i_am_color_fef">#00000fef</color> + <color name="i_am_color_ff0">#00000ff0</color> + <color name="i_am_color_ff1">#00000ff1</color> + <color name="i_am_color_ff2">#00000ff2</color> + <color name="i_am_color_ff3">#00000ff3</color> + <color name="i_am_color_ff4">#00000ff4</color> + <color name="i_am_color_ff5">#00000ff5</color> + <color name="i_am_color_ff6">#00000ff6</color> + <color name="i_am_color_ff7">#00000ff7</color> + <color name="i_am_color_ff8">#00000ff8</color> + <color name="i_am_color_ff9">#00000ff9</color> + <color name="i_am_color_ffa">#00000ffa</color> + <color name="i_am_color_ffb">#00000ffb</color> + <color name="i_am_color_ffc">#00000ffc</color> + <color name="i_am_color_ffd">#00000ffd</color> + <color name="i_am_color_ffe">#00000ffe</color> + <color name="i_am_color_fff">#00000fff</color> + <color name="i_am_color_1000">#00001000</color> + <color name="i_am_color_1001">#00001001</color> + <color name="i_am_color_1002">#00001002</color> + <color name="i_am_color_1003">#00001003</color> + <color name="i_am_color_1004">#00001004</color> + <color name="i_am_color_1005">#00001005</color> + <color name="i_am_color_1006">#00001006</color> + <color name="i_am_color_1007">#00001007</color> + <color name="i_am_color_1008">#00001008</color> + <color name="i_am_color_1009">#00001009</color> + <color name="i_am_color_100a">#0000100a</color> + <color name="i_am_color_100b">#0000100b</color> + <color name="i_am_color_100c">#0000100c</color> + <color name="i_am_color_100d">#0000100d</color> + <color name="i_am_color_100e">#0000100e</color> + <color name="i_am_color_100f">#0000100f</color> + <color name="i_am_color_1010">#00001010</color> + <color name="i_am_color_1011">#00001011</color> + <color name="i_am_color_1012">#00001012</color> + <color name="i_am_color_1013">#00001013</color> + <color name="i_am_color_1014">#00001014</color> + <color name="i_am_color_1015">#00001015</color> + <color name="i_am_color_1016">#00001016</color> + <color name="i_am_color_1017">#00001017</color> + <color name="i_am_color_1018">#00001018</color> + <color name="i_am_color_1019">#00001019</color> + <color name="i_am_color_101a">#0000101a</color> + <color name="i_am_color_101b">#0000101b</color> + <color name="i_am_color_101c">#0000101c</color> + <color name="i_am_color_101d">#0000101d</color> + <color name="i_am_color_101e">#0000101e</color> + <color name="i_am_color_101f">#0000101f</color> + <color name="i_am_color_1020">#00001020</color> + <color name="i_am_color_1021">#00001021</color> + <color name="i_am_color_1022">#00001022</color> + <color name="i_am_color_1023">#00001023</color> + <color name="i_am_color_1024">#00001024</color> + <color name="i_am_color_1025">#00001025</color> + <color name="i_am_color_1026">#00001026</color> + <color name="i_am_color_1027">#00001027</color> + <color name="i_am_color_1028">#00001028</color> + <color name="i_am_color_1029">#00001029</color> + <color name="i_am_color_102a">#0000102a</color> + <color name="i_am_color_102b">#0000102b</color> + <color name="i_am_color_102c">#0000102c</color> + <color name="i_am_color_102d">#0000102d</color> + <color name="i_am_color_102e">#0000102e</color> + <color name="i_am_color_102f">#0000102f</color> + <color name="i_am_color_1030">#00001030</color> + <color name="i_am_color_1031">#00001031</color> + <color name="i_am_color_1032">#00001032</color> + <color name="i_am_color_1033">#00001033</color> + <color name="i_am_color_1034">#00001034</color> + <color name="i_am_color_1035">#00001035</color> + <color name="i_am_color_1036">#00001036</color> + <color name="i_am_color_1037">#00001037</color> + <color name="i_am_color_1038">#00001038</color> + <color name="i_am_color_1039">#00001039</color> + <color name="i_am_color_103a">#0000103a</color> + <color name="i_am_color_103b">#0000103b</color> + <color name="i_am_color_103c">#0000103c</color> + <color name="i_am_color_103d">#0000103d</color> + <color name="i_am_color_103e">#0000103e</color> + <color name="i_am_color_103f">#0000103f</color> + <color name="i_am_color_1040">#00001040</color> + <color name="i_am_color_1041">#00001041</color> + <color name="i_am_color_1042">#00001042</color> + <color name="i_am_color_1043">#00001043</color> + <color name="i_am_color_1044">#00001044</color> + <color name="i_am_color_1045">#00001045</color> + <color name="i_am_color_1046">#00001046</color> + <color name="i_am_color_1047">#00001047</color> + <color name="i_am_color_1048">#00001048</color> + <color name="i_am_color_1049">#00001049</color> + <color name="i_am_color_104a">#0000104a</color> + <color name="i_am_color_104b">#0000104b</color> + <color name="i_am_color_104c">#0000104c</color> + <color name="i_am_color_104d">#0000104d</color> + <color name="i_am_color_104e">#0000104e</color> + <color name="i_am_color_104f">#0000104f</color> + <color name="i_am_color_1050">#00001050</color> + <color name="i_am_color_1051">#00001051</color> + <color name="i_am_color_1052">#00001052</color> + <color name="i_am_color_1053">#00001053</color> + <color name="i_am_color_1054">#00001054</color> + <color name="i_am_color_1055">#00001055</color> + <color name="i_am_color_1056">#00001056</color> + <color name="i_am_color_1057">#00001057</color> + <color name="i_am_color_1058">#00001058</color> + <color name="i_am_color_1059">#00001059</color> + <color name="i_am_color_105a">#0000105a</color> + <color name="i_am_color_105b">#0000105b</color> + <color name="i_am_color_105c">#0000105c</color> + <color name="i_am_color_105d">#0000105d</color> + <color name="i_am_color_105e">#0000105e</color> + <color name="i_am_color_105f">#0000105f</color> + <color name="i_am_color_1060">#00001060</color> + <color name="i_am_color_1061">#00001061</color> + <color name="i_am_color_1062">#00001062</color> + <color name="i_am_color_1063">#00001063</color> + <color name="i_am_color_1064">#00001064</color> + <color name="i_am_color_1065">#00001065</color> + <color name="i_am_color_1066">#00001066</color> + <color name="i_am_color_1067">#00001067</color> + <color name="i_am_color_1068">#00001068</color> + <color name="i_am_color_1069">#00001069</color> + <color name="i_am_color_106a">#0000106a</color> + <color name="i_am_color_106b">#0000106b</color> + <color name="i_am_color_106c">#0000106c</color> + <color name="i_am_color_106d">#0000106d</color> + <color name="i_am_color_106e">#0000106e</color> + <color name="i_am_color_106f">#0000106f</color> + <color name="i_am_color_1070">#00001070</color> + <color name="i_am_color_1071">#00001071</color> + <color name="i_am_color_1072">#00001072</color> + <color name="i_am_color_1073">#00001073</color> + <color name="i_am_color_1074">#00001074</color> + <color name="i_am_color_1075">#00001075</color> + <color name="i_am_color_1076">#00001076</color> + <color name="i_am_color_1077">#00001077</color> + <color name="i_am_color_1078">#00001078</color> + <color name="i_am_color_1079">#00001079</color> + <color name="i_am_color_107a">#0000107a</color> + <color name="i_am_color_107b">#0000107b</color> + <color name="i_am_color_107c">#0000107c</color> + <color name="i_am_color_107d">#0000107d</color> + <color name="i_am_color_107e">#0000107e</color> + <color name="i_am_color_107f">#0000107f</color> + <color name="i_am_color_1080">#00001080</color> + <color name="i_am_color_1081">#00001081</color> + <color name="i_am_color_1082">#00001082</color> + <color name="i_am_color_1083">#00001083</color> + <color name="i_am_color_1084">#00001084</color> + <color name="i_am_color_1085">#00001085</color> + <color name="i_am_color_1086">#00001086</color> + <color name="i_am_color_1087">#00001087</color> + <color name="i_am_color_1088">#00001088</color> + <color name="i_am_color_1089">#00001089</color> + <color name="i_am_color_108a">#0000108a</color> + <color name="i_am_color_108b">#0000108b</color> + <color name="i_am_color_108c">#0000108c</color> + <color name="i_am_color_108d">#0000108d</color> + <color name="i_am_color_108e">#0000108e</color> + <color name="i_am_color_108f">#0000108f</color> + <color name="i_am_color_1090">#00001090</color> + <color name="i_am_color_1091">#00001091</color> + <color name="i_am_color_1092">#00001092</color> + <color name="i_am_color_1093">#00001093</color> + <color name="i_am_color_1094">#00001094</color> + <color name="i_am_color_1095">#00001095</color> + <color name="i_am_color_1096">#00001096</color> + <color name="i_am_color_1097">#00001097</color> + <color name="i_am_color_1098">#00001098</color> + <color name="i_am_color_1099">#00001099</color> + <color name="i_am_color_109a">#0000109a</color> + <color name="i_am_color_109b">#0000109b</color> + <color name="i_am_color_109c">#0000109c</color> + <color name="i_am_color_109d">#0000109d</color> + <color name="i_am_color_109e">#0000109e</color> + <color name="i_am_color_109f">#0000109f</color> + <color name="i_am_color_10a0">#000010a0</color> + <color name="i_am_color_10a1">#000010a1</color> + <color name="i_am_color_10a2">#000010a2</color> + <color name="i_am_color_10a3">#000010a3</color> + <color name="i_am_color_10a4">#000010a4</color> + <color name="i_am_color_10a5">#000010a5</color> + <color name="i_am_color_10a6">#000010a6</color> + <color name="i_am_color_10a7">#000010a7</color> + <color name="i_am_color_10a8">#000010a8</color> + <color name="i_am_color_10a9">#000010a9</color> + <color name="i_am_color_10aa">#000010aa</color> + <color name="i_am_color_10ab">#000010ab</color> + <color name="i_am_color_10ac">#000010ac</color> + <color name="i_am_color_10ad">#000010ad</color> + <color name="i_am_color_10ae">#000010ae</color> + <color name="i_am_color_10af">#000010af</color> + <color name="i_am_color_10b0">#000010b0</color> + <color name="i_am_color_10b1">#000010b1</color> + <color name="i_am_color_10b2">#000010b2</color> + <color name="i_am_color_10b3">#000010b3</color> + <color name="i_am_color_10b4">#000010b4</color> + <color name="i_am_color_10b5">#000010b5</color> + <color name="i_am_color_10b6">#000010b6</color> + <color name="i_am_color_10b7">#000010b7</color> + <color name="i_am_color_10b8">#000010b8</color> + <color name="i_am_color_10b9">#000010b9</color> + <color name="i_am_color_10ba">#000010ba</color> + <color name="i_am_color_10bb">#000010bb</color> + <color name="i_am_color_10bc">#000010bc</color> + <color name="i_am_color_10bd">#000010bd</color> + <color name="i_am_color_10be">#000010be</color> + <color name="i_am_color_10bf">#000010bf</color> + <color name="i_am_color_10c0">#000010c0</color> + <color name="i_am_color_10c1">#000010c1</color> + <color name="i_am_color_10c2">#000010c2</color> + <color name="i_am_color_10c3">#000010c3</color> + <color name="i_am_color_10c4">#000010c4</color> + <color name="i_am_color_10c5">#000010c5</color> + <color name="i_am_color_10c6">#000010c6</color> + <color name="i_am_color_10c7">#000010c7</color> + <color name="i_am_color_10c8">#000010c8</color> + <color name="i_am_color_10c9">#000010c9</color> + <color name="i_am_color_10ca">#000010ca</color> + <color name="i_am_color_10cb">#000010cb</color> + <color name="i_am_color_10cc">#000010cc</color> + <color name="i_am_color_10cd">#000010cd</color> + <color name="i_am_color_10ce">#000010ce</color> + <color name="i_am_color_10cf">#000010cf</color> + <color name="i_am_color_10d0">#000010d0</color> + <color name="i_am_color_10d1">#000010d1</color> + <color name="i_am_color_10d2">#000010d2</color> + <color name="i_am_color_10d3">#000010d3</color> + <color name="i_am_color_10d4">#000010d4</color> + <color name="i_am_color_10d5">#000010d5</color> + <color name="i_am_color_10d6">#000010d6</color> + <color name="i_am_color_10d7">#000010d7</color> + <color name="i_am_color_10d8">#000010d8</color> + <color name="i_am_color_10d9">#000010d9</color> + <color name="i_am_color_10da">#000010da</color> + <color name="i_am_color_10db">#000010db</color> + <color name="i_am_color_10dc">#000010dc</color> + <color name="i_am_color_10dd">#000010dd</color> + <color name="i_am_color_10de">#000010de</color> + <color name="i_am_color_10df">#000010df</color> + <color name="i_am_color_10e0">#000010e0</color> + <color name="i_am_color_10e1">#000010e1</color> + <color name="i_am_color_10e2">#000010e2</color> + <color name="i_am_color_10e3">#000010e3</color> + <color name="i_am_color_10e4">#000010e4</color> + <color name="i_am_color_10e5">#000010e5</color> + <color name="i_am_color_10e6">#000010e6</color> + <color name="i_am_color_10e7">#000010e7</color> + <color name="i_am_color_10e8">#000010e8</color> + <color name="i_am_color_10e9">#000010e9</color> + <color name="i_am_color_10ea">#000010ea</color> + <color name="i_am_color_10eb">#000010eb</color> + <color name="i_am_color_10ec">#000010ec</color> + <color name="i_am_color_10ed">#000010ed</color> + <color name="i_am_color_10ee">#000010ee</color> + <color name="i_am_color_10ef">#000010ef</color> + <color name="i_am_color_10f0">#000010f0</color> + <color name="i_am_color_10f1">#000010f1</color> + <color name="i_am_color_10f2">#000010f2</color> + <color name="i_am_color_10f3">#000010f3</color> + <color name="i_am_color_10f4">#000010f4</color> + <color name="i_am_color_10f5">#000010f5</color> + <color name="i_am_color_10f6">#000010f6</color> + <color name="i_am_color_10f7">#000010f7</color> + <color name="i_am_color_10f8">#000010f8</color> + <color name="i_am_color_10f9">#000010f9</color> + <color name="i_am_color_10fa">#000010fa</color> + <color name="i_am_color_10fb">#000010fb</color> + <color name="i_am_color_10fc">#000010fc</color> + <color name="i_am_color_10fd">#000010fd</color> + <color name="i_am_color_10fe">#000010fe</color> + <color name="i_am_color_10ff">#000010ff</color> + <color name="i_am_color_1100">#00001100</color> + <color name="i_am_color_1101">#00001101</color> + <color name="i_am_color_1102">#00001102</color> + <color name="i_am_color_1103">#00001103</color> + <color name="i_am_color_1104">#00001104</color> + <color name="i_am_color_1105">#00001105</color> + <color name="i_am_color_1106">#00001106</color> + <color name="i_am_color_1107">#00001107</color> + <color name="i_am_color_1108">#00001108</color> + <color name="i_am_color_1109">#00001109</color> + <color name="i_am_color_110a">#0000110a</color> + <color name="i_am_color_110b">#0000110b</color> + <color name="i_am_color_110c">#0000110c</color> + <color name="i_am_color_110d">#0000110d</color> + <color name="i_am_color_110e">#0000110e</color> + <color name="i_am_color_110f">#0000110f</color> + <color name="i_am_color_1110">#00001110</color> + <color name="i_am_color_1111">#00001111</color> + <color name="i_am_color_1112">#00001112</color> + <color name="i_am_color_1113">#00001113</color> + <color name="i_am_color_1114">#00001114</color> + <color name="i_am_color_1115">#00001115</color> + <color name="i_am_color_1116">#00001116</color> + <color name="i_am_color_1117">#00001117</color> + <color name="i_am_color_1118">#00001118</color> + <color name="i_am_color_1119">#00001119</color> + <color name="i_am_color_111a">#0000111a</color> + <color name="i_am_color_111b">#0000111b</color> + <color name="i_am_color_111c">#0000111c</color> + <color name="i_am_color_111d">#0000111d</color> + <color name="i_am_color_111e">#0000111e</color> + <color name="i_am_color_111f">#0000111f</color> + <color name="i_am_color_1120">#00001120</color> + <color name="i_am_color_1121">#00001121</color> + <color name="i_am_color_1122">#00001122</color> + <color name="i_am_color_1123">#00001123</color> + <color name="i_am_color_1124">#00001124</color> + <color name="i_am_color_1125">#00001125</color> + <color name="i_am_color_1126">#00001126</color> + <color name="i_am_color_1127">#00001127</color> + <color name="i_am_color_1128">#00001128</color> + <color name="i_am_color_1129">#00001129</color> + <color name="i_am_color_112a">#0000112a</color> + <color name="i_am_color_112b">#0000112b</color> + <color name="i_am_color_112c">#0000112c</color> + <color name="i_am_color_112d">#0000112d</color> + <color name="i_am_color_112e">#0000112e</color> + <color name="i_am_color_112f">#0000112f</color> + <color name="i_am_color_1130">#00001130</color> + <color name="i_am_color_1131">#00001131</color> + <color name="i_am_color_1132">#00001132</color> + <color name="i_am_color_1133">#00001133</color> + <color name="i_am_color_1134">#00001134</color> + <color name="i_am_color_1135">#00001135</color> + <color name="i_am_color_1136">#00001136</color> + <color name="i_am_color_1137">#00001137</color> + <color name="i_am_color_1138">#00001138</color> + <color name="i_am_color_1139">#00001139</color> + <color name="i_am_color_113a">#0000113a</color> + <color name="i_am_color_113b">#0000113b</color> + <color name="i_am_color_113c">#0000113c</color> + <color name="i_am_color_113d">#0000113d</color> + <color name="i_am_color_113e">#0000113e</color> + <color name="i_am_color_113f">#0000113f</color> + <color name="i_am_color_1140">#00001140</color> + <color name="i_am_color_1141">#00001141</color> + <color name="i_am_color_1142">#00001142</color> + <color name="i_am_color_1143">#00001143</color> + <color name="i_am_color_1144">#00001144</color> + <color name="i_am_color_1145">#00001145</color> + <color name="i_am_color_1146">#00001146</color> + <color name="i_am_color_1147">#00001147</color> + <color name="i_am_color_1148">#00001148</color> + <color name="i_am_color_1149">#00001149</color> + <color name="i_am_color_114a">#0000114a</color> + <color name="i_am_color_114b">#0000114b</color> + <color name="i_am_color_114c">#0000114c</color> + <color name="i_am_color_114d">#0000114d</color> + <color name="i_am_color_114e">#0000114e</color> + <color name="i_am_color_114f">#0000114f</color> + <color name="i_am_color_1150">#00001150</color> + <color name="i_am_color_1151">#00001151</color> + <color name="i_am_color_1152">#00001152</color> + <color name="i_am_color_1153">#00001153</color> + <color name="i_am_color_1154">#00001154</color> + <color name="i_am_color_1155">#00001155</color> + <color name="i_am_color_1156">#00001156</color> + <color name="i_am_color_1157">#00001157</color> + <color name="i_am_color_1158">#00001158</color> + <color name="i_am_color_1159">#00001159</color> + <color name="i_am_color_115a">#0000115a</color> + <color name="i_am_color_115b">#0000115b</color> + <color name="i_am_color_115c">#0000115c</color> + <color name="i_am_color_115d">#0000115d</color> + <color name="i_am_color_115e">#0000115e</color> + <color name="i_am_color_115f">#0000115f</color> + <color name="i_am_color_1160">#00001160</color> + <color name="i_am_color_1161">#00001161</color> + <color name="i_am_color_1162">#00001162</color> + <color name="i_am_color_1163">#00001163</color> + <color name="i_am_color_1164">#00001164</color> + <color name="i_am_color_1165">#00001165</color> + <color name="i_am_color_1166">#00001166</color> + <color name="i_am_color_1167">#00001167</color> + <color name="i_am_color_1168">#00001168</color> + <color name="i_am_color_1169">#00001169</color> + <color name="i_am_color_116a">#0000116a</color> + <color name="i_am_color_116b">#0000116b</color> + <color name="i_am_color_116c">#0000116c</color> + <color name="i_am_color_116d">#0000116d</color> + <color name="i_am_color_116e">#0000116e</color> + <color name="i_am_color_116f">#0000116f</color> + <color name="i_am_color_1170">#00001170</color> + <color name="i_am_color_1171">#00001171</color> + <color name="i_am_color_1172">#00001172</color> + <color name="i_am_color_1173">#00001173</color> + <color name="i_am_color_1174">#00001174</color> + <color name="i_am_color_1175">#00001175</color> + <color name="i_am_color_1176">#00001176</color> + <color name="i_am_color_1177">#00001177</color> + <color name="i_am_color_1178">#00001178</color> + <color name="i_am_color_1179">#00001179</color> + <color name="i_am_color_117a">#0000117a</color> + <color name="i_am_color_117b">#0000117b</color> + <color name="i_am_color_117c">#0000117c</color> + <color name="i_am_color_117d">#0000117d</color> + <color name="i_am_color_117e">#0000117e</color> + <color name="i_am_color_117f">#0000117f</color> + <color name="i_am_color_1180">#00001180</color> + <color name="i_am_color_1181">#00001181</color> + <color name="i_am_color_1182">#00001182</color> + <color name="i_am_color_1183">#00001183</color> + <color name="i_am_color_1184">#00001184</color> + <color name="i_am_color_1185">#00001185</color> + <color name="i_am_color_1186">#00001186</color> + <color name="i_am_color_1187">#00001187</color> + <color name="i_am_color_1188">#00001188</color> + <color name="i_am_color_1189">#00001189</color> + <color name="i_am_color_118a">#0000118a</color> + <color name="i_am_color_118b">#0000118b</color> + <color name="i_am_color_118c">#0000118c</color> + <color name="i_am_color_118d">#0000118d</color> + <color name="i_am_color_118e">#0000118e</color> + <color name="i_am_color_118f">#0000118f</color> + <color name="i_am_color_1190">#00001190</color> + <color name="i_am_color_1191">#00001191</color> + <color name="i_am_color_1192">#00001192</color> + <color name="i_am_color_1193">#00001193</color> + <color name="i_am_color_1194">#00001194</color> + <color name="i_am_color_1195">#00001195</color> + <color name="i_am_color_1196">#00001196</color> + <color name="i_am_color_1197">#00001197</color> + <color name="i_am_color_1198">#00001198</color> + <color name="i_am_color_1199">#00001199</color> + <color name="i_am_color_119a">#0000119a</color> + <color name="i_am_color_119b">#0000119b</color> + <color name="i_am_color_119c">#0000119c</color> + <color name="i_am_color_119d">#0000119d</color> + <color name="i_am_color_119e">#0000119e</color> + <color name="i_am_color_119f">#0000119f</color> + <color name="i_am_color_11a0">#000011a0</color> + <color name="i_am_color_11a1">#000011a1</color> + <color name="i_am_color_11a2">#000011a2</color> + <color name="i_am_color_11a3">#000011a3</color> + <color name="i_am_color_11a4">#000011a4</color> + <color name="i_am_color_11a5">#000011a5</color> + <color name="i_am_color_11a6">#000011a6</color> + <color name="i_am_color_11a7">#000011a7</color> + <color name="i_am_color_11a8">#000011a8</color> + <color name="i_am_color_11a9">#000011a9</color> + <color name="i_am_color_11aa">#000011aa</color> + <color name="i_am_color_11ab">#000011ab</color> + <color name="i_am_color_11ac">#000011ac</color> + <color name="i_am_color_11ad">#000011ad</color> + <color name="i_am_color_11ae">#000011ae</color> + <color name="i_am_color_11af">#000011af</color> + <color name="i_am_color_11b0">#000011b0</color> + <color name="i_am_color_11b1">#000011b1</color> + <color name="i_am_color_11b2">#000011b2</color> + <color name="i_am_color_11b3">#000011b3</color> + <color name="i_am_color_11b4">#000011b4</color> + <color name="i_am_color_11b5">#000011b5</color> + <color name="i_am_color_11b6">#000011b6</color> + <color name="i_am_color_11b7">#000011b7</color> + <color name="i_am_color_11b8">#000011b8</color> + <color name="i_am_color_11b9">#000011b9</color> + <color name="i_am_color_11ba">#000011ba</color> + <color name="i_am_color_11bb">#000011bb</color> + <color name="i_am_color_11bc">#000011bc</color> + <color name="i_am_color_11bd">#000011bd</color> + <color name="i_am_color_11be">#000011be</color> + <color name="i_am_color_11bf">#000011bf</color> + <color name="i_am_color_11c0">#000011c0</color> + <color name="i_am_color_11c1">#000011c1</color> + <color name="i_am_color_11c2">#000011c2</color> + <color name="i_am_color_11c3">#000011c3</color> + <color name="i_am_color_11c4">#000011c4</color> + <color name="i_am_color_11c5">#000011c5</color> + <color name="i_am_color_11c6">#000011c6</color> + <color name="i_am_color_11c7">#000011c7</color> + <color name="i_am_color_11c8">#000011c8</color> + <color name="i_am_color_11c9">#000011c9</color> + <color name="i_am_color_11ca">#000011ca</color> + <color name="i_am_color_11cb">#000011cb</color> + <color name="i_am_color_11cc">#000011cc</color> + <color name="i_am_color_11cd">#000011cd</color> + <color name="i_am_color_11ce">#000011ce</color> + <color name="i_am_color_11cf">#000011cf</color> + <color name="i_am_color_11d0">#000011d0</color> + <color name="i_am_color_11d1">#000011d1</color> + <color name="i_am_color_11d2">#000011d2</color> + <color name="i_am_color_11d3">#000011d3</color> + <color name="i_am_color_11d4">#000011d4</color> + <color name="i_am_color_11d5">#000011d5</color> + <color name="i_am_color_11d6">#000011d6</color> + <color name="i_am_color_11d7">#000011d7</color> + <color name="i_am_color_11d8">#000011d8</color> + <color name="i_am_color_11d9">#000011d9</color> + <color name="i_am_color_11da">#000011da</color> + <color name="i_am_color_11db">#000011db</color> + <color name="i_am_color_11dc">#000011dc</color> + <color name="i_am_color_11dd">#000011dd</color> + <color name="i_am_color_11de">#000011de</color> + <color name="i_am_color_11df">#000011df</color> + <color name="i_am_color_11e0">#000011e0</color> + <color name="i_am_color_11e1">#000011e1</color> + <color name="i_am_color_11e2">#000011e2</color> + <color name="i_am_color_11e3">#000011e3</color> + <color name="i_am_color_11e4">#000011e4</color> + <color name="i_am_color_11e5">#000011e5</color> + <color name="i_am_color_11e6">#000011e6</color> + <color name="i_am_color_11e7">#000011e7</color> + <color name="i_am_color_11e8">#000011e8</color> + <color name="i_am_color_11e9">#000011e9</color> + <color name="i_am_color_11ea">#000011ea</color> + <color name="i_am_color_11eb">#000011eb</color> + <color name="i_am_color_11ec">#000011ec</color> + <color name="i_am_color_11ed">#000011ed</color> + <color name="i_am_color_11ee">#000011ee</color> + <color name="i_am_color_11ef">#000011ef</color> + <color name="i_am_color_11f0">#000011f0</color> + <color name="i_am_color_11f1">#000011f1</color> + <color name="i_am_color_11f2">#000011f2</color> + <color name="i_am_color_11f3">#000011f3</color> + <color name="i_am_color_11f4">#000011f4</color> + <color name="i_am_color_11f5">#000011f5</color> + <color name="i_am_color_11f6">#000011f6</color> + <color name="i_am_color_11f7">#000011f7</color> + <color name="i_am_color_11f8">#000011f8</color> + <color name="i_am_color_11f9">#000011f9</color> + <color name="i_am_color_11fa">#000011fa</color> + <color name="i_am_color_11fb">#000011fb</color> + <color name="i_am_color_11fc">#000011fc</color> + <color name="i_am_color_11fd">#000011fd</color> + <color name="i_am_color_11fe">#000011fe</color> + <color name="i_am_color_11ff">#000011ff</color> + <color name="i_am_color_1200">#00001200</color> + <color name="i_am_color_1201">#00001201</color> + <color name="i_am_color_1202">#00001202</color> + <color name="i_am_color_1203">#00001203</color> + <color name="i_am_color_1204">#00001204</color> + <color name="i_am_color_1205">#00001205</color> + <color name="i_am_color_1206">#00001206</color> + <color name="i_am_color_1207">#00001207</color> + <color name="i_am_color_1208">#00001208</color> + <color name="i_am_color_1209">#00001209</color> + <color name="i_am_color_120a">#0000120a</color> + <color name="i_am_color_120b">#0000120b</color> + <color name="i_am_color_120c">#0000120c</color> + <color name="i_am_color_120d">#0000120d</color> + <color name="i_am_color_120e">#0000120e</color> + <color name="i_am_color_120f">#0000120f</color> + <color name="i_am_color_1210">#00001210</color> + <color name="i_am_color_1211">#00001211</color> + <color name="i_am_color_1212">#00001212</color> + <color name="i_am_color_1213">#00001213</color> + <color name="i_am_color_1214">#00001214</color> + <color name="i_am_color_1215">#00001215</color> + <color name="i_am_color_1216">#00001216</color> + <color name="i_am_color_1217">#00001217</color> + <color name="i_am_color_1218">#00001218</color> + <color name="i_am_color_1219">#00001219</color> + <color name="i_am_color_121a">#0000121a</color> + <color name="i_am_color_121b">#0000121b</color> + <color name="i_am_color_121c">#0000121c</color> + <color name="i_am_color_121d">#0000121d</color> + <color name="i_am_color_121e">#0000121e</color> + <color name="i_am_color_121f">#0000121f</color> + <color name="i_am_color_1220">#00001220</color> + <color name="i_am_color_1221">#00001221</color> + <color name="i_am_color_1222">#00001222</color> + <color name="i_am_color_1223">#00001223</color> + <color name="i_am_color_1224">#00001224</color> + <color name="i_am_color_1225">#00001225</color> + <color name="i_am_color_1226">#00001226</color> + <color name="i_am_color_1227">#00001227</color> + <color name="i_am_color_1228">#00001228</color> + <color name="i_am_color_1229">#00001229</color> + <color name="i_am_color_122a">#0000122a</color> + <color name="i_am_color_122b">#0000122b</color> + <color name="i_am_color_122c">#0000122c</color> + <color name="i_am_color_122d">#0000122d</color> + <color name="i_am_color_122e">#0000122e</color> + <color name="i_am_color_122f">#0000122f</color> + <color name="i_am_color_1230">#00001230</color> + <color name="i_am_color_1231">#00001231</color> + <color name="i_am_color_1232">#00001232</color> + <color name="i_am_color_1233">#00001233</color> + <color name="i_am_color_1234">#00001234</color> + <color name="i_am_color_1235">#00001235</color> + <color name="i_am_color_1236">#00001236</color> + <color name="i_am_color_1237">#00001237</color> + <color name="i_am_color_1238">#00001238</color> + <color name="i_am_color_1239">#00001239</color> + <color name="i_am_color_123a">#0000123a</color> + <color name="i_am_color_123b">#0000123b</color> + <color name="i_am_color_123c">#0000123c</color> + <color name="i_am_color_123d">#0000123d</color> + <color name="i_am_color_123e">#0000123e</color> + <color name="i_am_color_123f">#0000123f</color> + <color name="i_am_color_1240">#00001240</color> + <color name="i_am_color_1241">#00001241</color> + <color name="i_am_color_1242">#00001242</color> + <color name="i_am_color_1243">#00001243</color> + <color name="i_am_color_1244">#00001244</color> + <color name="i_am_color_1245">#00001245</color> + <color name="i_am_color_1246">#00001246</color> + <color name="i_am_color_1247">#00001247</color> + <color name="i_am_color_1248">#00001248</color> + <color name="i_am_color_1249">#00001249</color> + <color name="i_am_color_124a">#0000124a</color> + <color name="i_am_color_124b">#0000124b</color> + <color name="i_am_color_124c">#0000124c</color> + <color name="i_am_color_124d">#0000124d</color> + <color name="i_am_color_124e">#0000124e</color> + <color name="i_am_color_124f">#0000124f</color> + <color name="i_am_color_1250">#00001250</color> + <color name="i_am_color_1251">#00001251</color> + <color name="i_am_color_1252">#00001252</color> + <color name="i_am_color_1253">#00001253</color> + <color name="i_am_color_1254">#00001254</color> + <color name="i_am_color_1255">#00001255</color> + <color name="i_am_color_1256">#00001256</color> + <color name="i_am_color_1257">#00001257</color> + <color name="i_am_color_1258">#00001258</color> + <color name="i_am_color_1259">#00001259</color> + <color name="i_am_color_125a">#0000125a</color> + <color name="i_am_color_125b">#0000125b</color> + <color name="i_am_color_125c">#0000125c</color> + <color name="i_am_color_125d">#0000125d</color> + <color name="i_am_color_125e">#0000125e</color> + <color name="i_am_color_125f">#0000125f</color> + <color name="i_am_color_1260">#00001260</color> + <color name="i_am_color_1261">#00001261</color> + <color name="i_am_color_1262">#00001262</color> + <color name="i_am_color_1263">#00001263</color> + <color name="i_am_color_1264">#00001264</color> + <color name="i_am_color_1265">#00001265</color> + <color name="i_am_color_1266">#00001266</color> + <color name="i_am_color_1267">#00001267</color> + <color name="i_am_color_1268">#00001268</color> + <color name="i_am_color_1269">#00001269</color> + <color name="i_am_color_126a">#0000126a</color> + <color name="i_am_color_126b">#0000126b</color> + <color name="i_am_color_126c">#0000126c</color> + <color name="i_am_color_126d">#0000126d</color> + <color name="i_am_color_126e">#0000126e</color> + <color name="i_am_color_126f">#0000126f</color> + <color name="i_am_color_1270">#00001270</color> + <color name="i_am_color_1271">#00001271</color> + <color name="i_am_color_1272">#00001272</color> + <color name="i_am_color_1273">#00001273</color> + <color name="i_am_color_1274">#00001274</color> + <color name="i_am_color_1275">#00001275</color> + <color name="i_am_color_1276">#00001276</color> + <color name="i_am_color_1277">#00001277</color> + <color name="i_am_color_1278">#00001278</color> + <color name="i_am_color_1279">#00001279</color> + <color name="i_am_color_127a">#0000127a</color> + <color name="i_am_color_127b">#0000127b</color> + <color name="i_am_color_127c">#0000127c</color> + <color name="i_am_color_127d">#0000127d</color> + <color name="i_am_color_127e">#0000127e</color> + <color name="i_am_color_127f">#0000127f</color> + <color name="i_am_color_1280">#00001280</color> + <color name="i_am_color_1281">#00001281</color> + <color name="i_am_color_1282">#00001282</color> + <color name="i_am_color_1283">#00001283</color> + <color name="i_am_color_1284">#00001284</color> + <color name="i_am_color_1285">#00001285</color> + <color name="i_am_color_1286">#00001286</color> + <color name="i_am_color_1287">#00001287</color> + <color name="i_am_color_1288">#00001288</color> + <color name="i_am_color_1289">#00001289</color> + <color name="i_am_color_128a">#0000128a</color> + <color name="i_am_color_128b">#0000128b</color> + <color name="i_am_color_128c">#0000128c</color> + <color name="i_am_color_128d">#0000128d</color> + <color name="i_am_color_128e">#0000128e</color> + <color name="i_am_color_128f">#0000128f</color> + <color name="i_am_color_1290">#00001290</color> + <color name="i_am_color_1291">#00001291</color> + <color name="i_am_color_1292">#00001292</color> + <color name="i_am_color_1293">#00001293</color> + <color name="i_am_color_1294">#00001294</color> + <color name="i_am_color_1295">#00001295</color> + <color name="i_am_color_1296">#00001296</color> + <color name="i_am_color_1297">#00001297</color> + <color name="i_am_color_1298">#00001298</color> + <color name="i_am_color_1299">#00001299</color> + <color name="i_am_color_129a">#0000129a</color> + <color name="i_am_color_129b">#0000129b</color> + <color name="i_am_color_129c">#0000129c</color> + <color name="i_am_color_129d">#0000129d</color> + <color name="i_am_color_129e">#0000129e</color> + <color name="i_am_color_129f">#0000129f</color> + <color name="i_am_color_12a0">#000012a0</color> + <color name="i_am_color_12a1">#000012a1</color> + <color name="i_am_color_12a2">#000012a2</color> + <color name="i_am_color_12a3">#000012a3</color> + <color name="i_am_color_12a4">#000012a4</color> + <color name="i_am_color_12a5">#000012a5</color> + <color name="i_am_color_12a6">#000012a6</color> + <color name="i_am_color_12a7">#000012a7</color> + <color name="i_am_color_12a8">#000012a8</color> + <color name="i_am_color_12a9">#000012a9</color> + <color name="i_am_color_12aa">#000012aa</color> + <color name="i_am_color_12ab">#000012ab</color> + <color name="i_am_color_12ac">#000012ac</color> + <color name="i_am_color_12ad">#000012ad</color> + <color name="i_am_color_12ae">#000012ae</color> + <color name="i_am_color_12af">#000012af</color> + <color name="i_am_color_12b0">#000012b0</color> + <color name="i_am_color_12b1">#000012b1</color> + <color name="i_am_color_12b2">#000012b2</color> + <color name="i_am_color_12b3">#000012b3</color> + <color name="i_am_color_12b4">#000012b4</color> + <color name="i_am_color_12b5">#000012b5</color> + <color name="i_am_color_12b6">#000012b6</color> + <color name="i_am_color_12b7">#000012b7</color> + <color name="i_am_color_12b8">#000012b8</color> + <color name="i_am_color_12b9">#000012b9</color> + <color name="i_am_color_12ba">#000012ba</color> + <color name="i_am_color_12bb">#000012bb</color> + <color name="i_am_color_12bc">#000012bc</color> + <color name="i_am_color_12bd">#000012bd</color> + <color name="i_am_color_12be">#000012be</color> + <color name="i_am_color_12bf">#000012bf</color> + <color name="i_am_color_12c0">#000012c0</color> + <color name="i_am_color_12c1">#000012c1</color> + <color name="i_am_color_12c2">#000012c2</color> + <color name="i_am_color_12c3">#000012c3</color> + <color name="i_am_color_12c4">#000012c4</color> + <color name="i_am_color_12c5">#000012c5</color> + <color name="i_am_color_12c6">#000012c6</color> + <color name="i_am_color_12c7">#000012c7</color> + <color name="i_am_color_12c8">#000012c8</color> + <color name="i_am_color_12c9">#000012c9</color> + <color name="i_am_color_12ca">#000012ca</color> + <color name="i_am_color_12cb">#000012cb</color> + <color name="i_am_color_12cc">#000012cc</color> + <color name="i_am_color_12cd">#000012cd</color> + <color name="i_am_color_12ce">#000012ce</color> + <color name="i_am_color_12cf">#000012cf</color> + <color name="i_am_color_12d0">#000012d0</color> + <color name="i_am_color_12d1">#000012d1</color> + <color name="i_am_color_12d2">#000012d2</color> + <color name="i_am_color_12d3">#000012d3</color> + <color name="i_am_color_12d4">#000012d4</color> + <color name="i_am_color_12d5">#000012d5</color> + <color name="i_am_color_12d6">#000012d6</color> + <color name="i_am_color_12d7">#000012d7</color> + <color name="i_am_color_12d8">#000012d8</color> + <color name="i_am_color_12d9">#000012d9</color> + <color name="i_am_color_12da">#000012da</color> + <color name="i_am_color_12db">#000012db</color> + <color name="i_am_color_12dc">#000012dc</color> + <color name="i_am_color_12dd">#000012dd</color> + <color name="i_am_color_12de">#000012de</color> + <color name="i_am_color_12df">#000012df</color> + <color name="i_am_color_12e0">#000012e0</color> + <color name="i_am_color_12e1">#000012e1</color> + <color name="i_am_color_12e2">#000012e2</color> + <color name="i_am_color_12e3">#000012e3</color> + <color name="i_am_color_12e4">#000012e4</color> + <color name="i_am_color_12e5">#000012e5</color> + <color name="i_am_color_12e6">#000012e6</color> + <color name="i_am_color_12e7">#000012e7</color> + <color name="i_am_color_12e8">#000012e8</color> + <color name="i_am_color_12e9">#000012e9</color> + <color name="i_am_color_12ea">#000012ea</color> + <color name="i_am_color_12eb">#000012eb</color> + <color name="i_am_color_12ec">#000012ec</color> + <color name="i_am_color_12ed">#000012ed</color> + <color name="i_am_color_12ee">#000012ee</color> + <color name="i_am_color_12ef">#000012ef</color> + <color name="i_am_color_12f0">#000012f0</color> + <color name="i_am_color_12f1">#000012f1</color> + <color name="i_am_color_12f2">#000012f2</color> + <color name="i_am_color_12f3">#000012f3</color> + <color name="i_am_color_12f4">#000012f4</color> + <color name="i_am_color_12f5">#000012f5</color> + <color name="i_am_color_12f6">#000012f6</color> + <color name="i_am_color_12f7">#000012f7</color> + <color name="i_am_color_12f8">#000012f8</color> + <color name="i_am_color_12f9">#000012f9</color> + <color name="i_am_color_12fa">#000012fa</color> + <color name="i_am_color_12fb">#000012fb</color> + <color name="i_am_color_12fc">#000012fc</color> + <color name="i_am_color_12fd">#000012fd</color> + <color name="i_am_color_12fe">#000012fe</color> + <color name="i_am_color_12ff">#000012ff</color> + <color name="i_am_color_1300">#00001300</color> + <color name="i_am_color_1301">#00001301</color> + <color name="i_am_color_1302">#00001302</color> + <color name="i_am_color_1303">#00001303</color> + <color name="i_am_color_1304">#00001304</color> + <color name="i_am_color_1305">#00001305</color> + <color name="i_am_color_1306">#00001306</color> + <color name="i_am_color_1307">#00001307</color> + <color name="i_am_color_1308">#00001308</color> + <color name="i_am_color_1309">#00001309</color> + <color name="i_am_color_130a">#0000130a</color> + <color name="i_am_color_130b">#0000130b</color> + <color name="i_am_color_130c">#0000130c</color> + <color name="i_am_color_130d">#0000130d</color> + <color name="i_am_color_130e">#0000130e</color> + <color name="i_am_color_130f">#0000130f</color> + <color name="i_am_color_1310">#00001310</color> + <color name="i_am_color_1311">#00001311</color> + <color name="i_am_color_1312">#00001312</color> + <color name="i_am_color_1313">#00001313</color> + <color name="i_am_color_1314">#00001314</color> + <color name="i_am_color_1315">#00001315</color> + <color name="i_am_color_1316">#00001316</color> + <color name="i_am_color_1317">#00001317</color> + <color name="i_am_color_1318">#00001318</color> + <color name="i_am_color_1319">#00001319</color> + <color name="i_am_color_131a">#0000131a</color> + <color name="i_am_color_131b">#0000131b</color> + <color name="i_am_color_131c">#0000131c</color> + <color name="i_am_color_131d">#0000131d</color> + <color name="i_am_color_131e">#0000131e</color> + <color name="i_am_color_131f">#0000131f</color> + <color name="i_am_color_1320">#00001320</color> + <color name="i_am_color_1321">#00001321</color> + <color name="i_am_color_1322">#00001322</color> + <color name="i_am_color_1323">#00001323</color> + <color name="i_am_color_1324">#00001324</color> + <color name="i_am_color_1325">#00001325</color> + <color name="i_am_color_1326">#00001326</color> + <color name="i_am_color_1327">#00001327</color> + <color name="i_am_color_1328">#00001328</color> + <color name="i_am_color_1329">#00001329</color> + <color name="i_am_color_132a">#0000132a</color> + <color name="i_am_color_132b">#0000132b</color> + <color name="i_am_color_132c">#0000132c</color> + <color name="i_am_color_132d">#0000132d</color> + <color name="i_am_color_132e">#0000132e</color> + <color name="i_am_color_132f">#0000132f</color> + <color name="i_am_color_1330">#00001330</color> + <color name="i_am_color_1331">#00001331</color> + <color name="i_am_color_1332">#00001332</color> + <color name="i_am_color_1333">#00001333</color> + <color name="i_am_color_1334">#00001334</color> + <color name="i_am_color_1335">#00001335</color> + <color name="i_am_color_1336">#00001336</color> + <color name="i_am_color_1337">#00001337</color> + <color name="i_am_color_1338">#00001338</color> + <color name="i_am_color_1339">#00001339</color> + <color name="i_am_color_133a">#0000133a</color> + <color name="i_am_color_133b">#0000133b</color> + <color name="i_am_color_133c">#0000133c</color> + <color name="i_am_color_133d">#0000133d</color> + <color name="i_am_color_133e">#0000133e</color> + <color name="i_am_color_133f">#0000133f</color> + <color name="i_am_color_1340">#00001340</color> + <color name="i_am_color_1341">#00001341</color> + <color name="i_am_color_1342">#00001342</color> + <color name="i_am_color_1343">#00001343</color> + <color name="i_am_color_1344">#00001344</color> + <color name="i_am_color_1345">#00001345</color> + <color name="i_am_color_1346">#00001346</color> + <color name="i_am_color_1347">#00001347</color> + <color name="i_am_color_1348">#00001348</color> + <color name="i_am_color_1349">#00001349</color> + <color name="i_am_color_134a">#0000134a</color> + <color name="i_am_color_134b">#0000134b</color> + <color name="i_am_color_134c">#0000134c</color> + <color name="i_am_color_134d">#0000134d</color> + <color name="i_am_color_134e">#0000134e</color> + <color name="i_am_color_134f">#0000134f</color> + <color name="i_am_color_1350">#00001350</color> + <color name="i_am_color_1351">#00001351</color> + <color name="i_am_color_1352">#00001352</color> + <color name="i_am_color_1353">#00001353</color> + <color name="i_am_color_1354">#00001354</color> + <color name="i_am_color_1355">#00001355</color> + <color name="i_am_color_1356">#00001356</color> + <color name="i_am_color_1357">#00001357</color> + <color name="i_am_color_1358">#00001358</color> + <color name="i_am_color_1359">#00001359</color> + <color name="i_am_color_135a">#0000135a</color> + <color name="i_am_color_135b">#0000135b</color> + <color name="i_am_color_135c">#0000135c</color> + <color name="i_am_color_135d">#0000135d</color> + <color name="i_am_color_135e">#0000135e</color> + <color name="i_am_color_135f">#0000135f</color> + <color name="i_am_color_1360">#00001360</color> + <color name="i_am_color_1361">#00001361</color> + <color name="i_am_color_1362">#00001362</color> + <color name="i_am_color_1363">#00001363</color> + <color name="i_am_color_1364">#00001364</color> + <color name="i_am_color_1365">#00001365</color> + <color name="i_am_color_1366">#00001366</color> + <color name="i_am_color_1367">#00001367</color> + <color name="i_am_color_1368">#00001368</color> + <color name="i_am_color_1369">#00001369</color> + <color name="i_am_color_136a">#0000136a</color> + <color name="i_am_color_136b">#0000136b</color> + <color name="i_am_color_136c">#0000136c</color> + <color name="i_am_color_136d">#0000136d</color> + <color name="i_am_color_136e">#0000136e</color> + <color name="i_am_color_136f">#0000136f</color> + <color name="i_am_color_1370">#00001370</color> + <color name="i_am_color_1371">#00001371</color> + <color name="i_am_color_1372">#00001372</color> + <color name="i_am_color_1373">#00001373</color> + <color name="i_am_color_1374">#00001374</color> + <color name="i_am_color_1375">#00001375</color> + <color name="i_am_color_1376">#00001376</color> + <color name="i_am_color_1377">#00001377</color> + <color name="i_am_color_1378">#00001378</color> + <color name="i_am_color_1379">#00001379</color> + <color name="i_am_color_137a">#0000137a</color> + <color name="i_am_color_137b">#0000137b</color> + <color name="i_am_color_137c">#0000137c</color> + <color name="i_am_color_137d">#0000137d</color> + <color name="i_am_color_137e">#0000137e</color> + <color name="i_am_color_137f">#0000137f</color> + <color name="i_am_color_1380">#00001380</color> + <color name="i_am_color_1381">#00001381</color> + <color name="i_am_color_1382">#00001382</color> + <color name="i_am_color_1383">#00001383</color> + <color name="i_am_color_1384">#00001384</color> + <color name="i_am_color_1385">#00001385</color> + <color name="i_am_color_1386">#00001386</color> + <color name="i_am_color_1387">#00001387</color> + <color name="i_am_color_1388">#00001388</color> + <color name="i_am_color_1389">#00001389</color> + <color name="i_am_color_138a">#0000138a</color> + <color name="i_am_color_138b">#0000138b</color> + <color name="i_am_color_138c">#0000138c</color> + <color name="i_am_color_138d">#0000138d</color> + <color name="i_am_color_138e">#0000138e</color> + <color name="i_am_color_138f">#0000138f</color> + <color name="i_am_color_1390">#00001390</color> + <color name="i_am_color_1391">#00001391</color> + <color name="i_am_color_1392">#00001392</color> + <color name="i_am_color_1393">#00001393</color> + <color name="i_am_color_1394">#00001394</color> + <color name="i_am_color_1395">#00001395</color> + <color name="i_am_color_1396">#00001396</color> + <color name="i_am_color_1397">#00001397</color> + <color name="i_am_color_1398">#00001398</color> + <color name="i_am_color_1399">#00001399</color> + <color name="i_am_color_139a">#0000139a</color> + <color name="i_am_color_139b">#0000139b</color> + <color name="i_am_color_139c">#0000139c</color> + <color name="i_am_color_139d">#0000139d</color> + <color name="i_am_color_139e">#0000139e</color> + <color name="i_am_color_139f">#0000139f</color> + <color name="i_am_color_13a0">#000013a0</color> + <color name="i_am_color_13a1">#000013a1</color> + <color name="i_am_color_13a2">#000013a2</color> + <color name="i_am_color_13a3">#000013a3</color> + <color name="i_am_color_13a4">#000013a4</color> + <color name="i_am_color_13a5">#000013a5</color> + <color name="i_am_color_13a6">#000013a6</color> + <color name="i_am_color_13a7">#000013a7</color> + <color name="i_am_color_13a8">#000013a8</color> + <color name="i_am_color_13a9">#000013a9</color> + <color name="i_am_color_13aa">#000013aa</color> + <color name="i_am_color_13ab">#000013ab</color> + <color name="i_am_color_13ac">#000013ac</color> + <color name="i_am_color_13ad">#000013ad</color> + <color name="i_am_color_13ae">#000013ae</color> + <color name="i_am_color_13af">#000013af</color> + <color name="i_am_color_13b0">#000013b0</color> + <color name="i_am_color_13b1">#000013b1</color> + <color name="i_am_color_13b2">#000013b2</color> + <color name="i_am_color_13b3">#000013b3</color> + <color name="i_am_color_13b4">#000013b4</color> + <color name="i_am_color_13b5">#000013b5</color> + <color name="i_am_color_13b6">#000013b6</color> + <color name="i_am_color_13b7">#000013b7</color> + <color name="i_am_color_13b8">#000013b8</color> + <color name="i_am_color_13b9">#000013b9</color> + <color name="i_am_color_13ba">#000013ba</color> + <color name="i_am_color_13bb">#000013bb</color> + <color name="i_am_color_13bc">#000013bc</color> + <color name="i_am_color_13bd">#000013bd</color> + <color name="i_am_color_13be">#000013be</color> + <color name="i_am_color_13bf">#000013bf</color> + <color name="i_am_color_13c0">#000013c0</color> + <color name="i_am_color_13c1">#000013c1</color> + <color name="i_am_color_13c2">#000013c2</color> + <color name="i_am_color_13c3">#000013c3</color> + <color name="i_am_color_13c4">#000013c4</color> + <color name="i_am_color_13c5">#000013c5</color> + <color name="i_am_color_13c6">#000013c6</color> + <color name="i_am_color_13c7">#000013c7</color> + <color name="i_am_color_13c8">#000013c8</color> + <color name="i_am_color_13c9">#000013c9</color> + <color name="i_am_color_13ca">#000013ca</color> + <color name="i_am_color_13cb">#000013cb</color> + <color name="i_am_color_13cc">#000013cc</color> + <color name="i_am_color_13cd">#000013cd</color> + <color name="i_am_color_13ce">#000013ce</color> + <color name="i_am_color_13cf">#000013cf</color> + <color name="i_am_color_13d0">#000013d0</color> + <color name="i_am_color_13d1">#000013d1</color> + <color name="i_am_color_13d2">#000013d2</color> + <color name="i_am_color_13d3">#000013d3</color> + <color name="i_am_color_13d4">#000013d4</color> + <color name="i_am_color_13d5">#000013d5</color> + <color name="i_am_color_13d6">#000013d6</color> + <color name="i_am_color_13d7">#000013d7</color> + <color name="i_am_color_13d8">#000013d8</color> + <color name="i_am_color_13d9">#000013d9</color> + <color name="i_am_color_13da">#000013da</color> + <color name="i_am_color_13db">#000013db</color> + <color name="i_am_color_13dc">#000013dc</color> + <color name="i_am_color_13dd">#000013dd</color> + <color name="i_am_color_13de">#000013de</color> + <color name="i_am_color_13df">#000013df</color> + <color name="i_am_color_13e0">#000013e0</color> + <color name="i_am_color_13e1">#000013e1</color> + <color name="i_am_color_13e2">#000013e2</color> + <color name="i_am_color_13e3">#000013e3</color> + <color name="i_am_color_13e4">#000013e4</color> + <color name="i_am_color_13e5">#000013e5</color> + <color name="i_am_color_13e6">#000013e6</color> + <color name="i_am_color_13e7">#000013e7</color> + <color name="i_am_color_13e8">#000013e8</color> + <color name="i_am_color_13e9">#000013e9</color> + <color name="i_am_color_13ea">#000013ea</color> + <color name="i_am_color_13eb">#000013eb</color> + <color name="i_am_color_13ec">#000013ec</color> + <color name="i_am_color_13ed">#000013ed</color> + <color name="i_am_color_13ee">#000013ee</color> + <color name="i_am_color_13ef">#000013ef</color> + <color name="i_am_color_13f0">#000013f0</color> + <color name="i_am_color_13f1">#000013f1</color> + <color name="i_am_color_13f2">#000013f2</color> + <color name="i_am_color_13f3">#000013f3</color> + <color name="i_am_color_13f4">#000013f4</color> + <color name="i_am_color_13f5">#000013f5</color> + <color name="i_am_color_13f6">#000013f6</color> + <color name="i_am_color_13f7">#000013f7</color> + <color name="i_am_color_13f8">#000013f8</color> + <color name="i_am_color_13f9">#000013f9</color> + <color name="i_am_color_13fa">#000013fa</color> + <color name="i_am_color_13fb">#000013fb</color> + <color name="i_am_color_13fc">#000013fc</color> + <color name="i_am_color_13fd">#000013fd</color> + <color name="i_am_color_13fe">#000013fe</color> + <color name="i_am_color_13ff">#000013ff</color> + <color name="i_am_color_1400">#00001400</color> + <color name="i_am_color_1401">#00001401</color> + <color name="i_am_color_1402">#00001402</color> + <color name="i_am_color_1403">#00001403</color> + <color name="i_am_color_1404">#00001404</color> + <color name="i_am_color_1405">#00001405</color> + <color name="i_am_color_1406">#00001406</color> + <color name="i_am_color_1407">#00001407</color> + <color name="i_am_color_1408">#00001408</color> + <color name="i_am_color_1409">#00001409</color> + <color name="i_am_color_140a">#0000140a</color> + <color name="i_am_color_140b">#0000140b</color> + <color name="i_am_color_140c">#0000140c</color> + <color name="i_am_color_140d">#0000140d</color> + <color name="i_am_color_140e">#0000140e</color> + <color name="i_am_color_140f">#0000140f</color> + <color name="i_am_color_1410">#00001410</color> + <color name="i_am_color_1411">#00001411</color> + <color name="i_am_color_1412">#00001412</color> + <color name="i_am_color_1413">#00001413</color> + <color name="i_am_color_1414">#00001414</color> + <color name="i_am_color_1415">#00001415</color> + <color name="i_am_color_1416">#00001416</color> + <color name="i_am_color_1417">#00001417</color> + <color name="i_am_color_1418">#00001418</color> + <color name="i_am_color_1419">#00001419</color> + <color name="i_am_color_141a">#0000141a</color> + <color name="i_am_color_141b">#0000141b</color> + <color name="i_am_color_141c">#0000141c</color> + <color name="i_am_color_141d">#0000141d</color> + <color name="i_am_color_141e">#0000141e</color> + <color name="i_am_color_141f">#0000141f</color> + <color name="i_am_color_1420">#00001420</color> + <color name="i_am_color_1421">#00001421</color> + <color name="i_am_color_1422">#00001422</color> + <color name="i_am_color_1423">#00001423</color> + <color name="i_am_color_1424">#00001424</color> + <color name="i_am_color_1425">#00001425</color> + <color name="i_am_color_1426">#00001426</color> + <color name="i_am_color_1427">#00001427</color> + <color name="i_am_color_1428">#00001428</color> + <color name="i_am_color_1429">#00001429</color> + <color name="i_am_color_142a">#0000142a</color> + <color name="i_am_color_142b">#0000142b</color> + <color name="i_am_color_142c">#0000142c</color> + <color name="i_am_color_142d">#0000142d</color> + <color name="i_am_color_142e">#0000142e</color> + <color name="i_am_color_142f">#0000142f</color> + <color name="i_am_color_1430">#00001430</color> + <color name="i_am_color_1431">#00001431</color> + <color name="i_am_color_1432">#00001432</color> + <color name="i_am_color_1433">#00001433</color> + <color name="i_am_color_1434">#00001434</color> + <color name="i_am_color_1435">#00001435</color> + <color name="i_am_color_1436">#00001436</color> + <color name="i_am_color_1437">#00001437</color> + <color name="i_am_color_1438">#00001438</color> + <color name="i_am_color_1439">#00001439</color> + <color name="i_am_color_143a">#0000143a</color> + <color name="i_am_color_143b">#0000143b</color> + <color name="i_am_color_143c">#0000143c</color> + <color name="i_am_color_143d">#0000143d</color> + <color name="i_am_color_143e">#0000143e</color> + <color name="i_am_color_143f">#0000143f</color> + <color name="i_am_color_1440">#00001440</color> + <color name="i_am_color_1441">#00001441</color> + <color name="i_am_color_1442">#00001442</color> + <color name="i_am_color_1443">#00001443</color> + <color name="i_am_color_1444">#00001444</color> + <color name="i_am_color_1445">#00001445</color> + <color name="i_am_color_1446">#00001446</color> + <color name="i_am_color_1447">#00001447</color> + <color name="i_am_color_1448">#00001448</color> + <color name="i_am_color_1449">#00001449</color> + <color name="i_am_color_144a">#0000144a</color> + <color name="i_am_color_144b">#0000144b</color> + <color name="i_am_color_144c">#0000144c</color> + <color name="i_am_color_144d">#0000144d</color> + <color name="i_am_color_144e">#0000144e</color> + <color name="i_am_color_144f">#0000144f</color> + <color name="i_am_color_1450">#00001450</color> + <color name="i_am_color_1451">#00001451</color> + <color name="i_am_color_1452">#00001452</color> + <color name="i_am_color_1453">#00001453</color> + <color name="i_am_color_1454">#00001454</color> + <color name="i_am_color_1455">#00001455</color> + <color name="i_am_color_1456">#00001456</color> + <color name="i_am_color_1457">#00001457</color> + <color name="i_am_color_1458">#00001458</color> + <color name="i_am_color_1459">#00001459</color> + <color name="i_am_color_145a">#0000145a</color> + <color name="i_am_color_145b">#0000145b</color> + <color name="i_am_color_145c">#0000145c</color> + <color name="i_am_color_145d">#0000145d</color> + <color name="i_am_color_145e">#0000145e</color> + <color name="i_am_color_145f">#0000145f</color> + <color name="i_am_color_1460">#00001460</color> + <color name="i_am_color_1461">#00001461</color> + <color name="i_am_color_1462">#00001462</color> + <color name="i_am_color_1463">#00001463</color> + <color name="i_am_color_1464">#00001464</color> + <color name="i_am_color_1465">#00001465</color> + <color name="i_am_color_1466">#00001466</color> + <color name="i_am_color_1467">#00001467</color> + <color name="i_am_color_1468">#00001468</color> + <color name="i_am_color_1469">#00001469</color> + <color name="i_am_color_146a">#0000146a</color> + <color name="i_am_color_146b">#0000146b</color> + <color name="i_am_color_146c">#0000146c</color> + <color name="i_am_color_146d">#0000146d</color> + <color name="i_am_color_146e">#0000146e</color> + <color name="i_am_color_146f">#0000146f</color> + <color name="i_am_color_1470">#00001470</color> + <color name="i_am_color_1471">#00001471</color> + <color name="i_am_color_1472">#00001472</color> + <color name="i_am_color_1473">#00001473</color> + <color name="i_am_color_1474">#00001474</color> + <color name="i_am_color_1475">#00001475</color> + <color name="i_am_color_1476">#00001476</color> + <color name="i_am_color_1477">#00001477</color> + <color name="i_am_color_1478">#00001478</color> + <color name="i_am_color_1479">#00001479</color> + <color name="i_am_color_147a">#0000147a</color> + <color name="i_am_color_147b">#0000147b</color> + <color name="i_am_color_147c">#0000147c</color> + <color name="i_am_color_147d">#0000147d</color> + <color name="i_am_color_147e">#0000147e</color> + <color name="i_am_color_147f">#0000147f</color> + <color name="i_am_color_1480">#00001480</color> + <color name="i_am_color_1481">#00001481</color> + <color name="i_am_color_1482">#00001482</color> + <color name="i_am_color_1483">#00001483</color> + <color name="i_am_color_1484">#00001484</color> + <color name="i_am_color_1485">#00001485</color> + <color name="i_am_color_1486">#00001486</color> + <color name="i_am_color_1487">#00001487</color> + <color name="i_am_color_1488">#00001488</color> + <color name="i_am_color_1489">#00001489</color> + <color name="i_am_color_148a">#0000148a</color> + <color name="i_am_color_148b">#0000148b</color> + <color name="i_am_color_148c">#0000148c</color> + <color name="i_am_color_148d">#0000148d</color> + <color name="i_am_color_148e">#0000148e</color> + <color name="i_am_color_148f">#0000148f</color> + <color name="i_am_color_1490">#00001490</color> + <color name="i_am_color_1491">#00001491</color> + <color name="i_am_color_1492">#00001492</color> + <color name="i_am_color_1493">#00001493</color> + <color name="i_am_color_1494">#00001494</color> + <color name="i_am_color_1495">#00001495</color> + <color name="i_am_color_1496">#00001496</color> + <color name="i_am_color_1497">#00001497</color> + <color name="i_am_color_1498">#00001498</color> + <color name="i_am_color_1499">#00001499</color> + <color name="i_am_color_149a">#0000149a</color> + <color name="i_am_color_149b">#0000149b</color> + <color name="i_am_color_149c">#0000149c</color> + <color name="i_am_color_149d">#0000149d</color> + <color name="i_am_color_149e">#0000149e</color> + <color name="i_am_color_149f">#0000149f</color> + <color name="i_am_color_14a0">#000014a0</color> + <color name="i_am_color_14a1">#000014a1</color> + <color name="i_am_color_14a2">#000014a2</color> + <color name="i_am_color_14a3">#000014a3</color> + <color name="i_am_color_14a4">#000014a4</color> + <color name="i_am_color_14a5">#000014a5</color> + <color name="i_am_color_14a6">#000014a6</color> + <color name="i_am_color_14a7">#000014a7</color> + <color name="i_am_color_14a8">#000014a8</color> + <color name="i_am_color_14a9">#000014a9</color> + <color name="i_am_color_14aa">#000014aa</color> + <color name="i_am_color_14ab">#000014ab</color> + <color name="i_am_color_14ac">#000014ac</color> + <color name="i_am_color_14ad">#000014ad</color> + <color name="i_am_color_14ae">#000014ae</color> + <color name="i_am_color_14af">#000014af</color> + <color name="i_am_color_14b0">#000014b0</color> + <color name="i_am_color_14b1">#000014b1</color> + <color name="i_am_color_14b2">#000014b2</color> + <color name="i_am_color_14b3">#000014b3</color> + <color name="i_am_color_14b4">#000014b4</color> + <color name="i_am_color_14b5">#000014b5</color> + <color name="i_am_color_14b6">#000014b6</color> + <color name="i_am_color_14b7">#000014b7</color> + <color name="i_am_color_14b8">#000014b8</color> + <color name="i_am_color_14b9">#000014b9</color> + <color name="i_am_color_14ba">#000014ba</color> + <color name="i_am_color_14bb">#000014bb</color> + <color name="i_am_color_14bc">#000014bc</color> + <color name="i_am_color_14bd">#000014bd</color> + <color name="i_am_color_14be">#000014be</color> + <color name="i_am_color_14bf">#000014bf</color> + <color name="i_am_color_14c0">#000014c0</color> + <color name="i_am_color_14c1">#000014c1</color> + <color name="i_am_color_14c2">#000014c2</color> + <color name="i_am_color_14c3">#000014c3</color> + <color name="i_am_color_14c4">#000014c4</color> + <color name="i_am_color_14c5">#000014c5</color> + <color name="i_am_color_14c6">#000014c6</color> + <color name="i_am_color_14c7">#000014c7</color> + <color name="i_am_color_14c8">#000014c8</color> + <color name="i_am_color_14c9">#000014c9</color> + <color name="i_am_color_14ca">#000014ca</color> + <color name="i_am_color_14cb">#000014cb</color> + <color name="i_am_color_14cc">#000014cc</color> + <color name="i_am_color_14cd">#000014cd</color> + <color name="i_am_color_14ce">#000014ce</color> + <color name="i_am_color_14cf">#000014cf</color> + <color name="i_am_color_14d0">#000014d0</color> + <color name="i_am_color_14d1">#000014d1</color> + <color name="i_am_color_14d2">#000014d2</color> + <color name="i_am_color_14d3">#000014d3</color> + <color name="i_am_color_14d4">#000014d4</color> + <color name="i_am_color_14d5">#000014d5</color> + <color name="i_am_color_14d6">#000014d6</color> + <color name="i_am_color_14d7">#000014d7</color> + <color name="i_am_color_14d8">#000014d8</color> + <color name="i_am_color_14d9">#000014d9</color> + <color name="i_am_color_14da">#000014da</color> + <color name="i_am_color_14db">#000014db</color> + <color name="i_am_color_14dc">#000014dc</color> + <color name="i_am_color_14dd">#000014dd</color> + <color name="i_am_color_14de">#000014de</color> + <color name="i_am_color_14df">#000014df</color> + <color name="i_am_color_14e0">#000014e0</color> + <color name="i_am_color_14e1">#000014e1</color> + <color name="i_am_color_14e2">#000014e2</color> + <color name="i_am_color_14e3">#000014e3</color> + <color name="i_am_color_14e4">#000014e4</color> + <color name="i_am_color_14e5">#000014e5</color> + <color name="i_am_color_14e6">#000014e6</color> + <color name="i_am_color_14e7">#000014e7</color> + <color name="i_am_color_14e8">#000014e8</color> + <color name="i_am_color_14e9">#000014e9</color> + <color name="i_am_color_14ea">#000014ea</color> + <color name="i_am_color_14eb">#000014eb</color> + <color name="i_am_color_14ec">#000014ec</color> + <color name="i_am_color_14ed">#000014ed</color> + <color name="i_am_color_14ee">#000014ee</color> + <color name="i_am_color_14ef">#000014ef</color> + <color name="i_am_color_14f0">#000014f0</color> + <color name="i_am_color_14f1">#000014f1</color> + <color name="i_am_color_14f2">#000014f2</color> + <color name="i_am_color_14f3">#000014f3</color> + <color name="i_am_color_14f4">#000014f4</color> + <color name="i_am_color_14f5">#000014f5</color> + <color name="i_am_color_14f6">#000014f6</color> + <color name="i_am_color_14f7">#000014f7</color> + <color name="i_am_color_14f8">#000014f8</color> + <color name="i_am_color_14f9">#000014f9</color> + <color name="i_am_color_14fa">#000014fa</color> + <color name="i_am_color_14fb">#000014fb</color> + <color name="i_am_color_14fc">#000014fc</color> + <color name="i_am_color_14fd">#000014fd</color> + <color name="i_am_color_14fe">#000014fe</color> + <color name="i_am_color_14ff">#000014ff</color> + <color name="i_am_color_1500">#00001500</color> + <color name="i_am_color_1501">#00001501</color> + <color name="i_am_color_1502">#00001502</color> + <color name="i_am_color_1503">#00001503</color> + <color name="i_am_color_1504">#00001504</color> + <color name="i_am_color_1505">#00001505</color> + <color name="i_am_color_1506">#00001506</color> + <color name="i_am_color_1507">#00001507</color> + <color name="i_am_color_1508">#00001508</color> + <color name="i_am_color_1509">#00001509</color> + <color name="i_am_color_150a">#0000150a</color> + <color name="i_am_color_150b">#0000150b</color> + <color name="i_am_color_150c">#0000150c</color> + <color name="i_am_color_150d">#0000150d</color> + <color name="i_am_color_150e">#0000150e</color> + <color name="i_am_color_150f">#0000150f</color> + <color name="i_am_color_1510">#00001510</color> + <color name="i_am_color_1511">#00001511</color> + <color name="i_am_color_1512">#00001512</color> + <color name="i_am_color_1513">#00001513</color> + <color name="i_am_color_1514">#00001514</color> + <color name="i_am_color_1515">#00001515</color> + <color name="i_am_color_1516">#00001516</color> + <color name="i_am_color_1517">#00001517</color> + <color name="i_am_color_1518">#00001518</color> + <color name="i_am_color_1519">#00001519</color> + <color name="i_am_color_151a">#0000151a</color> + <color name="i_am_color_151b">#0000151b</color> + <color name="i_am_color_151c">#0000151c</color> + <color name="i_am_color_151d">#0000151d</color> + <color name="i_am_color_151e">#0000151e</color> + <color name="i_am_color_151f">#0000151f</color> + <color name="i_am_color_1520">#00001520</color> + <color name="i_am_color_1521">#00001521</color> + <color name="i_am_color_1522">#00001522</color> + <color name="i_am_color_1523">#00001523</color> + <color name="i_am_color_1524">#00001524</color> + <color name="i_am_color_1525">#00001525</color> + <color name="i_am_color_1526">#00001526</color> + <color name="i_am_color_1527">#00001527</color> + <color name="i_am_color_1528">#00001528</color> + <color name="i_am_color_1529">#00001529</color> + <color name="i_am_color_152a">#0000152a</color> + <color name="i_am_color_152b">#0000152b</color> + <color name="i_am_color_152c">#0000152c</color> + <color name="i_am_color_152d">#0000152d</color> + <color name="i_am_color_152e">#0000152e</color> + <color name="i_am_color_152f">#0000152f</color> + <color name="i_am_color_1530">#00001530</color> + <color name="i_am_color_1531">#00001531</color> + <color name="i_am_color_1532">#00001532</color> + <color name="i_am_color_1533">#00001533</color> + <color name="i_am_color_1534">#00001534</color> + <color name="i_am_color_1535">#00001535</color> + <color name="i_am_color_1536">#00001536</color> + <color name="i_am_color_1537">#00001537</color> + <color name="i_am_color_1538">#00001538</color> + <color name="i_am_color_1539">#00001539</color> + <color name="i_am_color_153a">#0000153a</color> + <color name="i_am_color_153b">#0000153b</color> + <color name="i_am_color_153c">#0000153c</color> + <color name="i_am_color_153d">#0000153d</color> + <color name="i_am_color_153e">#0000153e</color> + <color name="i_am_color_153f">#0000153f</color> + <color name="i_am_color_1540">#00001540</color> + <color name="i_am_color_1541">#00001541</color> + <color name="i_am_color_1542">#00001542</color> + <color name="i_am_color_1543">#00001543</color> + <color name="i_am_color_1544">#00001544</color> + <color name="i_am_color_1545">#00001545</color> + <color name="i_am_color_1546">#00001546</color> + <color name="i_am_color_1547">#00001547</color> + <color name="i_am_color_1548">#00001548</color> + <color name="i_am_color_1549">#00001549</color> + <color name="i_am_color_154a">#0000154a</color> + <color name="i_am_color_154b">#0000154b</color> + <color name="i_am_color_154c">#0000154c</color> + <color name="i_am_color_154d">#0000154d</color> + <color name="i_am_color_154e">#0000154e</color> + <color name="i_am_color_154f">#0000154f</color> + <color name="i_am_color_1550">#00001550</color> + <color name="i_am_color_1551">#00001551</color> + <color name="i_am_color_1552">#00001552</color> + <color name="i_am_color_1553">#00001553</color> + <color name="i_am_color_1554">#00001554</color> + <color name="i_am_color_1555">#00001555</color> + <color name="i_am_color_1556">#00001556</color> + <color name="i_am_color_1557">#00001557</color> + <color name="i_am_color_1558">#00001558</color> + <color name="i_am_color_1559">#00001559</color> + <color name="i_am_color_155a">#0000155a</color> + <color name="i_am_color_155b">#0000155b</color> + <color name="i_am_color_155c">#0000155c</color> + <color name="i_am_color_155d">#0000155d</color> + <color name="i_am_color_155e">#0000155e</color> + <color name="i_am_color_155f">#0000155f</color> + <color name="i_am_color_1560">#00001560</color> + <color name="i_am_color_1561">#00001561</color> + <color name="i_am_color_1562">#00001562</color> + <color name="i_am_color_1563">#00001563</color> + <color name="i_am_color_1564">#00001564</color> + <color name="i_am_color_1565">#00001565</color> + <color name="i_am_color_1566">#00001566</color> + <color name="i_am_color_1567">#00001567</color> + <color name="i_am_color_1568">#00001568</color> + <color name="i_am_color_1569">#00001569</color> + <color name="i_am_color_156a">#0000156a</color> + <color name="i_am_color_156b">#0000156b</color> + <color name="i_am_color_156c">#0000156c</color> + <color name="i_am_color_156d">#0000156d</color> + <color name="i_am_color_156e">#0000156e</color> + <color name="i_am_color_156f">#0000156f</color> + <color name="i_am_color_1570">#00001570</color> + <color name="i_am_color_1571">#00001571</color> + <color name="i_am_color_1572">#00001572</color> + <color name="i_am_color_1573">#00001573</color> + <color name="i_am_color_1574">#00001574</color> + <color name="i_am_color_1575">#00001575</color> + <color name="i_am_color_1576">#00001576</color> + <color name="i_am_color_1577">#00001577</color> + <color name="i_am_color_1578">#00001578</color> + <color name="i_am_color_1579">#00001579</color> + <color name="i_am_color_157a">#0000157a</color> + <color name="i_am_color_157b">#0000157b</color> + <color name="i_am_color_157c">#0000157c</color> + <color name="i_am_color_157d">#0000157d</color> + <color name="i_am_color_157e">#0000157e</color> + <color name="i_am_color_157f">#0000157f</color> + <color name="i_am_color_1580">#00001580</color> + <color name="i_am_color_1581">#00001581</color> + <color name="i_am_color_1582">#00001582</color> + <color name="i_am_color_1583">#00001583</color> + <color name="i_am_color_1584">#00001584</color> + <color name="i_am_color_1585">#00001585</color> + <color name="i_am_color_1586">#00001586</color> + <color name="i_am_color_1587">#00001587</color> + <color name="i_am_color_1588">#00001588</color> + <color name="i_am_color_1589">#00001589</color> + <color name="i_am_color_158a">#0000158a</color> + <color name="i_am_color_158b">#0000158b</color> + <color name="i_am_color_158c">#0000158c</color> + <color name="i_am_color_158d">#0000158d</color> + <color name="i_am_color_158e">#0000158e</color> + <color name="i_am_color_158f">#0000158f</color> + <color name="i_am_color_1590">#00001590</color> + <color name="i_am_color_1591">#00001591</color> + <color name="i_am_color_1592">#00001592</color> + <color name="i_am_color_1593">#00001593</color> + <color name="i_am_color_1594">#00001594</color> + <color name="i_am_color_1595">#00001595</color> + <color name="i_am_color_1596">#00001596</color> + <color name="i_am_color_1597">#00001597</color> + <color name="i_am_color_1598">#00001598</color> + <color name="i_am_color_1599">#00001599</color> + <color name="i_am_color_159a">#0000159a</color> + <color name="i_am_color_159b">#0000159b</color> + <color name="i_am_color_159c">#0000159c</color> + <color name="i_am_color_159d">#0000159d</color> + <color name="i_am_color_159e">#0000159e</color> + <color name="i_am_color_159f">#0000159f</color> + <color name="i_am_color_15a0">#000015a0</color> + <color name="i_am_color_15a1">#000015a1</color> + <color name="i_am_color_15a2">#000015a2</color> + <color name="i_am_color_15a3">#000015a3</color> + <color name="i_am_color_15a4">#000015a4</color> + <color name="i_am_color_15a5">#000015a5</color> + <color name="i_am_color_15a6">#000015a6</color> + <color name="i_am_color_15a7">#000015a7</color> + <color name="i_am_color_15a8">#000015a8</color> + <color name="i_am_color_15a9">#000015a9</color> + <color name="i_am_color_15aa">#000015aa</color> + <color name="i_am_color_15ab">#000015ab</color> + <color name="i_am_color_15ac">#000015ac</color> + <color name="i_am_color_15ad">#000015ad</color> + <color name="i_am_color_15ae">#000015ae</color> + <color name="i_am_color_15af">#000015af</color> + <color name="i_am_color_15b0">#000015b0</color> + <color name="i_am_color_15b1">#000015b1</color> + <color name="i_am_color_15b2">#000015b2</color> + <color name="i_am_color_15b3">#000015b3</color> + <color name="i_am_color_15b4">#000015b4</color> + <color name="i_am_color_15b5">#000015b5</color> + <color name="i_am_color_15b6">#000015b6</color> + <color name="i_am_color_15b7">#000015b7</color> + <color name="i_am_color_15b8">#000015b8</color> + <color name="i_am_color_15b9">#000015b9</color> + <color name="i_am_color_15ba">#000015ba</color> + <color name="i_am_color_15bb">#000015bb</color> + <color name="i_am_color_15bc">#000015bc</color> + <color name="i_am_color_15bd">#000015bd</color> + <color name="i_am_color_15be">#000015be</color> + <color name="i_am_color_15bf">#000015bf</color> + <color name="i_am_color_15c0">#000015c0</color> + <color name="i_am_color_15c1">#000015c1</color> + <color name="i_am_color_15c2">#000015c2</color> + <color name="i_am_color_15c3">#000015c3</color> + <color name="i_am_color_15c4">#000015c4</color> + <color name="i_am_color_15c5">#000015c5</color> + <color name="i_am_color_15c6">#000015c6</color> + <color name="i_am_color_15c7">#000015c7</color> + <color name="i_am_color_15c8">#000015c8</color> + <color name="i_am_color_15c9">#000015c9</color> + <color name="i_am_color_15ca">#000015ca</color> + <color name="i_am_color_15cb">#000015cb</color> + <color name="i_am_color_15cc">#000015cc</color> + <color name="i_am_color_15cd">#000015cd</color> + <color name="i_am_color_15ce">#000015ce</color> + <color name="i_am_color_15cf">#000015cf</color> + <color name="i_am_color_15d0">#000015d0</color> + <color name="i_am_color_15d1">#000015d1</color> + <color name="i_am_color_15d2">#000015d2</color> + <color name="i_am_color_15d3">#000015d3</color> + <color name="i_am_color_15d4">#000015d4</color> + <color name="i_am_color_15d5">#000015d5</color> + <color name="i_am_color_15d6">#000015d6</color> + <color name="i_am_color_15d7">#000015d7</color> + <color name="i_am_color_15d8">#000015d8</color> + <color name="i_am_color_15d9">#000015d9</color> + <color name="i_am_color_15da">#000015da</color> + <color name="i_am_color_15db">#000015db</color> + <color name="i_am_color_15dc">#000015dc</color> + <color name="i_am_color_15dd">#000015dd</color> + <color name="i_am_color_15de">#000015de</color> + <color name="i_am_color_15df">#000015df</color> + <color name="i_am_color_15e0">#000015e0</color> + <color name="i_am_color_15e1">#000015e1</color> + <color name="i_am_color_15e2">#000015e2</color> + <color name="i_am_color_15e3">#000015e3</color> + <color name="i_am_color_15e4">#000015e4</color> + <color name="i_am_color_15e5">#000015e5</color> + <color name="i_am_color_15e6">#000015e6</color> + <color name="i_am_color_15e7">#000015e7</color> + <color name="i_am_color_15e8">#000015e8</color> + <color name="i_am_color_15e9">#000015e9</color> + <color name="i_am_color_15ea">#000015ea</color> + <color name="i_am_color_15eb">#000015eb</color> + <color name="i_am_color_15ec">#000015ec</color> + <color name="i_am_color_15ed">#000015ed</color> + <color name="i_am_color_15ee">#000015ee</color> + <color name="i_am_color_15ef">#000015ef</color> + <color name="i_am_color_15f0">#000015f0</color> + <color name="i_am_color_15f1">#000015f1</color> + <color name="i_am_color_15f2">#000015f2</color> + <color name="i_am_color_15f3">#000015f3</color> + <color name="i_am_color_15f4">#000015f4</color> + <color name="i_am_color_15f5">#000015f5</color> + <color name="i_am_color_15f6">#000015f6</color> + <color name="i_am_color_15f7">#000015f7</color> + <color name="i_am_color_15f8">#000015f8</color> + <color name="i_am_color_15f9">#000015f9</color> + <color name="i_am_color_15fa">#000015fa</color> + <color name="i_am_color_15fb">#000015fb</color> + <color name="i_am_color_15fc">#000015fc</color> + <color name="i_am_color_15fd">#000015fd</color> + <color name="i_am_color_15fe">#000015fe</color> + <color name="i_am_color_15ff">#000015ff</color> + <color name="i_am_color_1600">#00001600</color> + <color name="i_am_color_1601">#00001601</color> + <color name="i_am_color_1602">#00001602</color> + <color name="i_am_color_1603">#00001603</color> + <color name="i_am_color_1604">#00001604</color> + <color name="i_am_color_1605">#00001605</color> + <color name="i_am_color_1606">#00001606</color> + <color name="i_am_color_1607">#00001607</color> + <color name="i_am_color_1608">#00001608</color> + <color name="i_am_color_1609">#00001609</color> + <color name="i_am_color_160a">#0000160a</color> + <color name="i_am_color_160b">#0000160b</color> + <color name="i_am_color_160c">#0000160c</color> + <color name="i_am_color_160d">#0000160d</color> + <color name="i_am_color_160e">#0000160e</color> + <color name="i_am_color_160f">#0000160f</color> + <color name="i_am_color_1610">#00001610</color> + <color name="i_am_color_1611">#00001611</color> + <color name="i_am_color_1612">#00001612</color> + <color name="i_am_color_1613">#00001613</color> + <color name="i_am_color_1614">#00001614</color> + <color name="i_am_color_1615">#00001615</color> + <color name="i_am_color_1616">#00001616</color> + <color name="i_am_color_1617">#00001617</color> + <color name="i_am_color_1618">#00001618</color> + <color name="i_am_color_1619">#00001619</color> + <color name="i_am_color_161a">#0000161a</color> + <color name="i_am_color_161b">#0000161b</color> + <color name="i_am_color_161c">#0000161c</color> + <color name="i_am_color_161d">#0000161d</color> + <color name="i_am_color_161e">#0000161e</color> + <color name="i_am_color_161f">#0000161f</color> + <color name="i_am_color_1620">#00001620</color> + <color name="i_am_color_1621">#00001621</color> + <color name="i_am_color_1622">#00001622</color> + <color name="i_am_color_1623">#00001623</color> + <color name="i_am_color_1624">#00001624</color> + <color name="i_am_color_1625">#00001625</color> + <color name="i_am_color_1626">#00001626</color> + <color name="i_am_color_1627">#00001627</color> + <color name="i_am_color_1628">#00001628</color> + <color name="i_am_color_1629">#00001629</color> + <color name="i_am_color_162a">#0000162a</color> + <color name="i_am_color_162b">#0000162b</color> + <color name="i_am_color_162c">#0000162c</color> + <color name="i_am_color_162d">#0000162d</color> + <color name="i_am_color_162e">#0000162e</color> + <color name="i_am_color_162f">#0000162f</color> + <color name="i_am_color_1630">#00001630</color> + <color name="i_am_color_1631">#00001631</color> + <color name="i_am_color_1632">#00001632</color> + <color name="i_am_color_1633">#00001633</color> + <color name="i_am_color_1634">#00001634</color> + <color name="i_am_color_1635">#00001635</color> + <color name="i_am_color_1636">#00001636</color> + <color name="i_am_color_1637">#00001637</color> + <color name="i_am_color_1638">#00001638</color> + <color name="i_am_color_1639">#00001639</color> + <color name="i_am_color_163a">#0000163a</color> + <color name="i_am_color_163b">#0000163b</color> + <color name="i_am_color_163c">#0000163c</color> + <color name="i_am_color_163d">#0000163d</color> + <color name="i_am_color_163e">#0000163e</color> + <color name="i_am_color_163f">#0000163f</color> + <color name="i_am_color_1640">#00001640</color> + <color name="i_am_color_1641">#00001641</color> + <color name="i_am_color_1642">#00001642</color> + <color name="i_am_color_1643">#00001643</color> + <color name="i_am_color_1644">#00001644</color> + <color name="i_am_color_1645">#00001645</color> + <color name="i_am_color_1646">#00001646</color> + <color name="i_am_color_1647">#00001647</color> + <color name="i_am_color_1648">#00001648</color> + <color name="i_am_color_1649">#00001649</color> + <color name="i_am_color_164a">#0000164a</color> + <color name="i_am_color_164b">#0000164b</color> + <color name="i_am_color_164c">#0000164c</color> + <color name="i_am_color_164d">#0000164d</color> + <color name="i_am_color_164e">#0000164e</color> + <color name="i_am_color_164f">#0000164f</color> + <color name="i_am_color_1650">#00001650</color> + <color name="i_am_color_1651">#00001651</color> + <color name="i_am_color_1652">#00001652</color> + <color name="i_am_color_1653">#00001653</color> + <color name="i_am_color_1654">#00001654</color> + <color name="i_am_color_1655">#00001655</color> + <color name="i_am_color_1656">#00001656</color> + <color name="i_am_color_1657">#00001657</color> + <color name="i_am_color_1658">#00001658</color> + <color name="i_am_color_1659">#00001659</color> + <color name="i_am_color_165a">#0000165a</color> + <color name="i_am_color_165b">#0000165b</color> + <color name="i_am_color_165c">#0000165c</color> + <color name="i_am_color_165d">#0000165d</color> + <color name="i_am_color_165e">#0000165e</color> + <color name="i_am_color_165f">#0000165f</color> + <color name="i_am_color_1660">#00001660</color> + <color name="i_am_color_1661">#00001661</color> + <color name="i_am_color_1662">#00001662</color> + <color name="i_am_color_1663">#00001663</color> + <color name="i_am_color_1664">#00001664</color> + <color name="i_am_color_1665">#00001665</color> + <color name="i_am_color_1666">#00001666</color> + <color name="i_am_color_1667">#00001667</color> + <color name="i_am_color_1668">#00001668</color> + <color name="i_am_color_1669">#00001669</color> + <color name="i_am_color_166a">#0000166a</color> + <color name="i_am_color_166b">#0000166b</color> + <color name="i_am_color_166c">#0000166c</color> + <color name="i_am_color_166d">#0000166d</color> + <color name="i_am_color_166e">#0000166e</color> + <color name="i_am_color_166f">#0000166f</color> + <color name="i_am_color_1670">#00001670</color> + <color name="i_am_color_1671">#00001671</color> + <color name="i_am_color_1672">#00001672</color> + <color name="i_am_color_1673">#00001673</color> + <color name="i_am_color_1674">#00001674</color> + <color name="i_am_color_1675">#00001675</color> + <color name="i_am_color_1676">#00001676</color> + <color name="i_am_color_1677">#00001677</color> + <color name="i_am_color_1678">#00001678</color> + <color name="i_am_color_1679">#00001679</color> + <color name="i_am_color_167a">#0000167a</color> + <color name="i_am_color_167b">#0000167b</color> + <color name="i_am_color_167c">#0000167c</color> + <color name="i_am_color_167d">#0000167d</color> + <color name="i_am_color_167e">#0000167e</color> + <color name="i_am_color_167f">#0000167f</color> + <color name="i_am_color_1680">#00001680</color> + <color name="i_am_color_1681">#00001681</color> + <color name="i_am_color_1682">#00001682</color> + <color name="i_am_color_1683">#00001683</color> + <color name="i_am_color_1684">#00001684</color> + <color name="i_am_color_1685">#00001685</color> + <color name="i_am_color_1686">#00001686</color> + <color name="i_am_color_1687">#00001687</color> + <color name="i_am_color_1688">#00001688</color> + <color name="i_am_color_1689">#00001689</color> + <color name="i_am_color_168a">#0000168a</color> + <color name="i_am_color_168b">#0000168b</color> + <color name="i_am_color_168c">#0000168c</color> + <color name="i_am_color_168d">#0000168d</color> + <color name="i_am_color_168e">#0000168e</color> + <color name="i_am_color_168f">#0000168f</color> + <color name="i_am_color_1690">#00001690</color> + <color name="i_am_color_1691">#00001691</color> + <color name="i_am_color_1692">#00001692</color> + <color name="i_am_color_1693">#00001693</color> + <color name="i_am_color_1694">#00001694</color> + <color name="i_am_color_1695">#00001695</color> + <color name="i_am_color_1696">#00001696</color> + <color name="i_am_color_1697">#00001697</color> + <color name="i_am_color_1698">#00001698</color> + <color name="i_am_color_1699">#00001699</color> + <color name="i_am_color_169a">#0000169a</color> + <color name="i_am_color_169b">#0000169b</color> + <color name="i_am_color_169c">#0000169c</color> + <color name="i_am_color_169d">#0000169d</color> + <color name="i_am_color_169e">#0000169e</color> + <color name="i_am_color_169f">#0000169f</color> + <color name="i_am_color_16a0">#000016a0</color> + <color name="i_am_color_16a1">#000016a1</color> + <color name="i_am_color_16a2">#000016a2</color> + <color name="i_am_color_16a3">#000016a3</color> + <color name="i_am_color_16a4">#000016a4</color> + <color name="i_am_color_16a5">#000016a5</color> + <color name="i_am_color_16a6">#000016a6</color> + <color name="i_am_color_16a7">#000016a7</color> + <color name="i_am_color_16a8">#000016a8</color> + <color name="i_am_color_16a9">#000016a9</color> + <color name="i_am_color_16aa">#000016aa</color> + <color name="i_am_color_16ab">#000016ab</color> + <color name="i_am_color_16ac">#000016ac</color> + <color name="i_am_color_16ad">#000016ad</color> + <color name="i_am_color_16ae">#000016ae</color> + <color name="i_am_color_16af">#000016af</color> + <color name="i_am_color_16b0">#000016b0</color> + <color name="i_am_color_16b1">#000016b1</color> + <color name="i_am_color_16b2">#000016b2</color> + <color name="i_am_color_16b3">#000016b3</color> + <color name="i_am_color_16b4">#000016b4</color> + <color name="i_am_color_16b5">#000016b5</color> + <color name="i_am_color_16b6">#000016b6</color> + <color name="i_am_color_16b7">#000016b7</color> + <color name="i_am_color_16b8">#000016b8</color> + <color name="i_am_color_16b9">#000016b9</color> + <color name="i_am_color_16ba">#000016ba</color> + <color name="i_am_color_16bb">#000016bb</color> + <color name="i_am_color_16bc">#000016bc</color> + <color name="i_am_color_16bd">#000016bd</color> + <color name="i_am_color_16be">#000016be</color> + <color name="i_am_color_16bf">#000016bf</color> + <color name="i_am_color_16c0">#000016c0</color> + <color name="i_am_color_16c1">#000016c1</color> + <color name="i_am_color_16c2">#000016c2</color> + <color name="i_am_color_16c3">#000016c3</color> + <color name="i_am_color_16c4">#000016c4</color> + <color name="i_am_color_16c5">#000016c5</color> + <color name="i_am_color_16c6">#000016c6</color> + <color name="i_am_color_16c7">#000016c7</color> + <color name="i_am_color_16c8">#000016c8</color> + <color name="i_am_color_16c9">#000016c9</color> + <color name="i_am_color_16ca">#000016ca</color> + <color name="i_am_color_16cb">#000016cb</color> + <color name="i_am_color_16cc">#000016cc</color> + <color name="i_am_color_16cd">#000016cd</color> + <color name="i_am_color_16ce">#000016ce</color> + <color name="i_am_color_16cf">#000016cf</color> + <color name="i_am_color_16d0">#000016d0</color> + <color name="i_am_color_16d1">#000016d1</color> + <color name="i_am_color_16d2">#000016d2</color> + <color name="i_am_color_16d3">#000016d3</color> + <color name="i_am_color_16d4">#000016d4</color> + <color name="i_am_color_16d5">#000016d5</color> + <color name="i_am_color_16d6">#000016d6</color> + <color name="i_am_color_16d7">#000016d7</color> + <color name="i_am_color_16d8">#000016d8</color> + <color name="i_am_color_16d9">#000016d9</color> + <color name="i_am_color_16da">#000016da</color> + <color name="i_am_color_16db">#000016db</color> + <color name="i_am_color_16dc">#000016dc</color> + <color name="i_am_color_16dd">#000016dd</color> + <color name="i_am_color_16de">#000016de</color> + <color name="i_am_color_16df">#000016df</color> + <color name="i_am_color_16e0">#000016e0</color> + <color name="i_am_color_16e1">#000016e1</color> + <color name="i_am_color_16e2">#000016e2</color> + <color name="i_am_color_16e3">#000016e3</color> + <color name="i_am_color_16e4">#000016e4</color> + <color name="i_am_color_16e5">#000016e5</color> + <color name="i_am_color_16e6">#000016e6</color> + <color name="i_am_color_16e7">#000016e7</color> + <color name="i_am_color_16e8">#000016e8</color> + <color name="i_am_color_16e9">#000016e9</color> + <color name="i_am_color_16ea">#000016ea</color> + <color name="i_am_color_16eb">#000016eb</color> + <color name="i_am_color_16ec">#000016ec</color> + <color name="i_am_color_16ed">#000016ed</color> + <color name="i_am_color_16ee">#000016ee</color> + <color name="i_am_color_16ef">#000016ef</color> + <color name="i_am_color_16f0">#000016f0</color> + <color name="i_am_color_16f1">#000016f1</color> + <color name="i_am_color_16f2">#000016f2</color> + <color name="i_am_color_16f3">#000016f3</color> + <color name="i_am_color_16f4">#000016f4</color> + <color name="i_am_color_16f5">#000016f5</color> + <color name="i_am_color_16f6">#000016f6</color> + <color name="i_am_color_16f7">#000016f7</color> + <color name="i_am_color_16f8">#000016f8</color> + <color name="i_am_color_16f9">#000016f9</color> + <color name="i_am_color_16fa">#000016fa</color> + <color name="i_am_color_16fb">#000016fb</color> + <color name="i_am_color_16fc">#000016fc</color> + <color name="i_am_color_16fd">#000016fd</color> + <color name="i_am_color_16fe">#000016fe</color> + <color name="i_am_color_16ff">#000016ff</color> + <color name="i_am_color_1700">#00001700</color> + <color name="i_am_color_1701">#00001701</color> + <color name="i_am_color_1702">#00001702</color> + <color name="i_am_color_1703">#00001703</color> + <color name="i_am_color_1704">#00001704</color> + <color name="i_am_color_1705">#00001705</color> + <color name="i_am_color_1706">#00001706</color> + <color name="i_am_color_1707">#00001707</color> + <color name="i_am_color_1708">#00001708</color> + <color name="i_am_color_1709">#00001709</color> + <color name="i_am_color_170a">#0000170a</color> + <color name="i_am_color_170b">#0000170b</color> + <color name="i_am_color_170c">#0000170c</color> + <color name="i_am_color_170d">#0000170d</color> + <color name="i_am_color_170e">#0000170e</color> + <color name="i_am_color_170f">#0000170f</color> + <color name="i_am_color_1710">#00001710</color> + <color name="i_am_color_1711">#00001711</color> + <color name="i_am_color_1712">#00001712</color> + <color name="i_am_color_1713">#00001713</color> + <color name="i_am_color_1714">#00001714</color> + <color name="i_am_color_1715">#00001715</color> + <color name="i_am_color_1716">#00001716</color> + <color name="i_am_color_1717">#00001717</color> + <color name="i_am_color_1718">#00001718</color> + <color name="i_am_color_1719">#00001719</color> + <color name="i_am_color_171a">#0000171a</color> + <color name="i_am_color_171b">#0000171b</color> + <color name="i_am_color_171c">#0000171c</color> + <color name="i_am_color_171d">#0000171d</color> + <color name="i_am_color_171e">#0000171e</color> + <color name="i_am_color_171f">#0000171f</color> + <color name="i_am_color_1720">#00001720</color> + <color name="i_am_color_1721">#00001721</color> + <color name="i_am_color_1722">#00001722</color> + <color name="i_am_color_1723">#00001723</color> + <color name="i_am_color_1724">#00001724</color> + <color name="i_am_color_1725">#00001725</color> + <color name="i_am_color_1726">#00001726</color> + <color name="i_am_color_1727">#00001727</color> + <color name="i_am_color_1728">#00001728</color> + <color name="i_am_color_1729">#00001729</color> + <color name="i_am_color_172a">#0000172a</color> + <color name="i_am_color_172b">#0000172b</color> + <color name="i_am_color_172c">#0000172c</color> + <color name="i_am_color_172d">#0000172d</color> + <color name="i_am_color_172e">#0000172e</color> + <color name="i_am_color_172f">#0000172f</color> + <color name="i_am_color_1730">#00001730</color> + <color name="i_am_color_1731">#00001731</color> + <color name="i_am_color_1732">#00001732</color> + <color name="i_am_color_1733">#00001733</color> + <color name="i_am_color_1734">#00001734</color> + <color name="i_am_color_1735">#00001735</color> + <color name="i_am_color_1736">#00001736</color> + <color name="i_am_color_1737">#00001737</color> + <color name="i_am_color_1738">#00001738</color> + <color name="i_am_color_1739">#00001739</color> + <color name="i_am_color_173a">#0000173a</color> + <color name="i_am_color_173b">#0000173b</color> + <color name="i_am_color_173c">#0000173c</color> + <color name="i_am_color_173d">#0000173d</color> + <color name="i_am_color_173e">#0000173e</color> + <color name="i_am_color_173f">#0000173f</color> + <color name="i_am_color_1740">#00001740</color> + <color name="i_am_color_1741">#00001741</color> + <color name="i_am_color_1742">#00001742</color> + <color name="i_am_color_1743">#00001743</color> + <color name="i_am_color_1744">#00001744</color> + <color name="i_am_color_1745">#00001745</color> + <color name="i_am_color_1746">#00001746</color> + <color name="i_am_color_1747">#00001747</color> + <color name="i_am_color_1748">#00001748</color> + <color name="i_am_color_1749">#00001749</color> + <color name="i_am_color_174a">#0000174a</color> + <color name="i_am_color_174b">#0000174b</color> + <color name="i_am_color_174c">#0000174c</color> + <color name="i_am_color_174d">#0000174d</color> + <color name="i_am_color_174e">#0000174e</color> + <color name="i_am_color_174f">#0000174f</color> + <color name="i_am_color_1750">#00001750</color> + <color name="i_am_color_1751">#00001751</color> + <color name="i_am_color_1752">#00001752</color> + <color name="i_am_color_1753">#00001753</color> + <color name="i_am_color_1754">#00001754</color> + <color name="i_am_color_1755">#00001755</color> + <color name="i_am_color_1756">#00001756</color> + <color name="i_am_color_1757">#00001757</color> + <color name="i_am_color_1758">#00001758</color> + <color name="i_am_color_1759">#00001759</color> + <color name="i_am_color_175a">#0000175a</color> + <color name="i_am_color_175b">#0000175b</color> + <color name="i_am_color_175c">#0000175c</color> + <color name="i_am_color_175d">#0000175d</color> + <color name="i_am_color_175e">#0000175e</color> + <color name="i_am_color_175f">#0000175f</color> + <color name="i_am_color_1760">#00001760</color> + <color name="i_am_color_1761">#00001761</color> + <color name="i_am_color_1762">#00001762</color> + <color name="i_am_color_1763">#00001763</color> + <color name="i_am_color_1764">#00001764</color> + <color name="i_am_color_1765">#00001765</color> + <color name="i_am_color_1766">#00001766</color> + <color name="i_am_color_1767">#00001767</color> + <color name="i_am_color_1768">#00001768</color> + <color name="i_am_color_1769">#00001769</color> + <color name="i_am_color_176a">#0000176a</color> + <color name="i_am_color_176b">#0000176b</color> + <color name="i_am_color_176c">#0000176c</color> + <color name="i_am_color_176d">#0000176d</color> + <color name="i_am_color_176e">#0000176e</color> + <color name="i_am_color_176f">#0000176f</color> + <color name="i_am_color_1770">#00001770</color> + <color name="i_am_color_1771">#00001771</color> + <color name="i_am_color_1772">#00001772</color> + <color name="i_am_color_1773">#00001773</color> + <color name="i_am_color_1774">#00001774</color> + <color name="i_am_color_1775">#00001775</color> + <color name="i_am_color_1776">#00001776</color> + <color name="i_am_color_1777">#00001777</color> + <color name="i_am_color_1778">#00001778</color> + <color name="i_am_color_1779">#00001779</color> + <color name="i_am_color_177a">#0000177a</color> + <color name="i_am_color_177b">#0000177b</color> + <color name="i_am_color_177c">#0000177c</color> + <color name="i_am_color_177d">#0000177d</color> + <color name="i_am_color_177e">#0000177e</color> + <color name="i_am_color_177f">#0000177f</color> + <color name="i_am_color_1780">#00001780</color> + <color name="i_am_color_1781">#00001781</color> + <color name="i_am_color_1782">#00001782</color> + <color name="i_am_color_1783">#00001783</color> + <color name="i_am_color_1784">#00001784</color> + <color name="i_am_color_1785">#00001785</color> + <color name="i_am_color_1786">#00001786</color> + <color name="i_am_color_1787">#00001787</color> + <color name="i_am_color_1788">#00001788</color> + <color name="i_am_color_1789">#00001789</color> + <color name="i_am_color_178a">#0000178a</color> + <color name="i_am_color_178b">#0000178b</color> + <color name="i_am_color_178c">#0000178c</color> + <color name="i_am_color_178d">#0000178d</color> + <color name="i_am_color_178e">#0000178e</color> + <color name="i_am_color_178f">#0000178f</color> + <color name="i_am_color_1790">#00001790</color> + <color name="i_am_color_1791">#00001791</color> + <color name="i_am_color_1792">#00001792</color> + <color name="i_am_color_1793">#00001793</color> + <color name="i_am_color_1794">#00001794</color> + <color name="i_am_color_1795">#00001795</color> + <color name="i_am_color_1796">#00001796</color> + <color name="i_am_color_1797">#00001797</color> + <color name="i_am_color_1798">#00001798</color> + <color name="i_am_color_1799">#00001799</color> + <color name="i_am_color_179a">#0000179a</color> + <color name="i_am_color_179b">#0000179b</color> + <color name="i_am_color_179c">#0000179c</color> + <color name="i_am_color_179d">#0000179d</color> + <color name="i_am_color_179e">#0000179e</color> + <color name="i_am_color_179f">#0000179f</color> + <color name="i_am_color_17a0">#000017a0</color> + <color name="i_am_color_17a1">#000017a1</color> + <color name="i_am_color_17a2">#000017a2</color> + <color name="i_am_color_17a3">#000017a3</color> + <color name="i_am_color_17a4">#000017a4</color> + <color name="i_am_color_17a5">#000017a5</color> + <color name="i_am_color_17a6">#000017a6</color> + <color name="i_am_color_17a7">#000017a7</color> + <color name="i_am_color_17a8">#000017a8</color> + <color name="i_am_color_17a9">#000017a9</color> + <color name="i_am_color_17aa">#000017aa</color> + <color name="i_am_color_17ab">#000017ab</color> + <color name="i_am_color_17ac">#000017ac</color> + <color name="i_am_color_17ad">#000017ad</color> + <color name="i_am_color_17ae">#000017ae</color> + <color name="i_am_color_17af">#000017af</color> + <color name="i_am_color_17b0">#000017b0</color> + <color name="i_am_color_17b1">#000017b1</color> + <color name="i_am_color_17b2">#000017b2</color> + <color name="i_am_color_17b3">#000017b3</color> + <color name="i_am_color_17b4">#000017b4</color> + <color name="i_am_color_17b5">#000017b5</color> + <color name="i_am_color_17b6">#000017b6</color> + <color name="i_am_color_17b7">#000017b7</color> + <color name="i_am_color_17b8">#000017b8</color> + <color name="i_am_color_17b9">#000017b9</color> + <color name="i_am_color_17ba">#000017ba</color> + <color name="i_am_color_17bb">#000017bb</color> + <color name="i_am_color_17bc">#000017bc</color> + <color name="i_am_color_17bd">#000017bd</color> + <color name="i_am_color_17be">#000017be</color> + <color name="i_am_color_17bf">#000017bf</color> + <color name="i_am_color_17c0">#000017c0</color> + <color name="i_am_color_17c1">#000017c1</color> + <color name="i_am_color_17c2">#000017c2</color> + <color name="i_am_color_17c3">#000017c3</color> + <color name="i_am_color_17c4">#000017c4</color> + <color name="i_am_color_17c5">#000017c5</color> + <color name="i_am_color_17c6">#000017c6</color> + <color name="i_am_color_17c7">#000017c7</color> + <color name="i_am_color_17c8">#000017c8</color> + <color name="i_am_color_17c9">#000017c9</color> + <color name="i_am_color_17ca">#000017ca</color> + <color name="i_am_color_17cb">#000017cb</color> + <color name="i_am_color_17cc">#000017cc</color> + <color name="i_am_color_17cd">#000017cd</color> + <color name="i_am_color_17ce">#000017ce</color> + <color name="i_am_color_17cf">#000017cf</color> + <color name="i_am_color_17d0">#000017d0</color> + <color name="i_am_color_17d1">#000017d1</color> + <color name="i_am_color_17d2">#000017d2</color> + <color name="i_am_color_17d3">#000017d3</color> + <color name="i_am_color_17d4">#000017d4</color> + <color name="i_am_color_17d5">#000017d5</color> + <color name="i_am_color_17d6">#000017d6</color> + <color name="i_am_color_17d7">#000017d7</color> + <color name="i_am_color_17d8">#000017d8</color> + <color name="i_am_color_17d9">#000017d9</color> + <color name="i_am_color_17da">#000017da</color> + <color name="i_am_color_17db">#000017db</color> + <color name="i_am_color_17dc">#000017dc</color> + <color name="i_am_color_17dd">#000017dd</color> + <color name="i_am_color_17de">#000017de</color> + <color name="i_am_color_17df">#000017df</color> + <color name="i_am_color_17e0">#000017e0</color> + <color name="i_am_color_17e1">#000017e1</color> + <color name="i_am_color_17e2">#000017e2</color> + <color name="i_am_color_17e3">#000017e3</color> + <color name="i_am_color_17e4">#000017e4</color> + <color name="i_am_color_17e5">#000017e5</color> + <color name="i_am_color_17e6">#000017e6</color> + <color name="i_am_color_17e7">#000017e7</color> + <color name="i_am_color_17e8">#000017e8</color> + <color name="i_am_color_17e9">#000017e9</color> + <color name="i_am_color_17ea">#000017ea</color> + <color name="i_am_color_17eb">#000017eb</color> + <color name="i_am_color_17ec">#000017ec</color> + <color name="i_am_color_17ed">#000017ed</color> + <color name="i_am_color_17ee">#000017ee</color> + <color name="i_am_color_17ef">#000017ef</color> + <color name="i_am_color_17f0">#000017f0</color> + <color name="i_am_color_17f1">#000017f1</color> + <color name="i_am_color_17f2">#000017f2</color> + <color name="i_am_color_17f3">#000017f3</color> + <color name="i_am_color_17f4">#000017f4</color> + <color name="i_am_color_17f5">#000017f5</color> + <color name="i_am_color_17f6">#000017f6</color> + <color name="i_am_color_17f7">#000017f7</color> + <color name="i_am_color_17f8">#000017f8</color> + <color name="i_am_color_17f9">#000017f9</color> + <color name="i_am_color_17fa">#000017fa</color> + <color name="i_am_color_17fb">#000017fb</color> + <color name="i_am_color_17fc">#000017fc</color> + <color name="i_am_color_17fd">#000017fd</color> + <color name="i_am_color_17fe">#000017fe</color> + <color name="i_am_color_17ff">#000017ff</color> + <color name="i_am_color_1800">#00001800</color> + <color name="i_am_color_1801">#00001801</color> + <color name="i_am_color_1802">#00001802</color> + <color name="i_am_color_1803">#00001803</color> + <color name="i_am_color_1804">#00001804</color> + <color name="i_am_color_1805">#00001805</color> + <color name="i_am_color_1806">#00001806</color> + <color name="i_am_color_1807">#00001807</color> + <color name="i_am_color_1808">#00001808</color> + <color name="i_am_color_1809">#00001809</color> + <color name="i_am_color_180a">#0000180a</color> + <color name="i_am_color_180b">#0000180b</color> + <color name="i_am_color_180c">#0000180c</color> + <color name="i_am_color_180d">#0000180d</color> + <color name="i_am_color_180e">#0000180e</color> + <color name="i_am_color_180f">#0000180f</color> + <color name="i_am_color_1810">#00001810</color> + <color name="i_am_color_1811">#00001811</color> + <color name="i_am_color_1812">#00001812</color> + <color name="i_am_color_1813">#00001813</color> + <color name="i_am_color_1814">#00001814</color> + <color name="i_am_color_1815">#00001815</color> + <color name="i_am_color_1816">#00001816</color> + <color name="i_am_color_1817">#00001817</color> + <color name="i_am_color_1818">#00001818</color> + <color name="i_am_color_1819">#00001819</color> + <color name="i_am_color_181a">#0000181a</color> + <color name="i_am_color_181b">#0000181b</color> + <color name="i_am_color_181c">#0000181c</color> + <color name="i_am_color_181d">#0000181d</color> + <color name="i_am_color_181e">#0000181e</color> + <color name="i_am_color_181f">#0000181f</color> + <color name="i_am_color_1820">#00001820</color> + <color name="i_am_color_1821">#00001821</color> + <color name="i_am_color_1822">#00001822</color> + <color name="i_am_color_1823">#00001823</color> + <color name="i_am_color_1824">#00001824</color> + <color name="i_am_color_1825">#00001825</color> + <color name="i_am_color_1826">#00001826</color> + <color name="i_am_color_1827">#00001827</color> + <color name="i_am_color_1828">#00001828</color> + <color name="i_am_color_1829">#00001829</color> + <color name="i_am_color_182a">#0000182a</color> + <color name="i_am_color_182b">#0000182b</color> + <color name="i_am_color_182c">#0000182c</color> + <color name="i_am_color_182d">#0000182d</color> + <color name="i_am_color_182e">#0000182e</color> + <color name="i_am_color_182f">#0000182f</color> + <color name="i_am_color_1830">#00001830</color> + <color name="i_am_color_1831">#00001831</color> + <color name="i_am_color_1832">#00001832</color> + <color name="i_am_color_1833">#00001833</color> + <color name="i_am_color_1834">#00001834</color> + <color name="i_am_color_1835">#00001835</color> + <color name="i_am_color_1836">#00001836</color> + <color name="i_am_color_1837">#00001837</color> + <color name="i_am_color_1838">#00001838</color> + <color name="i_am_color_1839">#00001839</color> + <color name="i_am_color_183a">#0000183a</color> + <color name="i_am_color_183b">#0000183b</color> + <color name="i_am_color_183c">#0000183c</color> + <color name="i_am_color_183d">#0000183d</color> + <color name="i_am_color_183e">#0000183e</color> + <color name="i_am_color_183f">#0000183f</color> + <color name="i_am_color_1840">#00001840</color> + <color name="i_am_color_1841">#00001841</color> + <color name="i_am_color_1842">#00001842</color> + <color name="i_am_color_1843">#00001843</color> + <color name="i_am_color_1844">#00001844</color> + <color name="i_am_color_1845">#00001845</color> + <color name="i_am_color_1846">#00001846</color> + <color name="i_am_color_1847">#00001847</color> + <color name="i_am_color_1848">#00001848</color> + <color name="i_am_color_1849">#00001849</color> + <color name="i_am_color_184a">#0000184a</color> + <color name="i_am_color_184b">#0000184b</color> + <color name="i_am_color_184c">#0000184c</color> + <color name="i_am_color_184d">#0000184d</color> + <color name="i_am_color_184e">#0000184e</color> + <color name="i_am_color_184f">#0000184f</color> + <color name="i_am_color_1850">#00001850</color> + <color name="i_am_color_1851">#00001851</color> + <color name="i_am_color_1852">#00001852</color> + <color name="i_am_color_1853">#00001853</color> + <color name="i_am_color_1854">#00001854</color> + <color name="i_am_color_1855">#00001855</color> + <color name="i_am_color_1856">#00001856</color> + <color name="i_am_color_1857">#00001857</color> + <color name="i_am_color_1858">#00001858</color> + <color name="i_am_color_1859">#00001859</color> + <color name="i_am_color_185a">#0000185a</color> + <color name="i_am_color_185b">#0000185b</color> + <color name="i_am_color_185c">#0000185c</color> + <color name="i_am_color_185d">#0000185d</color> + <color name="i_am_color_185e">#0000185e</color> + <color name="i_am_color_185f">#0000185f</color> + <color name="i_am_color_1860">#00001860</color> + <color name="i_am_color_1861">#00001861</color> + <color name="i_am_color_1862">#00001862</color> + <color name="i_am_color_1863">#00001863</color> + <color name="i_am_color_1864">#00001864</color> + <color name="i_am_color_1865">#00001865</color> + <color name="i_am_color_1866">#00001866</color> + <color name="i_am_color_1867">#00001867</color> + <color name="i_am_color_1868">#00001868</color> + <color name="i_am_color_1869">#00001869</color> + <color name="i_am_color_186a">#0000186a</color> + <color name="i_am_color_186b">#0000186b</color> + <color name="i_am_color_186c">#0000186c</color> + <color name="i_am_color_186d">#0000186d</color> + <color name="i_am_color_186e">#0000186e</color> + <color name="i_am_color_186f">#0000186f</color> + <color name="i_am_color_1870">#00001870</color> + <color name="i_am_color_1871">#00001871</color> + <color name="i_am_color_1872">#00001872</color> + <color name="i_am_color_1873">#00001873</color> + <color name="i_am_color_1874">#00001874</color> + <color name="i_am_color_1875">#00001875</color> + <color name="i_am_color_1876">#00001876</color> + <color name="i_am_color_1877">#00001877</color> + <color name="i_am_color_1878">#00001878</color> + <color name="i_am_color_1879">#00001879</color> + <color name="i_am_color_187a">#0000187a</color> + <color name="i_am_color_187b">#0000187b</color> + <color name="i_am_color_187c">#0000187c</color> + <color name="i_am_color_187d">#0000187d</color> + <color name="i_am_color_187e">#0000187e</color> + <color name="i_am_color_187f">#0000187f</color> + <color name="i_am_color_1880">#00001880</color> + <color name="i_am_color_1881">#00001881</color> + <color name="i_am_color_1882">#00001882</color> + <color name="i_am_color_1883">#00001883</color> + <color name="i_am_color_1884">#00001884</color> + <color name="i_am_color_1885">#00001885</color> + <color name="i_am_color_1886">#00001886</color> + <color name="i_am_color_1887">#00001887</color> + <color name="i_am_color_1888">#00001888</color> + <color name="i_am_color_1889">#00001889</color> + <color name="i_am_color_188a">#0000188a</color> + <color name="i_am_color_188b">#0000188b</color> + <color name="i_am_color_188c">#0000188c</color> + <color name="i_am_color_188d">#0000188d</color> + <color name="i_am_color_188e">#0000188e</color> + <color name="i_am_color_188f">#0000188f</color> + <color name="i_am_color_1890">#00001890</color> + <color name="i_am_color_1891">#00001891</color> + <color name="i_am_color_1892">#00001892</color> + <color name="i_am_color_1893">#00001893</color> + <color name="i_am_color_1894">#00001894</color> + <color name="i_am_color_1895">#00001895</color> + <color name="i_am_color_1896">#00001896</color> + <color name="i_am_color_1897">#00001897</color> + <color name="i_am_color_1898">#00001898</color> + <color name="i_am_color_1899">#00001899</color> + <color name="i_am_color_189a">#0000189a</color> + <color name="i_am_color_189b">#0000189b</color> + <color name="i_am_color_189c">#0000189c</color> + <color name="i_am_color_189d">#0000189d</color> + <color name="i_am_color_189e">#0000189e</color> + <color name="i_am_color_189f">#0000189f</color> + <color name="i_am_color_18a0">#000018a0</color> + <color name="i_am_color_18a1">#000018a1</color> + <color name="i_am_color_18a2">#000018a2</color> + <color name="i_am_color_18a3">#000018a3</color> + <color name="i_am_color_18a4">#000018a4</color> + <color name="i_am_color_18a5">#000018a5</color> + <color name="i_am_color_18a6">#000018a6</color> + <color name="i_am_color_18a7">#000018a7</color> + <color name="i_am_color_18a8">#000018a8</color> + <color name="i_am_color_18a9">#000018a9</color> + <color name="i_am_color_18aa">#000018aa</color> + <color name="i_am_color_18ab">#000018ab</color> + <color name="i_am_color_18ac">#000018ac</color> + <color name="i_am_color_18ad">#000018ad</color> + <color name="i_am_color_18ae">#000018ae</color> + <color name="i_am_color_18af">#000018af</color> + <color name="i_am_color_18b0">#000018b0</color> + <color name="i_am_color_18b1">#000018b1</color> + <color name="i_am_color_18b2">#000018b2</color> + <color name="i_am_color_18b3">#000018b3</color> + <color name="i_am_color_18b4">#000018b4</color> + <color name="i_am_color_18b5">#000018b5</color> + <color name="i_am_color_18b6">#000018b6</color> + <color name="i_am_color_18b7">#000018b7</color> + <color name="i_am_color_18b8">#000018b8</color> + <color name="i_am_color_18b9">#000018b9</color> + <color name="i_am_color_18ba">#000018ba</color> + <color name="i_am_color_18bb">#000018bb</color> + <color name="i_am_color_18bc">#000018bc</color> + <color name="i_am_color_18bd">#000018bd</color> + <color name="i_am_color_18be">#000018be</color> + <color name="i_am_color_18bf">#000018bf</color> + <color name="i_am_color_18c0">#000018c0</color> + <color name="i_am_color_18c1">#000018c1</color> + <color name="i_am_color_18c2">#000018c2</color> + <color name="i_am_color_18c3">#000018c3</color> + <color name="i_am_color_18c4">#000018c4</color> + <color name="i_am_color_18c5">#000018c5</color> + <color name="i_am_color_18c6">#000018c6</color> + <color name="i_am_color_18c7">#000018c7</color> + <color name="i_am_color_18c8">#000018c8</color> + <color name="i_am_color_18c9">#000018c9</color> + <color name="i_am_color_18ca">#000018ca</color> + <color name="i_am_color_18cb">#000018cb</color> + <color name="i_am_color_18cc">#000018cc</color> + <color name="i_am_color_18cd">#000018cd</color> + <color name="i_am_color_18ce">#000018ce</color> + <color name="i_am_color_18cf">#000018cf</color> + <color name="i_am_color_18d0">#000018d0</color> + <color name="i_am_color_18d1">#000018d1</color> + <color name="i_am_color_18d2">#000018d2</color> + <color name="i_am_color_18d3">#000018d3</color> + <color name="i_am_color_18d4">#000018d4</color> + <color name="i_am_color_18d5">#000018d5</color> + <color name="i_am_color_18d6">#000018d6</color> + <color name="i_am_color_18d7">#000018d7</color> + <color name="i_am_color_18d8">#000018d8</color> + <color name="i_am_color_18d9">#000018d9</color> + <color name="i_am_color_18da">#000018da</color> + <color name="i_am_color_18db">#000018db</color> + <color name="i_am_color_18dc">#000018dc</color> + <color name="i_am_color_18dd">#000018dd</color> + <color name="i_am_color_18de">#000018de</color> + <color name="i_am_color_18df">#000018df</color> + <color name="i_am_color_18e0">#000018e0</color> + <color name="i_am_color_18e1">#000018e1</color> + <color name="i_am_color_18e2">#000018e2</color> + <color name="i_am_color_18e3">#000018e3</color> + <color name="i_am_color_18e4">#000018e4</color> + <color name="i_am_color_18e5">#000018e5</color> + <color name="i_am_color_18e6">#000018e6</color> + <color name="i_am_color_18e7">#000018e7</color> + <color name="i_am_color_18e8">#000018e8</color> + <color name="i_am_color_18e9">#000018e9</color> + <color name="i_am_color_18ea">#000018ea</color> + <color name="i_am_color_18eb">#000018eb</color> + <color name="i_am_color_18ec">#000018ec</color> + <color name="i_am_color_18ed">#000018ed</color> + <color name="i_am_color_18ee">#000018ee</color> + <color name="i_am_color_18ef">#000018ef</color> + <color name="i_am_color_18f0">#000018f0</color> + <color name="i_am_color_18f1">#000018f1</color> + <color name="i_am_color_18f2">#000018f2</color> + <color name="i_am_color_18f3">#000018f3</color> + <color name="i_am_color_18f4">#000018f4</color> + <color name="i_am_color_18f5">#000018f5</color> + <color name="i_am_color_18f6">#000018f6</color> + <color name="i_am_color_18f7">#000018f7</color> + <color name="i_am_color_18f8">#000018f8</color> + <color name="i_am_color_18f9">#000018f9</color> + <color name="i_am_color_18fa">#000018fa</color> + <color name="i_am_color_18fb">#000018fb</color> + <color name="i_am_color_18fc">#000018fc</color> + <color name="i_am_color_18fd">#000018fd</color> + <color name="i_am_color_18fe">#000018fe</color> + <color name="i_am_color_18ff">#000018ff</color> + <color name="i_am_color_1900">#00001900</color> + <color name="i_am_color_1901">#00001901</color> + <color name="i_am_color_1902">#00001902</color> + <color name="i_am_color_1903">#00001903</color> + <color name="i_am_color_1904">#00001904</color> + <color name="i_am_color_1905">#00001905</color> + <color name="i_am_color_1906">#00001906</color> + <color name="i_am_color_1907">#00001907</color> + <color name="i_am_color_1908">#00001908</color> + <color name="i_am_color_1909">#00001909</color> + <color name="i_am_color_190a">#0000190a</color> + <color name="i_am_color_190b">#0000190b</color> + <color name="i_am_color_190c">#0000190c</color> + <color name="i_am_color_190d">#0000190d</color> + <color name="i_am_color_190e">#0000190e</color> + <color name="i_am_color_190f">#0000190f</color> + <color name="i_am_color_1910">#00001910</color> + <color name="i_am_color_1911">#00001911</color> + <color name="i_am_color_1912">#00001912</color> + <color name="i_am_color_1913">#00001913</color> + <color name="i_am_color_1914">#00001914</color> + <color name="i_am_color_1915">#00001915</color> + <color name="i_am_color_1916">#00001916</color> + <color name="i_am_color_1917">#00001917</color> + <color name="i_am_color_1918">#00001918</color> + <color name="i_am_color_1919">#00001919</color> + <color name="i_am_color_191a">#0000191a</color> + <color name="i_am_color_191b">#0000191b</color> + <color name="i_am_color_191c">#0000191c</color> + <color name="i_am_color_191d">#0000191d</color> + <color name="i_am_color_191e">#0000191e</color> + <color name="i_am_color_191f">#0000191f</color> + <color name="i_am_color_1920">#00001920</color> + <color name="i_am_color_1921">#00001921</color> + <color name="i_am_color_1922">#00001922</color> + <color name="i_am_color_1923">#00001923</color> + <color name="i_am_color_1924">#00001924</color> + <color name="i_am_color_1925">#00001925</color> + <color name="i_am_color_1926">#00001926</color> + <color name="i_am_color_1927">#00001927</color> + <color name="i_am_color_1928">#00001928</color> + <color name="i_am_color_1929">#00001929</color> + <color name="i_am_color_192a">#0000192a</color> + <color name="i_am_color_192b">#0000192b</color> + <color name="i_am_color_192c">#0000192c</color> + <color name="i_am_color_192d">#0000192d</color> + <color name="i_am_color_192e">#0000192e</color> + <color name="i_am_color_192f">#0000192f</color> + <color name="i_am_color_1930">#00001930</color> + <color name="i_am_color_1931">#00001931</color> + <color name="i_am_color_1932">#00001932</color> + <color name="i_am_color_1933">#00001933</color> + <color name="i_am_color_1934">#00001934</color> + <color name="i_am_color_1935">#00001935</color> + <color name="i_am_color_1936">#00001936</color> + <color name="i_am_color_1937">#00001937</color> + <color name="i_am_color_1938">#00001938</color> + <color name="i_am_color_1939">#00001939</color> + <color name="i_am_color_193a">#0000193a</color> + <color name="i_am_color_193b">#0000193b</color> + <color name="i_am_color_193c">#0000193c</color> + <color name="i_am_color_193d">#0000193d</color> + <color name="i_am_color_193e">#0000193e</color> + <color name="i_am_color_193f">#0000193f</color> + <color name="i_am_color_1940">#00001940</color> + <color name="i_am_color_1941">#00001941</color> + <color name="i_am_color_1942">#00001942</color> + <color name="i_am_color_1943">#00001943</color> + <color name="i_am_color_1944">#00001944</color> + <color name="i_am_color_1945">#00001945</color> + <color name="i_am_color_1946">#00001946</color> + <color name="i_am_color_1947">#00001947</color> + <color name="i_am_color_1948">#00001948</color> + <color name="i_am_color_1949">#00001949</color> + <color name="i_am_color_194a">#0000194a</color> + <color name="i_am_color_194b">#0000194b</color> + <color name="i_am_color_194c">#0000194c</color> + <color name="i_am_color_194d">#0000194d</color> + <color name="i_am_color_194e">#0000194e</color> + <color name="i_am_color_194f">#0000194f</color> + <color name="i_am_color_1950">#00001950</color> + <color name="i_am_color_1951">#00001951</color> + <color name="i_am_color_1952">#00001952</color> + <color name="i_am_color_1953">#00001953</color> + <color name="i_am_color_1954">#00001954</color> + <color name="i_am_color_1955">#00001955</color> + <color name="i_am_color_1956">#00001956</color> + <color name="i_am_color_1957">#00001957</color> + <color name="i_am_color_1958">#00001958</color> + <color name="i_am_color_1959">#00001959</color> + <color name="i_am_color_195a">#0000195a</color> + <color name="i_am_color_195b">#0000195b</color> + <color name="i_am_color_195c">#0000195c</color> + <color name="i_am_color_195d">#0000195d</color> + <color name="i_am_color_195e">#0000195e</color> + <color name="i_am_color_195f">#0000195f</color> + <color name="i_am_color_1960">#00001960</color> + <color name="i_am_color_1961">#00001961</color> + <color name="i_am_color_1962">#00001962</color> + <color name="i_am_color_1963">#00001963</color> + <color name="i_am_color_1964">#00001964</color> + <color name="i_am_color_1965">#00001965</color> + <color name="i_am_color_1966">#00001966</color> + <color name="i_am_color_1967">#00001967</color> + <color name="i_am_color_1968">#00001968</color> + <color name="i_am_color_1969">#00001969</color> + <color name="i_am_color_196a">#0000196a</color> + <color name="i_am_color_196b">#0000196b</color> + <color name="i_am_color_196c">#0000196c</color> + <color name="i_am_color_196d">#0000196d</color> + <color name="i_am_color_196e">#0000196e</color> + <color name="i_am_color_196f">#0000196f</color> + <color name="i_am_color_1970">#00001970</color> + <color name="i_am_color_1971">#00001971</color> + <color name="i_am_color_1972">#00001972</color> + <color name="i_am_color_1973">#00001973</color> + <color name="i_am_color_1974">#00001974</color> + <color name="i_am_color_1975">#00001975</color> + <color name="i_am_color_1976">#00001976</color> + <color name="i_am_color_1977">#00001977</color> + <color name="i_am_color_1978">#00001978</color> + <color name="i_am_color_1979">#00001979</color> + <color name="i_am_color_197a">#0000197a</color> + <color name="i_am_color_197b">#0000197b</color> + <color name="i_am_color_197c">#0000197c</color> + <color name="i_am_color_197d">#0000197d</color> + <color name="i_am_color_197e">#0000197e</color> + <color name="i_am_color_197f">#0000197f</color> + <color name="i_am_color_1980">#00001980</color> + <color name="i_am_color_1981">#00001981</color> + <color name="i_am_color_1982">#00001982</color> + <color name="i_am_color_1983">#00001983</color> + <color name="i_am_color_1984">#00001984</color> + <color name="i_am_color_1985">#00001985</color> + <color name="i_am_color_1986">#00001986</color> + <color name="i_am_color_1987">#00001987</color> + <color name="i_am_color_1988">#00001988</color> + <color name="i_am_color_1989">#00001989</color> + <color name="i_am_color_198a">#0000198a</color> + <color name="i_am_color_198b">#0000198b</color> + <color name="i_am_color_198c">#0000198c</color> + <color name="i_am_color_198d">#0000198d</color> + <color name="i_am_color_198e">#0000198e</color> + <color name="i_am_color_198f">#0000198f</color> + <color name="i_am_color_1990">#00001990</color> + <color name="i_am_color_1991">#00001991</color> + <color name="i_am_color_1992">#00001992</color> + <color name="i_am_color_1993">#00001993</color> + <color name="i_am_color_1994">#00001994</color> + <color name="i_am_color_1995">#00001995</color> + <color name="i_am_color_1996">#00001996</color> + <color name="i_am_color_1997">#00001997</color> + <color name="i_am_color_1998">#00001998</color> + <color name="i_am_color_1999">#00001999</color> + <color name="i_am_color_199a">#0000199a</color> + <color name="i_am_color_199b">#0000199b</color> + <color name="i_am_color_199c">#0000199c</color> + <color name="i_am_color_199d">#0000199d</color> + <color name="i_am_color_199e">#0000199e</color> + <color name="i_am_color_199f">#0000199f</color> + <color name="i_am_color_19a0">#000019a0</color> + <color name="i_am_color_19a1">#000019a1</color> + <color name="i_am_color_19a2">#000019a2</color> + <color name="i_am_color_19a3">#000019a3</color> + <color name="i_am_color_19a4">#000019a4</color> + <color name="i_am_color_19a5">#000019a5</color> + <color name="i_am_color_19a6">#000019a6</color> + <color name="i_am_color_19a7">#000019a7</color> + <color name="i_am_color_19a8">#000019a8</color> + <color name="i_am_color_19a9">#000019a9</color> + <color name="i_am_color_19aa">#000019aa</color> + <color name="i_am_color_19ab">#000019ab</color> + <color name="i_am_color_19ac">#000019ac</color> + <color name="i_am_color_19ad">#000019ad</color> + <color name="i_am_color_19ae">#000019ae</color> + <color name="i_am_color_19af">#000019af</color> + <color name="i_am_color_19b0">#000019b0</color> + <color name="i_am_color_19b1">#000019b1</color> + <color name="i_am_color_19b2">#000019b2</color> + <color name="i_am_color_19b3">#000019b3</color> + <color name="i_am_color_19b4">#000019b4</color> + <color name="i_am_color_19b5">#000019b5</color> + <color name="i_am_color_19b6">#000019b6</color> + <color name="i_am_color_19b7">#000019b7</color> + <color name="i_am_color_19b8">#000019b8</color> + <color name="i_am_color_19b9">#000019b9</color> + <color name="i_am_color_19ba">#000019ba</color> + <color name="i_am_color_19bb">#000019bb</color> + <color name="i_am_color_19bc">#000019bc</color> + <color name="i_am_color_19bd">#000019bd</color> + <color name="i_am_color_19be">#000019be</color> + <color name="i_am_color_19bf">#000019bf</color> + <color name="i_am_color_19c0">#000019c0</color> + <color name="i_am_color_19c1">#000019c1</color> + <color name="i_am_color_19c2">#000019c2</color> + <color name="i_am_color_19c3">#000019c3</color> + <color name="i_am_color_19c4">#000019c4</color> + <color name="i_am_color_19c5">#000019c5</color> + <color name="i_am_color_19c6">#000019c6</color> + <color name="i_am_color_19c7">#000019c7</color> + <color name="i_am_color_19c8">#000019c8</color> + <color name="i_am_color_19c9">#000019c9</color> + <color name="i_am_color_19ca">#000019ca</color> + <color name="i_am_color_19cb">#000019cb</color> + <color name="i_am_color_19cc">#000019cc</color> + <color name="i_am_color_19cd">#000019cd</color> + <color name="i_am_color_19ce">#000019ce</color> + <color name="i_am_color_19cf">#000019cf</color> + <color name="i_am_color_19d0">#000019d0</color> + <color name="i_am_color_19d1">#000019d1</color> + <color name="i_am_color_19d2">#000019d2</color> + <color name="i_am_color_19d3">#000019d3</color> + <color name="i_am_color_19d4">#000019d4</color> + <color name="i_am_color_19d5">#000019d5</color> + <color name="i_am_color_19d6">#000019d6</color> + <color name="i_am_color_19d7">#000019d7</color> + <color name="i_am_color_19d8">#000019d8</color> + <color name="i_am_color_19d9">#000019d9</color> + <color name="i_am_color_19da">#000019da</color> + <color name="i_am_color_19db">#000019db</color> + <color name="i_am_color_19dc">#000019dc</color> + <color name="i_am_color_19dd">#000019dd</color> + <color name="i_am_color_19de">#000019de</color> + <color name="i_am_color_19df">#000019df</color> + <color name="i_am_color_19e0">#000019e0</color> + <color name="i_am_color_19e1">#000019e1</color> + <color name="i_am_color_19e2">#000019e2</color> + <color name="i_am_color_19e3">#000019e3</color> + <color name="i_am_color_19e4">#000019e4</color> + <color name="i_am_color_19e5">#000019e5</color> + <color name="i_am_color_19e6">#000019e6</color> + <color name="i_am_color_19e7">#000019e7</color> + <color name="i_am_color_19e8">#000019e8</color> + <color name="i_am_color_19e9">#000019e9</color> + <color name="i_am_color_19ea">#000019ea</color> + <color name="i_am_color_19eb">#000019eb</color> + <color name="i_am_color_19ec">#000019ec</color> + <color name="i_am_color_19ed">#000019ed</color> + <color name="i_am_color_19ee">#000019ee</color> + <color name="i_am_color_19ef">#000019ef</color> + <color name="i_am_color_19f0">#000019f0</color> + <color name="i_am_color_19f1">#000019f1</color> + <color name="i_am_color_19f2">#000019f2</color> + <color name="i_am_color_19f3">#000019f3</color> + <color name="i_am_color_19f4">#000019f4</color> + <color name="i_am_color_19f5">#000019f5</color> + <color name="i_am_color_19f6">#000019f6</color> + <color name="i_am_color_19f7">#000019f7</color> + <color name="i_am_color_19f8">#000019f8</color> + <color name="i_am_color_19f9">#000019f9</color> + <color name="i_am_color_19fa">#000019fa</color> + <color name="i_am_color_19fb">#000019fb</color> + <color name="i_am_color_19fc">#000019fc</color> + <color name="i_am_color_19fd">#000019fd</color> + <color name="i_am_color_19fe">#000019fe</color> + <color name="i_am_color_19ff">#000019ff</color> + <color name="i_am_color_1a00">#00001a00</color> + <color name="i_am_color_1a01">#00001a01</color> + <color name="i_am_color_1a02">#00001a02</color> + <color name="i_am_color_1a03">#00001a03</color> + <color name="i_am_color_1a04">#00001a04</color> + <color name="i_am_color_1a05">#00001a05</color> + <color name="i_am_color_1a06">#00001a06</color> + <color name="i_am_color_1a07">#00001a07</color> + <color name="i_am_color_1a08">#00001a08</color> + <color name="i_am_color_1a09">#00001a09</color> + <color name="i_am_color_1a0a">#00001a0a</color> + <color name="i_am_color_1a0b">#00001a0b</color> + <color name="i_am_color_1a0c">#00001a0c</color> + <color name="i_am_color_1a0d">#00001a0d</color> + <color name="i_am_color_1a0e">#00001a0e</color> + <color name="i_am_color_1a0f">#00001a0f</color> + <color name="i_am_color_1a10">#00001a10</color> + <color name="i_am_color_1a11">#00001a11</color> + <color name="i_am_color_1a12">#00001a12</color> + <color name="i_am_color_1a13">#00001a13</color> + <color name="i_am_color_1a14">#00001a14</color> + <color name="i_am_color_1a15">#00001a15</color> + <color name="i_am_color_1a16">#00001a16</color> + <color name="i_am_color_1a17">#00001a17</color> + <color name="i_am_color_1a18">#00001a18</color> + <color name="i_am_color_1a19">#00001a19</color> + <color name="i_am_color_1a1a">#00001a1a</color> + <color name="i_am_color_1a1b">#00001a1b</color> + <color name="i_am_color_1a1c">#00001a1c</color> + <color name="i_am_color_1a1d">#00001a1d</color> + <color name="i_am_color_1a1e">#00001a1e</color> + <color name="i_am_color_1a1f">#00001a1f</color> + <color name="i_am_color_1a20">#00001a20</color> + <color name="i_am_color_1a21">#00001a21</color> + <color name="i_am_color_1a22">#00001a22</color> + <color name="i_am_color_1a23">#00001a23</color> + <color name="i_am_color_1a24">#00001a24</color> + <color name="i_am_color_1a25">#00001a25</color> + <color name="i_am_color_1a26">#00001a26</color> + <color name="i_am_color_1a27">#00001a27</color> + <color name="i_am_color_1a28">#00001a28</color> + <color name="i_am_color_1a29">#00001a29</color> + <color name="i_am_color_1a2a">#00001a2a</color> + <color name="i_am_color_1a2b">#00001a2b</color> + <color name="i_am_color_1a2c">#00001a2c</color> + <color name="i_am_color_1a2d">#00001a2d</color> + <color name="i_am_color_1a2e">#00001a2e</color> + <color name="i_am_color_1a2f">#00001a2f</color> + <color name="i_am_color_1a30">#00001a30</color> + <color name="i_am_color_1a31">#00001a31</color> + <color name="i_am_color_1a32">#00001a32</color> + <color name="i_am_color_1a33">#00001a33</color> + <color name="i_am_color_1a34">#00001a34</color> + <color name="i_am_color_1a35">#00001a35</color> + <color name="i_am_color_1a36">#00001a36</color> + <color name="i_am_color_1a37">#00001a37</color> + <color name="i_am_color_1a38">#00001a38</color> + <color name="i_am_color_1a39">#00001a39</color> + <color name="i_am_color_1a3a">#00001a3a</color> + <color name="i_am_color_1a3b">#00001a3b</color> + <color name="i_am_color_1a3c">#00001a3c</color> + <color name="i_am_color_1a3d">#00001a3d</color> + <color name="i_am_color_1a3e">#00001a3e</color> + <color name="i_am_color_1a3f">#00001a3f</color> + <color name="i_am_color_1a40">#00001a40</color> + <color name="i_am_color_1a41">#00001a41</color> + <color name="i_am_color_1a42">#00001a42</color> + <color name="i_am_color_1a43">#00001a43</color> + <color name="i_am_color_1a44">#00001a44</color> + <color name="i_am_color_1a45">#00001a45</color> + <color name="i_am_color_1a46">#00001a46</color> + <color name="i_am_color_1a47">#00001a47</color> + <color name="i_am_color_1a48">#00001a48</color> + <color name="i_am_color_1a49">#00001a49</color> + <color name="i_am_color_1a4a">#00001a4a</color> + <color name="i_am_color_1a4b">#00001a4b</color> + <color name="i_am_color_1a4c">#00001a4c</color> + <color name="i_am_color_1a4d">#00001a4d</color> + <color name="i_am_color_1a4e">#00001a4e</color> + <color name="i_am_color_1a4f">#00001a4f</color> + <color name="i_am_color_1a50">#00001a50</color> + <color name="i_am_color_1a51">#00001a51</color> + <color name="i_am_color_1a52">#00001a52</color> + <color name="i_am_color_1a53">#00001a53</color> + <color name="i_am_color_1a54">#00001a54</color> + <color name="i_am_color_1a55">#00001a55</color> + <color name="i_am_color_1a56">#00001a56</color> + <color name="i_am_color_1a57">#00001a57</color> + <color name="i_am_color_1a58">#00001a58</color> + <color name="i_am_color_1a59">#00001a59</color> + <color name="i_am_color_1a5a">#00001a5a</color> + <color name="i_am_color_1a5b">#00001a5b</color> + <color name="i_am_color_1a5c">#00001a5c</color> + <color name="i_am_color_1a5d">#00001a5d</color> + <color name="i_am_color_1a5e">#00001a5e</color> + <color name="i_am_color_1a5f">#00001a5f</color> + <color name="i_am_color_1a60">#00001a60</color> + <color name="i_am_color_1a61">#00001a61</color> + <color name="i_am_color_1a62">#00001a62</color> + <color name="i_am_color_1a63">#00001a63</color> + <color name="i_am_color_1a64">#00001a64</color> + <color name="i_am_color_1a65">#00001a65</color> + <color name="i_am_color_1a66">#00001a66</color> + <color name="i_am_color_1a67">#00001a67</color> + <color name="i_am_color_1a68">#00001a68</color> + <color name="i_am_color_1a69">#00001a69</color> + <color name="i_am_color_1a6a">#00001a6a</color> + <color name="i_am_color_1a6b">#00001a6b</color> + <color name="i_am_color_1a6c">#00001a6c</color> + <color name="i_am_color_1a6d">#00001a6d</color> + <color name="i_am_color_1a6e">#00001a6e</color> + <color name="i_am_color_1a6f">#00001a6f</color> + <color name="i_am_color_1a70">#00001a70</color> + <color name="i_am_color_1a71">#00001a71</color> + <color name="i_am_color_1a72">#00001a72</color> + <color name="i_am_color_1a73">#00001a73</color> + <color name="i_am_color_1a74">#00001a74</color> + <color name="i_am_color_1a75">#00001a75</color> + <color name="i_am_color_1a76">#00001a76</color> + <color name="i_am_color_1a77">#00001a77</color> + <color name="i_am_color_1a78">#00001a78</color> + <color name="i_am_color_1a79">#00001a79</color> + <color name="i_am_color_1a7a">#00001a7a</color> + <color name="i_am_color_1a7b">#00001a7b</color> + <color name="i_am_color_1a7c">#00001a7c</color> + <color name="i_am_color_1a7d">#00001a7d</color> + <color name="i_am_color_1a7e">#00001a7e</color> + <color name="i_am_color_1a7f">#00001a7f</color> + <color name="i_am_color_1a80">#00001a80</color> + <color name="i_am_color_1a81">#00001a81</color> + <color name="i_am_color_1a82">#00001a82</color> + <color name="i_am_color_1a83">#00001a83</color> + <color name="i_am_color_1a84">#00001a84</color> + <color name="i_am_color_1a85">#00001a85</color> + <color name="i_am_color_1a86">#00001a86</color> + <color name="i_am_color_1a87">#00001a87</color> + <color name="i_am_color_1a88">#00001a88</color> + <color name="i_am_color_1a89">#00001a89</color> + <color name="i_am_color_1a8a">#00001a8a</color> + <color name="i_am_color_1a8b">#00001a8b</color> + <color name="i_am_color_1a8c">#00001a8c</color> + <color name="i_am_color_1a8d">#00001a8d</color> + <color name="i_am_color_1a8e">#00001a8e</color> + <color name="i_am_color_1a8f">#00001a8f</color> + <color name="i_am_color_1a90">#00001a90</color> + <color name="i_am_color_1a91">#00001a91</color> + <color name="i_am_color_1a92">#00001a92</color> + <color name="i_am_color_1a93">#00001a93</color> + <color name="i_am_color_1a94">#00001a94</color> + <color name="i_am_color_1a95">#00001a95</color> + <color name="i_am_color_1a96">#00001a96</color> + <color name="i_am_color_1a97">#00001a97</color> + <color name="i_am_color_1a98">#00001a98</color> + <color name="i_am_color_1a99">#00001a99</color> + <color name="i_am_color_1a9a">#00001a9a</color> + <color name="i_am_color_1a9b">#00001a9b</color> + <color name="i_am_color_1a9c">#00001a9c</color> + <color name="i_am_color_1a9d">#00001a9d</color> + <color name="i_am_color_1a9e">#00001a9e</color> + <color name="i_am_color_1a9f">#00001a9f</color> + <color name="i_am_color_1aa0">#00001aa0</color> + <color name="i_am_color_1aa1">#00001aa1</color> + <color name="i_am_color_1aa2">#00001aa2</color> + <color name="i_am_color_1aa3">#00001aa3</color> + <color name="i_am_color_1aa4">#00001aa4</color> + <color name="i_am_color_1aa5">#00001aa5</color> + <color name="i_am_color_1aa6">#00001aa6</color> + <color name="i_am_color_1aa7">#00001aa7</color> + <color name="i_am_color_1aa8">#00001aa8</color> + <color name="i_am_color_1aa9">#00001aa9</color> + <color name="i_am_color_1aaa">#00001aaa</color> + <color name="i_am_color_1aab">#00001aab</color> + <color name="i_am_color_1aac">#00001aac</color> + <color name="i_am_color_1aad">#00001aad</color> + <color name="i_am_color_1aae">#00001aae</color> + <color name="i_am_color_1aaf">#00001aaf</color> + <color name="i_am_color_1ab0">#00001ab0</color> + <color name="i_am_color_1ab1">#00001ab1</color> + <color name="i_am_color_1ab2">#00001ab2</color> + <color name="i_am_color_1ab3">#00001ab3</color> + <color name="i_am_color_1ab4">#00001ab4</color> + <color name="i_am_color_1ab5">#00001ab5</color> + <color name="i_am_color_1ab6">#00001ab6</color> + <color name="i_am_color_1ab7">#00001ab7</color> + <color name="i_am_color_1ab8">#00001ab8</color> + <color name="i_am_color_1ab9">#00001ab9</color> + <color name="i_am_color_1aba">#00001aba</color> + <color name="i_am_color_1abb">#00001abb</color> + <color name="i_am_color_1abc">#00001abc</color> + <color name="i_am_color_1abd">#00001abd</color> + <color name="i_am_color_1abe">#00001abe</color> + <color name="i_am_color_1abf">#00001abf</color> + <color name="i_am_color_1ac0">#00001ac0</color> + <color name="i_am_color_1ac1">#00001ac1</color> + <color name="i_am_color_1ac2">#00001ac2</color> + <color name="i_am_color_1ac3">#00001ac3</color> + <color name="i_am_color_1ac4">#00001ac4</color> + <color name="i_am_color_1ac5">#00001ac5</color> + <color name="i_am_color_1ac6">#00001ac6</color> + <color name="i_am_color_1ac7">#00001ac7</color> + <color name="i_am_color_1ac8">#00001ac8</color> + <color name="i_am_color_1ac9">#00001ac9</color> + <color name="i_am_color_1aca">#00001aca</color> + <color name="i_am_color_1acb">#00001acb</color> + <color name="i_am_color_1acc">#00001acc</color> + <color name="i_am_color_1acd">#00001acd</color> + <color name="i_am_color_1ace">#00001ace</color> + <color name="i_am_color_1acf">#00001acf</color> + <color name="i_am_color_1ad0">#00001ad0</color> + <color name="i_am_color_1ad1">#00001ad1</color> + <color name="i_am_color_1ad2">#00001ad2</color> + <color name="i_am_color_1ad3">#00001ad3</color> + <color name="i_am_color_1ad4">#00001ad4</color> + <color name="i_am_color_1ad5">#00001ad5</color> + <color name="i_am_color_1ad6">#00001ad6</color> + <color name="i_am_color_1ad7">#00001ad7</color> + <color name="i_am_color_1ad8">#00001ad8</color> + <color name="i_am_color_1ad9">#00001ad9</color> + <color name="i_am_color_1ada">#00001ada</color> + <color name="i_am_color_1adb">#00001adb</color> + <color name="i_am_color_1adc">#00001adc</color> + <color name="i_am_color_1add">#00001add</color> + <color name="i_am_color_1ade">#00001ade</color> + <color name="i_am_color_1adf">#00001adf</color> + <color name="i_am_color_1ae0">#00001ae0</color> + <color name="i_am_color_1ae1">#00001ae1</color> + <color name="i_am_color_1ae2">#00001ae2</color> + <color name="i_am_color_1ae3">#00001ae3</color> + <color name="i_am_color_1ae4">#00001ae4</color> + <color name="i_am_color_1ae5">#00001ae5</color> + <color name="i_am_color_1ae6">#00001ae6</color> + <color name="i_am_color_1ae7">#00001ae7</color> + <color name="i_am_color_1ae8">#00001ae8</color> + <color name="i_am_color_1ae9">#00001ae9</color> + <color name="i_am_color_1aea">#00001aea</color> + <color name="i_am_color_1aeb">#00001aeb</color> + <color name="i_am_color_1aec">#00001aec</color> + <color name="i_am_color_1aed">#00001aed</color> + <color name="i_am_color_1aee">#00001aee</color> + <color name="i_am_color_1aef">#00001aef</color> + <color name="i_am_color_1af0">#00001af0</color> + <color name="i_am_color_1af1">#00001af1</color> + <color name="i_am_color_1af2">#00001af2</color> + <color name="i_am_color_1af3">#00001af3</color> + <color name="i_am_color_1af4">#00001af4</color> + <color name="i_am_color_1af5">#00001af5</color> + <color name="i_am_color_1af6">#00001af6</color> + <color name="i_am_color_1af7">#00001af7</color> + <color name="i_am_color_1af8">#00001af8</color> + <color name="i_am_color_1af9">#00001af9</color> + <color name="i_am_color_1afa">#00001afa</color> + <color name="i_am_color_1afb">#00001afb</color> + <color name="i_am_color_1afc">#00001afc</color> + <color name="i_am_color_1afd">#00001afd</color> + <color name="i_am_color_1afe">#00001afe</color> + <color name="i_am_color_1aff">#00001aff</color> + <color name="i_am_color_1b00">#00001b00</color> + <color name="i_am_color_1b01">#00001b01</color> + <color name="i_am_color_1b02">#00001b02</color> + <color name="i_am_color_1b03">#00001b03</color> + <color name="i_am_color_1b04">#00001b04</color> + <color name="i_am_color_1b05">#00001b05</color> + <color name="i_am_color_1b06">#00001b06</color> + <color name="i_am_color_1b07">#00001b07</color> + <color name="i_am_color_1b08">#00001b08</color> + <color name="i_am_color_1b09">#00001b09</color> + <color name="i_am_color_1b0a">#00001b0a</color> + <color name="i_am_color_1b0b">#00001b0b</color> + <color name="i_am_color_1b0c">#00001b0c</color> + <color name="i_am_color_1b0d">#00001b0d</color> + <color name="i_am_color_1b0e">#00001b0e</color> + <color name="i_am_color_1b0f">#00001b0f</color> + <color name="i_am_color_1b10">#00001b10</color> + <color name="i_am_color_1b11">#00001b11</color> + <color name="i_am_color_1b12">#00001b12</color> + <color name="i_am_color_1b13">#00001b13</color> + <color name="i_am_color_1b14">#00001b14</color> + <color name="i_am_color_1b15">#00001b15</color> + <color name="i_am_color_1b16">#00001b16</color> + <color name="i_am_color_1b17">#00001b17</color> + <color name="i_am_color_1b18">#00001b18</color> + <color name="i_am_color_1b19">#00001b19</color> + <color name="i_am_color_1b1a">#00001b1a</color> + <color name="i_am_color_1b1b">#00001b1b</color> + <color name="i_am_color_1b1c">#00001b1c</color> + <color name="i_am_color_1b1d">#00001b1d</color> + <color name="i_am_color_1b1e">#00001b1e</color> + <color name="i_am_color_1b1f">#00001b1f</color> + <color name="i_am_color_1b20">#00001b20</color> + <color name="i_am_color_1b21">#00001b21</color> + <color name="i_am_color_1b22">#00001b22</color> + <color name="i_am_color_1b23">#00001b23</color> + <color name="i_am_color_1b24">#00001b24</color> + <color name="i_am_color_1b25">#00001b25</color> + <color name="i_am_color_1b26">#00001b26</color> + <color name="i_am_color_1b27">#00001b27</color> + <color name="i_am_color_1b28">#00001b28</color> + <color name="i_am_color_1b29">#00001b29</color> + <color name="i_am_color_1b2a">#00001b2a</color> + <color name="i_am_color_1b2b">#00001b2b</color> + <color name="i_am_color_1b2c">#00001b2c</color> + <color name="i_am_color_1b2d">#00001b2d</color> + <color name="i_am_color_1b2e">#00001b2e</color> + <color name="i_am_color_1b2f">#00001b2f</color> + <color name="i_am_color_1b30">#00001b30</color> + <color name="i_am_color_1b31">#00001b31</color> + <color name="i_am_color_1b32">#00001b32</color> + <color name="i_am_color_1b33">#00001b33</color> + <color name="i_am_color_1b34">#00001b34</color> + <color name="i_am_color_1b35">#00001b35</color> + <color name="i_am_color_1b36">#00001b36</color> + <color name="i_am_color_1b37">#00001b37</color> + <color name="i_am_color_1b38">#00001b38</color> + <color name="i_am_color_1b39">#00001b39</color> + <color name="i_am_color_1b3a">#00001b3a</color> + <color name="i_am_color_1b3b">#00001b3b</color> + <color name="i_am_color_1b3c">#00001b3c</color> + <color name="i_am_color_1b3d">#00001b3d</color> + <color name="i_am_color_1b3e">#00001b3e</color> + <color name="i_am_color_1b3f">#00001b3f</color> + <color name="i_am_color_1b40">#00001b40</color> + <color name="i_am_color_1b41">#00001b41</color> + <color name="i_am_color_1b42">#00001b42</color> + <color name="i_am_color_1b43">#00001b43</color> + <color name="i_am_color_1b44">#00001b44</color> + <color name="i_am_color_1b45">#00001b45</color> + <color name="i_am_color_1b46">#00001b46</color> + <color name="i_am_color_1b47">#00001b47</color> + <color name="i_am_color_1b48">#00001b48</color> + <color name="i_am_color_1b49">#00001b49</color> + <color name="i_am_color_1b4a">#00001b4a</color> + <color name="i_am_color_1b4b">#00001b4b</color> + <color name="i_am_color_1b4c">#00001b4c</color> + <color name="i_am_color_1b4d">#00001b4d</color> + <color name="i_am_color_1b4e">#00001b4e</color> + <color name="i_am_color_1b4f">#00001b4f</color> + <color name="i_am_color_1b50">#00001b50</color> + <color name="i_am_color_1b51">#00001b51</color> + <color name="i_am_color_1b52">#00001b52</color> + <color name="i_am_color_1b53">#00001b53</color> + <color name="i_am_color_1b54">#00001b54</color> + <color name="i_am_color_1b55">#00001b55</color> + <color name="i_am_color_1b56">#00001b56</color> + <color name="i_am_color_1b57">#00001b57</color> + <color name="i_am_color_1b58">#00001b58</color> + <color name="i_am_color_1b59">#00001b59</color> + <color name="i_am_color_1b5a">#00001b5a</color> + <color name="i_am_color_1b5b">#00001b5b</color> + <color name="i_am_color_1b5c">#00001b5c</color> + <color name="i_am_color_1b5d">#00001b5d</color> + <color name="i_am_color_1b5e">#00001b5e</color> + <color name="i_am_color_1b5f">#00001b5f</color> + <color name="i_am_color_1b60">#00001b60</color> + <color name="i_am_color_1b61">#00001b61</color> + <color name="i_am_color_1b62">#00001b62</color> + <color name="i_am_color_1b63">#00001b63</color> + <color name="i_am_color_1b64">#00001b64</color> + <color name="i_am_color_1b65">#00001b65</color> + <color name="i_am_color_1b66">#00001b66</color> + <color name="i_am_color_1b67">#00001b67</color> + <color name="i_am_color_1b68">#00001b68</color> + <color name="i_am_color_1b69">#00001b69</color> + <color name="i_am_color_1b6a">#00001b6a</color> + <color name="i_am_color_1b6b">#00001b6b</color> + <color name="i_am_color_1b6c">#00001b6c</color> + <color name="i_am_color_1b6d">#00001b6d</color> + <color name="i_am_color_1b6e">#00001b6e</color> + <color name="i_am_color_1b6f">#00001b6f</color> + <color name="i_am_color_1b70">#00001b70</color> + <color name="i_am_color_1b71">#00001b71</color> + <color name="i_am_color_1b72">#00001b72</color> + <color name="i_am_color_1b73">#00001b73</color> + <color name="i_am_color_1b74">#00001b74</color> + <color name="i_am_color_1b75">#00001b75</color> + <color name="i_am_color_1b76">#00001b76</color> + <color name="i_am_color_1b77">#00001b77</color> + <color name="i_am_color_1b78">#00001b78</color> + <color name="i_am_color_1b79">#00001b79</color> + <color name="i_am_color_1b7a">#00001b7a</color> + <color name="i_am_color_1b7b">#00001b7b</color> + <color name="i_am_color_1b7c">#00001b7c</color> + <color name="i_am_color_1b7d">#00001b7d</color> + <color name="i_am_color_1b7e">#00001b7e</color> + <color name="i_am_color_1b7f">#00001b7f</color> + <color name="i_am_color_1b80">#00001b80</color> + <color name="i_am_color_1b81">#00001b81</color> + <color name="i_am_color_1b82">#00001b82</color> + <color name="i_am_color_1b83">#00001b83</color> + <color name="i_am_color_1b84">#00001b84</color> + <color name="i_am_color_1b85">#00001b85</color> + <color name="i_am_color_1b86">#00001b86</color> + <color name="i_am_color_1b87">#00001b87</color> + <color name="i_am_color_1b88">#00001b88</color> + <color name="i_am_color_1b89">#00001b89</color> + <color name="i_am_color_1b8a">#00001b8a</color> + <color name="i_am_color_1b8b">#00001b8b</color> + <color name="i_am_color_1b8c">#00001b8c</color> + <color name="i_am_color_1b8d">#00001b8d</color> + <color name="i_am_color_1b8e">#00001b8e</color> + <color name="i_am_color_1b8f">#00001b8f</color> + <color name="i_am_color_1b90">#00001b90</color> + <color name="i_am_color_1b91">#00001b91</color> + <color name="i_am_color_1b92">#00001b92</color> + <color name="i_am_color_1b93">#00001b93</color> + <color name="i_am_color_1b94">#00001b94</color> + <color name="i_am_color_1b95">#00001b95</color> + <color name="i_am_color_1b96">#00001b96</color> + <color name="i_am_color_1b97">#00001b97</color> + <color name="i_am_color_1b98">#00001b98</color> + <color name="i_am_color_1b99">#00001b99</color> + <color name="i_am_color_1b9a">#00001b9a</color> + <color name="i_am_color_1b9b">#00001b9b</color> + <color name="i_am_color_1b9c">#00001b9c</color> + <color name="i_am_color_1b9d">#00001b9d</color> + <color name="i_am_color_1b9e">#00001b9e</color> + <color name="i_am_color_1b9f">#00001b9f</color> + <color name="i_am_color_1ba0">#00001ba0</color> + <color name="i_am_color_1ba1">#00001ba1</color> + <color name="i_am_color_1ba2">#00001ba2</color> + <color name="i_am_color_1ba3">#00001ba3</color> + <color name="i_am_color_1ba4">#00001ba4</color> + <color name="i_am_color_1ba5">#00001ba5</color> + <color name="i_am_color_1ba6">#00001ba6</color> + <color name="i_am_color_1ba7">#00001ba7</color> + <color name="i_am_color_1ba8">#00001ba8</color> + <color name="i_am_color_1ba9">#00001ba9</color> + <color name="i_am_color_1baa">#00001baa</color> + <color name="i_am_color_1bab">#00001bab</color> + <color name="i_am_color_1bac">#00001bac</color> + <color name="i_am_color_1bad">#00001bad</color> + <color name="i_am_color_1bae">#00001bae</color> + <color name="i_am_color_1baf">#00001baf</color> + <color name="i_am_color_1bb0">#00001bb0</color> + <color name="i_am_color_1bb1">#00001bb1</color> + <color name="i_am_color_1bb2">#00001bb2</color> + <color name="i_am_color_1bb3">#00001bb3</color> + <color name="i_am_color_1bb4">#00001bb4</color> + <color name="i_am_color_1bb5">#00001bb5</color> + <color name="i_am_color_1bb6">#00001bb6</color> + <color name="i_am_color_1bb7">#00001bb7</color> + <color name="i_am_color_1bb8">#00001bb8</color> + <color name="i_am_color_1bb9">#00001bb9</color> + <color name="i_am_color_1bba">#00001bba</color> + <color name="i_am_color_1bbb">#00001bbb</color> + <color name="i_am_color_1bbc">#00001bbc</color> + <color name="i_am_color_1bbd">#00001bbd</color> + <color name="i_am_color_1bbe">#00001bbe</color> + <color name="i_am_color_1bbf">#00001bbf</color> + <color name="i_am_color_1bc0">#00001bc0</color> + <color name="i_am_color_1bc1">#00001bc1</color> + <color name="i_am_color_1bc2">#00001bc2</color> + <color name="i_am_color_1bc3">#00001bc3</color> + <color name="i_am_color_1bc4">#00001bc4</color> + <color name="i_am_color_1bc5">#00001bc5</color> + <color name="i_am_color_1bc6">#00001bc6</color> + <color name="i_am_color_1bc7">#00001bc7</color> + <color name="i_am_color_1bc8">#00001bc8</color> + <color name="i_am_color_1bc9">#00001bc9</color> + <color name="i_am_color_1bca">#00001bca</color> + <color name="i_am_color_1bcb">#00001bcb</color> + <color name="i_am_color_1bcc">#00001bcc</color> + <color name="i_am_color_1bcd">#00001bcd</color> + <color name="i_am_color_1bce">#00001bce</color> + <color name="i_am_color_1bcf">#00001bcf</color> + <color name="i_am_color_1bd0">#00001bd0</color> + <color name="i_am_color_1bd1">#00001bd1</color> + <color name="i_am_color_1bd2">#00001bd2</color> + <color name="i_am_color_1bd3">#00001bd3</color> + <color name="i_am_color_1bd4">#00001bd4</color> + <color name="i_am_color_1bd5">#00001bd5</color> + <color name="i_am_color_1bd6">#00001bd6</color> + <color name="i_am_color_1bd7">#00001bd7</color> + <color name="i_am_color_1bd8">#00001bd8</color> + <color name="i_am_color_1bd9">#00001bd9</color> + <color name="i_am_color_1bda">#00001bda</color> + <color name="i_am_color_1bdb">#00001bdb</color> + <color name="i_am_color_1bdc">#00001bdc</color> + <color name="i_am_color_1bdd">#00001bdd</color> + <color name="i_am_color_1bde">#00001bde</color> + <color name="i_am_color_1bdf">#00001bdf</color> + <color name="i_am_color_1be0">#00001be0</color> + <color name="i_am_color_1be1">#00001be1</color> + <color name="i_am_color_1be2">#00001be2</color> + <color name="i_am_color_1be3">#00001be3</color> + <color name="i_am_color_1be4">#00001be4</color> + <color name="i_am_color_1be5">#00001be5</color> + <color name="i_am_color_1be6">#00001be6</color> + <color name="i_am_color_1be7">#00001be7</color> + <color name="i_am_color_1be8">#00001be8</color> + <color name="i_am_color_1be9">#00001be9</color> + <color name="i_am_color_1bea">#00001bea</color> + <color name="i_am_color_1beb">#00001beb</color> + <color name="i_am_color_1bec">#00001bec</color> + <color name="i_am_color_1bed">#00001bed</color> + <color name="i_am_color_1bee">#00001bee</color> + <color name="i_am_color_1bef">#00001bef</color> + <color name="i_am_color_1bf0">#00001bf0</color> + <color name="i_am_color_1bf1">#00001bf1</color> + <color name="i_am_color_1bf2">#00001bf2</color> + <color name="i_am_color_1bf3">#00001bf3</color> + <color name="i_am_color_1bf4">#00001bf4</color> + <color name="i_am_color_1bf5">#00001bf5</color> + <color name="i_am_color_1bf6">#00001bf6</color> + <color name="i_am_color_1bf7">#00001bf7</color> + <color name="i_am_color_1bf8">#00001bf8</color> + <color name="i_am_color_1bf9">#00001bf9</color> + <color name="i_am_color_1bfa">#00001bfa</color> + <color name="i_am_color_1bfb">#00001bfb</color> + <color name="i_am_color_1bfc">#00001bfc</color> + <color name="i_am_color_1bfd">#00001bfd</color> + <color name="i_am_color_1bfe">#00001bfe</color> + <color name="i_am_color_1bff">#00001bff</color> + <color name="i_am_color_1c00">#00001c00</color> + <color name="i_am_color_1c01">#00001c01</color> + <color name="i_am_color_1c02">#00001c02</color> + <color name="i_am_color_1c03">#00001c03</color> + <color name="i_am_color_1c04">#00001c04</color> + <color name="i_am_color_1c05">#00001c05</color> + <color name="i_am_color_1c06">#00001c06</color> + <color name="i_am_color_1c07">#00001c07</color> + <color name="i_am_color_1c08">#00001c08</color> + <color name="i_am_color_1c09">#00001c09</color> + <color name="i_am_color_1c0a">#00001c0a</color> + <color name="i_am_color_1c0b">#00001c0b</color> + <color name="i_am_color_1c0c">#00001c0c</color> + <color name="i_am_color_1c0d">#00001c0d</color> + <color name="i_am_color_1c0e">#00001c0e</color> + <color name="i_am_color_1c0f">#00001c0f</color> + <color name="i_am_color_1c10">#00001c10</color> + <color name="i_am_color_1c11">#00001c11</color> + <color name="i_am_color_1c12">#00001c12</color> + <color name="i_am_color_1c13">#00001c13</color> + <color name="i_am_color_1c14">#00001c14</color> + <color name="i_am_color_1c15">#00001c15</color> + <color name="i_am_color_1c16">#00001c16</color> + <color name="i_am_color_1c17">#00001c17</color> + <color name="i_am_color_1c18">#00001c18</color> + <color name="i_am_color_1c19">#00001c19</color> + <color name="i_am_color_1c1a">#00001c1a</color> + <color name="i_am_color_1c1b">#00001c1b</color> + <color name="i_am_color_1c1c">#00001c1c</color> + <color name="i_am_color_1c1d">#00001c1d</color> + <color name="i_am_color_1c1e">#00001c1e</color> + <color name="i_am_color_1c1f">#00001c1f</color> + <color name="i_am_color_1c20">#00001c20</color> + <color name="i_am_color_1c21">#00001c21</color> + <color name="i_am_color_1c22">#00001c22</color> + <color name="i_am_color_1c23">#00001c23</color> + <color name="i_am_color_1c24">#00001c24</color> + <color name="i_am_color_1c25">#00001c25</color> + <color name="i_am_color_1c26">#00001c26</color> + <color name="i_am_color_1c27">#00001c27</color> + <color name="i_am_color_1c28">#00001c28</color> + <color name="i_am_color_1c29">#00001c29</color> + <color name="i_am_color_1c2a">#00001c2a</color> + <color name="i_am_color_1c2b">#00001c2b</color> + <color name="i_am_color_1c2c">#00001c2c</color> + <color name="i_am_color_1c2d">#00001c2d</color> + <color name="i_am_color_1c2e">#00001c2e</color> + <color name="i_am_color_1c2f">#00001c2f</color> + <color name="i_am_color_1c30">#00001c30</color> + <color name="i_am_color_1c31">#00001c31</color> + <color name="i_am_color_1c32">#00001c32</color> + <color name="i_am_color_1c33">#00001c33</color> + <color name="i_am_color_1c34">#00001c34</color> + <color name="i_am_color_1c35">#00001c35</color> + <color name="i_am_color_1c36">#00001c36</color> + <color name="i_am_color_1c37">#00001c37</color> + <color name="i_am_color_1c38">#00001c38</color> + <color name="i_am_color_1c39">#00001c39</color> + <color name="i_am_color_1c3a">#00001c3a</color> + <color name="i_am_color_1c3b">#00001c3b</color> + <color name="i_am_color_1c3c">#00001c3c</color> + <color name="i_am_color_1c3d">#00001c3d</color> + <color name="i_am_color_1c3e">#00001c3e</color> + <color name="i_am_color_1c3f">#00001c3f</color> + <color name="i_am_color_1c40">#00001c40</color> + <color name="i_am_color_1c41">#00001c41</color> + <color name="i_am_color_1c42">#00001c42</color> + <color name="i_am_color_1c43">#00001c43</color> + <color name="i_am_color_1c44">#00001c44</color> + <color name="i_am_color_1c45">#00001c45</color> + <color name="i_am_color_1c46">#00001c46</color> + <color name="i_am_color_1c47">#00001c47</color> + <color name="i_am_color_1c48">#00001c48</color> + <color name="i_am_color_1c49">#00001c49</color> + <color name="i_am_color_1c4a">#00001c4a</color> + <color name="i_am_color_1c4b">#00001c4b</color> + <color name="i_am_color_1c4c">#00001c4c</color> + <color name="i_am_color_1c4d">#00001c4d</color> + <color name="i_am_color_1c4e">#00001c4e</color> + <color name="i_am_color_1c4f">#00001c4f</color> + <color name="i_am_color_1c50">#00001c50</color> + <color name="i_am_color_1c51">#00001c51</color> + <color name="i_am_color_1c52">#00001c52</color> + <color name="i_am_color_1c53">#00001c53</color> + <color name="i_am_color_1c54">#00001c54</color> + <color name="i_am_color_1c55">#00001c55</color> + <color name="i_am_color_1c56">#00001c56</color> + <color name="i_am_color_1c57">#00001c57</color> + <color name="i_am_color_1c58">#00001c58</color> + <color name="i_am_color_1c59">#00001c59</color> + <color name="i_am_color_1c5a">#00001c5a</color> + <color name="i_am_color_1c5b">#00001c5b</color> + <color name="i_am_color_1c5c">#00001c5c</color> + <color name="i_am_color_1c5d">#00001c5d</color> + <color name="i_am_color_1c5e">#00001c5e</color> + <color name="i_am_color_1c5f">#00001c5f</color> + <color name="i_am_color_1c60">#00001c60</color> + <color name="i_am_color_1c61">#00001c61</color> + <color name="i_am_color_1c62">#00001c62</color> + <color name="i_am_color_1c63">#00001c63</color> + <color name="i_am_color_1c64">#00001c64</color> + <color name="i_am_color_1c65">#00001c65</color> + <color name="i_am_color_1c66">#00001c66</color> + <color name="i_am_color_1c67">#00001c67</color> + <color name="i_am_color_1c68">#00001c68</color> + <color name="i_am_color_1c69">#00001c69</color> + <color name="i_am_color_1c6a">#00001c6a</color> + <color name="i_am_color_1c6b">#00001c6b</color> + <color name="i_am_color_1c6c">#00001c6c</color> + <color name="i_am_color_1c6d">#00001c6d</color> + <color name="i_am_color_1c6e">#00001c6e</color> + <color name="i_am_color_1c6f">#00001c6f</color> + <color name="i_am_color_1c70">#00001c70</color> + <color name="i_am_color_1c71">#00001c71</color> + <color name="i_am_color_1c72">#00001c72</color> + <color name="i_am_color_1c73">#00001c73</color> + <color name="i_am_color_1c74">#00001c74</color> + <color name="i_am_color_1c75">#00001c75</color> + <color name="i_am_color_1c76">#00001c76</color> + <color name="i_am_color_1c77">#00001c77</color> + <color name="i_am_color_1c78">#00001c78</color> + <color name="i_am_color_1c79">#00001c79</color> + <color name="i_am_color_1c7a">#00001c7a</color> + <color name="i_am_color_1c7b">#00001c7b</color> + <color name="i_am_color_1c7c">#00001c7c</color> + <color name="i_am_color_1c7d">#00001c7d</color> + <color name="i_am_color_1c7e">#00001c7e</color> + <color name="i_am_color_1c7f">#00001c7f</color> + <color name="i_am_color_1c80">#00001c80</color> + <color name="i_am_color_1c81">#00001c81</color> + <color name="i_am_color_1c82">#00001c82</color> + <color name="i_am_color_1c83">#00001c83</color> + <color name="i_am_color_1c84">#00001c84</color> + <color name="i_am_color_1c85">#00001c85</color> + <color name="i_am_color_1c86">#00001c86</color> + <color name="i_am_color_1c87">#00001c87</color> + <color name="i_am_color_1c88">#00001c88</color> + <color name="i_am_color_1c89">#00001c89</color> + <color name="i_am_color_1c8a">#00001c8a</color> + <color name="i_am_color_1c8b">#00001c8b</color> + <color name="i_am_color_1c8c">#00001c8c</color> + <color name="i_am_color_1c8d">#00001c8d</color> + <color name="i_am_color_1c8e">#00001c8e</color> + <color name="i_am_color_1c8f">#00001c8f</color> + <color name="i_am_color_1c90">#00001c90</color> + <color name="i_am_color_1c91">#00001c91</color> + <color name="i_am_color_1c92">#00001c92</color> + <color name="i_am_color_1c93">#00001c93</color> + <color name="i_am_color_1c94">#00001c94</color> + <color name="i_am_color_1c95">#00001c95</color> + <color name="i_am_color_1c96">#00001c96</color> + <color name="i_am_color_1c97">#00001c97</color> + <color name="i_am_color_1c98">#00001c98</color> + <color name="i_am_color_1c99">#00001c99</color> + <color name="i_am_color_1c9a">#00001c9a</color> + <color name="i_am_color_1c9b">#00001c9b</color> + <color name="i_am_color_1c9c">#00001c9c</color> + <color name="i_am_color_1c9d">#00001c9d</color> + <color name="i_am_color_1c9e">#00001c9e</color> + <color name="i_am_color_1c9f">#00001c9f</color> + <color name="i_am_color_1ca0">#00001ca0</color> + <color name="i_am_color_1ca1">#00001ca1</color> + <color name="i_am_color_1ca2">#00001ca2</color> + <color name="i_am_color_1ca3">#00001ca3</color> + <color name="i_am_color_1ca4">#00001ca4</color> + <color name="i_am_color_1ca5">#00001ca5</color> + <color name="i_am_color_1ca6">#00001ca6</color> + <color name="i_am_color_1ca7">#00001ca7</color> + <color name="i_am_color_1ca8">#00001ca8</color> + <color name="i_am_color_1ca9">#00001ca9</color> + <color name="i_am_color_1caa">#00001caa</color> + <color name="i_am_color_1cab">#00001cab</color> + <color name="i_am_color_1cac">#00001cac</color> + <color name="i_am_color_1cad">#00001cad</color> + <color name="i_am_color_1cae">#00001cae</color> + <color name="i_am_color_1caf">#00001caf</color> + <color name="i_am_color_1cb0">#00001cb0</color> + <color name="i_am_color_1cb1">#00001cb1</color> + <color name="i_am_color_1cb2">#00001cb2</color> + <color name="i_am_color_1cb3">#00001cb3</color> + <color name="i_am_color_1cb4">#00001cb4</color> + <color name="i_am_color_1cb5">#00001cb5</color> + <color name="i_am_color_1cb6">#00001cb6</color> + <color name="i_am_color_1cb7">#00001cb7</color> + <color name="i_am_color_1cb8">#00001cb8</color> + <color name="i_am_color_1cb9">#00001cb9</color> + <color name="i_am_color_1cba">#00001cba</color> + <color name="i_am_color_1cbb">#00001cbb</color> + <color name="i_am_color_1cbc">#00001cbc</color> + <color name="i_am_color_1cbd">#00001cbd</color> + <color name="i_am_color_1cbe">#00001cbe</color> + <color name="i_am_color_1cbf">#00001cbf</color> + <color name="i_am_color_1cc0">#00001cc0</color> + <color name="i_am_color_1cc1">#00001cc1</color> + <color name="i_am_color_1cc2">#00001cc2</color> + <color name="i_am_color_1cc3">#00001cc3</color> + <color name="i_am_color_1cc4">#00001cc4</color> + <color name="i_am_color_1cc5">#00001cc5</color> + <color name="i_am_color_1cc6">#00001cc6</color> + <color name="i_am_color_1cc7">#00001cc7</color> + <color name="i_am_color_1cc8">#00001cc8</color> + <color name="i_am_color_1cc9">#00001cc9</color> + <color name="i_am_color_1cca">#00001cca</color> + <color name="i_am_color_1ccb">#00001ccb</color> + <color name="i_am_color_1ccc">#00001ccc</color> + <color name="i_am_color_1ccd">#00001ccd</color> + <color name="i_am_color_1cce">#00001cce</color> + <color name="i_am_color_1ccf">#00001ccf</color> + <color name="i_am_color_1cd0">#00001cd0</color> + <color name="i_am_color_1cd1">#00001cd1</color> + <color name="i_am_color_1cd2">#00001cd2</color> + <color name="i_am_color_1cd3">#00001cd3</color> + <color name="i_am_color_1cd4">#00001cd4</color> + <color name="i_am_color_1cd5">#00001cd5</color> + <color name="i_am_color_1cd6">#00001cd6</color> + <color name="i_am_color_1cd7">#00001cd7</color> + <color name="i_am_color_1cd8">#00001cd8</color> + <color name="i_am_color_1cd9">#00001cd9</color> + <color name="i_am_color_1cda">#00001cda</color> + <color name="i_am_color_1cdb">#00001cdb</color> + <color name="i_am_color_1cdc">#00001cdc</color> + <color name="i_am_color_1cdd">#00001cdd</color> + <color name="i_am_color_1cde">#00001cde</color> + <color name="i_am_color_1cdf">#00001cdf</color> + <color name="i_am_color_1ce0">#00001ce0</color> + <color name="i_am_color_1ce1">#00001ce1</color> + <color name="i_am_color_1ce2">#00001ce2</color> + <color name="i_am_color_1ce3">#00001ce3</color> + <color name="i_am_color_1ce4">#00001ce4</color> + <color name="i_am_color_1ce5">#00001ce5</color> + <color name="i_am_color_1ce6">#00001ce6</color> + <color name="i_am_color_1ce7">#00001ce7</color> + <color name="i_am_color_1ce8">#00001ce8</color> + <color name="i_am_color_1ce9">#00001ce9</color> + <color name="i_am_color_1cea">#00001cea</color> + <color name="i_am_color_1ceb">#00001ceb</color> + <color name="i_am_color_1cec">#00001cec</color> + <color name="i_am_color_1ced">#00001ced</color> + <color name="i_am_color_1cee">#00001cee</color> + <color name="i_am_color_1cef">#00001cef</color> + <color name="i_am_color_1cf0">#00001cf0</color> + <color name="i_am_color_1cf1">#00001cf1</color> + <color name="i_am_color_1cf2">#00001cf2</color> + <color name="i_am_color_1cf3">#00001cf3</color> + <color name="i_am_color_1cf4">#00001cf4</color> + <color name="i_am_color_1cf5">#00001cf5</color> + <color name="i_am_color_1cf6">#00001cf6</color> + <color name="i_am_color_1cf7">#00001cf7</color> + <color name="i_am_color_1cf8">#00001cf8</color> + <color name="i_am_color_1cf9">#00001cf9</color> + <color name="i_am_color_1cfa">#00001cfa</color> + <color name="i_am_color_1cfb">#00001cfb</color> + <color name="i_am_color_1cfc">#00001cfc</color> + <color name="i_am_color_1cfd">#00001cfd</color> + <color name="i_am_color_1cfe">#00001cfe</color> + <color name="i_am_color_1cff">#00001cff</color> + <color name="i_am_color_1d00">#00001d00</color> + <color name="i_am_color_1d01">#00001d01</color> + <color name="i_am_color_1d02">#00001d02</color> + <color name="i_am_color_1d03">#00001d03</color> + <color name="i_am_color_1d04">#00001d04</color> + <color name="i_am_color_1d05">#00001d05</color> + <color name="i_am_color_1d06">#00001d06</color> + <color name="i_am_color_1d07">#00001d07</color> + <color name="i_am_color_1d08">#00001d08</color> + <color name="i_am_color_1d09">#00001d09</color> + <color name="i_am_color_1d0a">#00001d0a</color> + <color name="i_am_color_1d0b">#00001d0b</color> + <color name="i_am_color_1d0c">#00001d0c</color> + <color name="i_am_color_1d0d">#00001d0d</color> + <color name="i_am_color_1d0e">#00001d0e</color> + <color name="i_am_color_1d0f">#00001d0f</color> + <color name="i_am_color_1d10">#00001d10</color> + <color name="i_am_color_1d11">#00001d11</color> + <color name="i_am_color_1d12">#00001d12</color> + <color name="i_am_color_1d13">#00001d13</color> + <color name="i_am_color_1d14">#00001d14</color> + <color name="i_am_color_1d15">#00001d15</color> + <color name="i_am_color_1d16">#00001d16</color> + <color name="i_am_color_1d17">#00001d17</color> + <color name="i_am_color_1d18">#00001d18</color> + <color name="i_am_color_1d19">#00001d19</color> + <color name="i_am_color_1d1a">#00001d1a</color> + <color name="i_am_color_1d1b">#00001d1b</color> + <color name="i_am_color_1d1c">#00001d1c</color> + <color name="i_am_color_1d1d">#00001d1d</color> + <color name="i_am_color_1d1e">#00001d1e</color> + <color name="i_am_color_1d1f">#00001d1f</color> + <color name="i_am_color_1d20">#00001d20</color> + <color name="i_am_color_1d21">#00001d21</color> + <color name="i_am_color_1d22">#00001d22</color> + <color name="i_am_color_1d23">#00001d23</color> + <color name="i_am_color_1d24">#00001d24</color> + <color name="i_am_color_1d25">#00001d25</color> + <color name="i_am_color_1d26">#00001d26</color> + <color name="i_am_color_1d27">#00001d27</color> + <color name="i_am_color_1d28">#00001d28</color> + <color name="i_am_color_1d29">#00001d29</color> + <color name="i_am_color_1d2a">#00001d2a</color> + <color name="i_am_color_1d2b">#00001d2b</color> + <color name="i_am_color_1d2c">#00001d2c</color> + <color name="i_am_color_1d2d">#00001d2d</color> + <color name="i_am_color_1d2e">#00001d2e</color> + <color name="i_am_color_1d2f">#00001d2f</color> + <color name="i_am_color_1d30">#00001d30</color> + <color name="i_am_color_1d31">#00001d31</color> + <color name="i_am_color_1d32">#00001d32</color> + <color name="i_am_color_1d33">#00001d33</color> + <color name="i_am_color_1d34">#00001d34</color> + <color name="i_am_color_1d35">#00001d35</color> + <color name="i_am_color_1d36">#00001d36</color> + <color name="i_am_color_1d37">#00001d37</color> + <color name="i_am_color_1d38">#00001d38</color> + <color name="i_am_color_1d39">#00001d39</color> + <color name="i_am_color_1d3a">#00001d3a</color> + <color name="i_am_color_1d3b">#00001d3b</color> + <color name="i_am_color_1d3c">#00001d3c</color> + <color name="i_am_color_1d3d">#00001d3d</color> + <color name="i_am_color_1d3e">#00001d3e</color> + <color name="i_am_color_1d3f">#00001d3f</color> + <color name="i_am_color_1d40">#00001d40</color> + <color name="i_am_color_1d41">#00001d41</color> + <color name="i_am_color_1d42">#00001d42</color> + <color name="i_am_color_1d43">#00001d43</color> + <color name="i_am_color_1d44">#00001d44</color> + <color name="i_am_color_1d45">#00001d45</color> + <color name="i_am_color_1d46">#00001d46</color> + <color name="i_am_color_1d47">#00001d47</color> + <color name="i_am_color_1d48">#00001d48</color> + <color name="i_am_color_1d49">#00001d49</color> + <color name="i_am_color_1d4a">#00001d4a</color> + <color name="i_am_color_1d4b">#00001d4b</color> + <color name="i_am_color_1d4c">#00001d4c</color> + <color name="i_am_color_1d4d">#00001d4d</color> + <color name="i_am_color_1d4e">#00001d4e</color> + <color name="i_am_color_1d4f">#00001d4f</color> + <color name="i_am_color_1d50">#00001d50</color> + <color name="i_am_color_1d51">#00001d51</color> + <color name="i_am_color_1d52">#00001d52</color> + <color name="i_am_color_1d53">#00001d53</color> + <color name="i_am_color_1d54">#00001d54</color> + <color name="i_am_color_1d55">#00001d55</color> + <color name="i_am_color_1d56">#00001d56</color> + <color name="i_am_color_1d57">#00001d57</color> + <color name="i_am_color_1d58">#00001d58</color> + <color name="i_am_color_1d59">#00001d59</color> + <color name="i_am_color_1d5a">#00001d5a</color> + <color name="i_am_color_1d5b">#00001d5b</color> + <color name="i_am_color_1d5c">#00001d5c</color> + <color name="i_am_color_1d5d">#00001d5d</color> + <color name="i_am_color_1d5e">#00001d5e</color> + <color name="i_am_color_1d5f">#00001d5f</color> + <color name="i_am_color_1d60">#00001d60</color> + <color name="i_am_color_1d61">#00001d61</color> + <color name="i_am_color_1d62">#00001d62</color> + <color name="i_am_color_1d63">#00001d63</color> + <color name="i_am_color_1d64">#00001d64</color> + <color name="i_am_color_1d65">#00001d65</color> + <color name="i_am_color_1d66">#00001d66</color> + <color name="i_am_color_1d67">#00001d67</color> + <color name="i_am_color_1d68">#00001d68</color> + <color name="i_am_color_1d69">#00001d69</color> + <color name="i_am_color_1d6a">#00001d6a</color> + <color name="i_am_color_1d6b">#00001d6b</color> + <color name="i_am_color_1d6c">#00001d6c</color> + <color name="i_am_color_1d6d">#00001d6d</color> + <color name="i_am_color_1d6e">#00001d6e</color> + <color name="i_am_color_1d6f">#00001d6f</color> + <color name="i_am_color_1d70">#00001d70</color> + <color name="i_am_color_1d71">#00001d71</color> + <color name="i_am_color_1d72">#00001d72</color> + <color name="i_am_color_1d73">#00001d73</color> + <color name="i_am_color_1d74">#00001d74</color> + <color name="i_am_color_1d75">#00001d75</color> + <color name="i_am_color_1d76">#00001d76</color> + <color name="i_am_color_1d77">#00001d77</color> + <color name="i_am_color_1d78">#00001d78</color> + <color name="i_am_color_1d79">#00001d79</color> + <color name="i_am_color_1d7a">#00001d7a</color> + <color name="i_am_color_1d7b">#00001d7b</color> + <color name="i_am_color_1d7c">#00001d7c</color> + <color name="i_am_color_1d7d">#00001d7d</color> + <color name="i_am_color_1d7e">#00001d7e</color> + <color name="i_am_color_1d7f">#00001d7f</color> + <color name="i_am_color_1d80">#00001d80</color> + <color name="i_am_color_1d81">#00001d81</color> + <color name="i_am_color_1d82">#00001d82</color> + <color name="i_am_color_1d83">#00001d83</color> + <color name="i_am_color_1d84">#00001d84</color> + <color name="i_am_color_1d85">#00001d85</color> + <color name="i_am_color_1d86">#00001d86</color> + <color name="i_am_color_1d87">#00001d87</color> + <color name="i_am_color_1d88">#00001d88</color> + <color name="i_am_color_1d89">#00001d89</color> + <color name="i_am_color_1d8a">#00001d8a</color> + <color name="i_am_color_1d8b">#00001d8b</color> + <color name="i_am_color_1d8c">#00001d8c</color> + <color name="i_am_color_1d8d">#00001d8d</color> + <color name="i_am_color_1d8e">#00001d8e</color> + <color name="i_am_color_1d8f">#00001d8f</color> + <color name="i_am_color_1d90">#00001d90</color> + <color name="i_am_color_1d91">#00001d91</color> + <color name="i_am_color_1d92">#00001d92</color> + <color name="i_am_color_1d93">#00001d93</color> + <color name="i_am_color_1d94">#00001d94</color> + <color name="i_am_color_1d95">#00001d95</color> + <color name="i_am_color_1d96">#00001d96</color> + <color name="i_am_color_1d97">#00001d97</color> + <color name="i_am_color_1d98">#00001d98</color> + <color name="i_am_color_1d99">#00001d99</color> + <color name="i_am_color_1d9a">#00001d9a</color> + <color name="i_am_color_1d9b">#00001d9b</color> + <color name="i_am_color_1d9c">#00001d9c</color> + <color name="i_am_color_1d9d">#00001d9d</color> + <color name="i_am_color_1d9e">#00001d9e</color> + <color name="i_am_color_1d9f">#00001d9f</color> + <color name="i_am_color_1da0">#00001da0</color> + <color name="i_am_color_1da1">#00001da1</color> + <color name="i_am_color_1da2">#00001da2</color> + <color name="i_am_color_1da3">#00001da3</color> + <color name="i_am_color_1da4">#00001da4</color> + <color name="i_am_color_1da5">#00001da5</color> + <color name="i_am_color_1da6">#00001da6</color> + <color name="i_am_color_1da7">#00001da7</color> + <color name="i_am_color_1da8">#00001da8</color> + <color name="i_am_color_1da9">#00001da9</color> + <color name="i_am_color_1daa">#00001daa</color> + <color name="i_am_color_1dab">#00001dab</color> + <color name="i_am_color_1dac">#00001dac</color> + <color name="i_am_color_1dad">#00001dad</color> + <color name="i_am_color_1dae">#00001dae</color> + <color name="i_am_color_1daf">#00001daf</color> + <color name="i_am_color_1db0">#00001db0</color> + <color name="i_am_color_1db1">#00001db1</color> + <color name="i_am_color_1db2">#00001db2</color> + <color name="i_am_color_1db3">#00001db3</color> + <color name="i_am_color_1db4">#00001db4</color> + <color name="i_am_color_1db5">#00001db5</color> + <color name="i_am_color_1db6">#00001db6</color> + <color name="i_am_color_1db7">#00001db7</color> + <color name="i_am_color_1db8">#00001db8</color> + <color name="i_am_color_1db9">#00001db9</color> + <color name="i_am_color_1dba">#00001dba</color> + <color name="i_am_color_1dbb">#00001dbb</color> + <color name="i_am_color_1dbc">#00001dbc</color> + <color name="i_am_color_1dbd">#00001dbd</color> + <color name="i_am_color_1dbe">#00001dbe</color> + <color name="i_am_color_1dbf">#00001dbf</color> + <color name="i_am_color_1dc0">#00001dc0</color> + <color name="i_am_color_1dc1">#00001dc1</color> + <color name="i_am_color_1dc2">#00001dc2</color> + <color name="i_am_color_1dc3">#00001dc3</color> + <color name="i_am_color_1dc4">#00001dc4</color> + <color name="i_am_color_1dc5">#00001dc5</color> + <color name="i_am_color_1dc6">#00001dc6</color> + <color name="i_am_color_1dc7">#00001dc7</color> + <color name="i_am_color_1dc8">#00001dc8</color> + <color name="i_am_color_1dc9">#00001dc9</color> + <color name="i_am_color_1dca">#00001dca</color> + <color name="i_am_color_1dcb">#00001dcb</color> + <color name="i_am_color_1dcc">#00001dcc</color> + <color name="i_am_color_1dcd">#00001dcd</color> + <color name="i_am_color_1dce">#00001dce</color> + <color name="i_am_color_1dcf">#00001dcf</color> + <color name="i_am_color_1dd0">#00001dd0</color> + <color name="i_am_color_1dd1">#00001dd1</color> + <color name="i_am_color_1dd2">#00001dd2</color> + <color name="i_am_color_1dd3">#00001dd3</color> + <color name="i_am_color_1dd4">#00001dd4</color> + <color name="i_am_color_1dd5">#00001dd5</color> + <color name="i_am_color_1dd6">#00001dd6</color> + <color name="i_am_color_1dd7">#00001dd7</color> + <color name="i_am_color_1dd8">#00001dd8</color> + <color name="i_am_color_1dd9">#00001dd9</color> + <color name="i_am_color_1dda">#00001dda</color> + <color name="i_am_color_1ddb">#00001ddb</color> + <color name="i_am_color_1ddc">#00001ddc</color> + <color name="i_am_color_1ddd">#00001ddd</color> + <color name="i_am_color_1dde">#00001dde</color> + <color name="i_am_color_1ddf">#00001ddf</color> + <color name="i_am_color_1de0">#00001de0</color> + <color name="i_am_color_1de1">#00001de1</color> + <color name="i_am_color_1de2">#00001de2</color> + <color name="i_am_color_1de3">#00001de3</color> + <color name="i_am_color_1de4">#00001de4</color> + <color name="i_am_color_1de5">#00001de5</color> + <color name="i_am_color_1de6">#00001de6</color> + <color name="i_am_color_1de7">#00001de7</color> + <color name="i_am_color_1de8">#00001de8</color> + <color name="i_am_color_1de9">#00001de9</color> + <color name="i_am_color_1dea">#00001dea</color> + <color name="i_am_color_1deb">#00001deb</color> + <color name="i_am_color_1dec">#00001dec</color> + <color name="i_am_color_1ded">#00001ded</color> + <color name="i_am_color_1dee">#00001dee</color> + <color name="i_am_color_1def">#00001def</color> + <color name="i_am_color_1df0">#00001df0</color> + <color name="i_am_color_1df1">#00001df1</color> + <color name="i_am_color_1df2">#00001df2</color> + <color name="i_am_color_1df3">#00001df3</color> + <color name="i_am_color_1df4">#00001df4</color> + <color name="i_am_color_1df5">#00001df5</color> + <color name="i_am_color_1df6">#00001df6</color> + <color name="i_am_color_1df7">#00001df7</color> + <color name="i_am_color_1df8">#00001df8</color> + <color name="i_am_color_1df9">#00001df9</color> + <color name="i_am_color_1dfa">#00001dfa</color> + <color name="i_am_color_1dfb">#00001dfb</color> + <color name="i_am_color_1dfc">#00001dfc</color> + <color name="i_am_color_1dfd">#00001dfd</color> + <color name="i_am_color_1dfe">#00001dfe</color> + <color name="i_am_color_1dff">#00001dff</color> + <color name="i_am_color_1e00">#00001e00</color> + <color name="i_am_color_1e01">#00001e01</color> + <color name="i_am_color_1e02">#00001e02</color> + <color name="i_am_color_1e03">#00001e03</color> + <color name="i_am_color_1e04">#00001e04</color> + <color name="i_am_color_1e05">#00001e05</color> + <color name="i_am_color_1e06">#00001e06</color> + <color name="i_am_color_1e07">#00001e07</color> + <color name="i_am_color_1e08">#00001e08</color> + <color name="i_am_color_1e09">#00001e09</color> + <color name="i_am_color_1e0a">#00001e0a</color> + <color name="i_am_color_1e0b">#00001e0b</color> + <color name="i_am_color_1e0c">#00001e0c</color> + <color name="i_am_color_1e0d">#00001e0d</color> + <color name="i_am_color_1e0e">#00001e0e</color> + <color name="i_am_color_1e0f">#00001e0f</color> + <color name="i_am_color_1e10">#00001e10</color> + <color name="i_am_color_1e11">#00001e11</color> + <color name="i_am_color_1e12">#00001e12</color> + <color name="i_am_color_1e13">#00001e13</color> + <color name="i_am_color_1e14">#00001e14</color> + <color name="i_am_color_1e15">#00001e15</color> + <color name="i_am_color_1e16">#00001e16</color> + <color name="i_am_color_1e17">#00001e17</color> + <color name="i_am_color_1e18">#00001e18</color> + <color name="i_am_color_1e19">#00001e19</color> + <color name="i_am_color_1e1a">#00001e1a</color> + <color name="i_am_color_1e1b">#00001e1b</color> + <color name="i_am_color_1e1c">#00001e1c</color> + <color name="i_am_color_1e1d">#00001e1d</color> + <color name="i_am_color_1e1e">#00001e1e</color> + <color name="i_am_color_1e1f">#00001e1f</color> + <color name="i_am_color_1e20">#00001e20</color> + <color name="i_am_color_1e21">#00001e21</color> + <color name="i_am_color_1e22">#00001e22</color> + <color name="i_am_color_1e23">#00001e23</color> + <color name="i_am_color_1e24">#00001e24</color> + <color name="i_am_color_1e25">#00001e25</color> + <color name="i_am_color_1e26">#00001e26</color> + <color name="i_am_color_1e27">#00001e27</color> + <color name="i_am_color_1e28">#00001e28</color> + <color name="i_am_color_1e29">#00001e29</color> + <color name="i_am_color_1e2a">#00001e2a</color> + <color name="i_am_color_1e2b">#00001e2b</color> + <color name="i_am_color_1e2c">#00001e2c</color> + <color name="i_am_color_1e2d">#00001e2d</color> + <color name="i_am_color_1e2e">#00001e2e</color> + <color name="i_am_color_1e2f">#00001e2f</color> + <color name="i_am_color_1e30">#00001e30</color> + <color name="i_am_color_1e31">#00001e31</color> + <color name="i_am_color_1e32">#00001e32</color> + <color name="i_am_color_1e33">#00001e33</color> + <color name="i_am_color_1e34">#00001e34</color> + <color name="i_am_color_1e35">#00001e35</color> + <color name="i_am_color_1e36">#00001e36</color> + <color name="i_am_color_1e37">#00001e37</color> + <color name="i_am_color_1e38">#00001e38</color> + <color name="i_am_color_1e39">#00001e39</color> + <color name="i_am_color_1e3a">#00001e3a</color> + <color name="i_am_color_1e3b">#00001e3b</color> + <color name="i_am_color_1e3c">#00001e3c</color> + <color name="i_am_color_1e3d">#00001e3d</color> + <color name="i_am_color_1e3e">#00001e3e</color> + <color name="i_am_color_1e3f">#00001e3f</color> + <color name="i_am_color_1e40">#00001e40</color> + <color name="i_am_color_1e41">#00001e41</color> + <color name="i_am_color_1e42">#00001e42</color> + <color name="i_am_color_1e43">#00001e43</color> + <color name="i_am_color_1e44">#00001e44</color> + <color name="i_am_color_1e45">#00001e45</color> + <color name="i_am_color_1e46">#00001e46</color> + <color name="i_am_color_1e47">#00001e47</color> + <color name="i_am_color_1e48">#00001e48</color> + <color name="i_am_color_1e49">#00001e49</color> + <color name="i_am_color_1e4a">#00001e4a</color> + <color name="i_am_color_1e4b">#00001e4b</color> + <color name="i_am_color_1e4c">#00001e4c</color> + <color name="i_am_color_1e4d">#00001e4d</color> + <color name="i_am_color_1e4e">#00001e4e</color> + <color name="i_am_color_1e4f">#00001e4f</color> + <color name="i_am_color_1e50">#00001e50</color> + <color name="i_am_color_1e51">#00001e51</color> + <color name="i_am_color_1e52">#00001e52</color> + <color name="i_am_color_1e53">#00001e53</color> + <color name="i_am_color_1e54">#00001e54</color> + <color name="i_am_color_1e55">#00001e55</color> + <color name="i_am_color_1e56">#00001e56</color> + <color name="i_am_color_1e57">#00001e57</color> + <color name="i_am_color_1e58">#00001e58</color> + <color name="i_am_color_1e59">#00001e59</color> + <color name="i_am_color_1e5a">#00001e5a</color> + <color name="i_am_color_1e5b">#00001e5b</color> + <color name="i_am_color_1e5c">#00001e5c</color> + <color name="i_am_color_1e5d">#00001e5d</color> + <color name="i_am_color_1e5e">#00001e5e</color> + <color name="i_am_color_1e5f">#00001e5f</color> + <color name="i_am_color_1e60">#00001e60</color> + <color name="i_am_color_1e61">#00001e61</color> + <color name="i_am_color_1e62">#00001e62</color> + <color name="i_am_color_1e63">#00001e63</color> + <color name="i_am_color_1e64">#00001e64</color> + <color name="i_am_color_1e65">#00001e65</color> + <color name="i_am_color_1e66">#00001e66</color> + <color name="i_am_color_1e67">#00001e67</color> + <color name="i_am_color_1e68">#00001e68</color> + <color name="i_am_color_1e69">#00001e69</color> + <color name="i_am_color_1e6a">#00001e6a</color> + <color name="i_am_color_1e6b">#00001e6b</color> + <color name="i_am_color_1e6c">#00001e6c</color> + <color name="i_am_color_1e6d">#00001e6d</color> + <color name="i_am_color_1e6e">#00001e6e</color> + <color name="i_am_color_1e6f">#00001e6f</color> + <color name="i_am_color_1e70">#00001e70</color> + <color name="i_am_color_1e71">#00001e71</color> + <color name="i_am_color_1e72">#00001e72</color> + <color name="i_am_color_1e73">#00001e73</color> + <color name="i_am_color_1e74">#00001e74</color> + <color name="i_am_color_1e75">#00001e75</color> + <color name="i_am_color_1e76">#00001e76</color> + <color name="i_am_color_1e77">#00001e77</color> + <color name="i_am_color_1e78">#00001e78</color> + <color name="i_am_color_1e79">#00001e79</color> + <color name="i_am_color_1e7a">#00001e7a</color> + <color name="i_am_color_1e7b">#00001e7b</color> + <color name="i_am_color_1e7c">#00001e7c</color> + <color name="i_am_color_1e7d">#00001e7d</color> + <color name="i_am_color_1e7e">#00001e7e</color> + <color name="i_am_color_1e7f">#00001e7f</color> + <color name="i_am_color_1e80">#00001e80</color> + <color name="i_am_color_1e81">#00001e81</color> + <color name="i_am_color_1e82">#00001e82</color> + <color name="i_am_color_1e83">#00001e83</color> + <color name="i_am_color_1e84">#00001e84</color> + <color name="i_am_color_1e85">#00001e85</color> + <color name="i_am_color_1e86">#00001e86</color> + <color name="i_am_color_1e87">#00001e87</color> + <color name="i_am_color_1e88">#00001e88</color> + <color name="i_am_color_1e89">#00001e89</color> + <color name="i_am_color_1e8a">#00001e8a</color> + <color name="i_am_color_1e8b">#00001e8b</color> + <color name="i_am_color_1e8c">#00001e8c</color> + <color name="i_am_color_1e8d">#00001e8d</color> + <color name="i_am_color_1e8e">#00001e8e</color> + <color name="i_am_color_1e8f">#00001e8f</color> + <color name="i_am_color_1e90">#00001e90</color> + <color name="i_am_color_1e91">#00001e91</color> + <color name="i_am_color_1e92">#00001e92</color> + <color name="i_am_color_1e93">#00001e93</color> + <color name="i_am_color_1e94">#00001e94</color> + <color name="i_am_color_1e95">#00001e95</color> + <color name="i_am_color_1e96">#00001e96</color> + <color name="i_am_color_1e97">#00001e97</color> + <color name="i_am_color_1e98">#00001e98</color> + <color name="i_am_color_1e99">#00001e99</color> + <color name="i_am_color_1e9a">#00001e9a</color> + <color name="i_am_color_1e9b">#00001e9b</color> + <color name="i_am_color_1e9c">#00001e9c</color> + <color name="i_am_color_1e9d">#00001e9d</color> + <color name="i_am_color_1e9e">#00001e9e</color> + <color name="i_am_color_1e9f">#00001e9f</color> + <color name="i_am_color_1ea0">#00001ea0</color> + <color name="i_am_color_1ea1">#00001ea1</color> + <color name="i_am_color_1ea2">#00001ea2</color> + <color name="i_am_color_1ea3">#00001ea3</color> + <color name="i_am_color_1ea4">#00001ea4</color> + <color name="i_am_color_1ea5">#00001ea5</color> + <color name="i_am_color_1ea6">#00001ea6</color> + <color name="i_am_color_1ea7">#00001ea7</color> + <color name="i_am_color_1ea8">#00001ea8</color> + <color name="i_am_color_1ea9">#00001ea9</color> + <color name="i_am_color_1eaa">#00001eaa</color> + <color name="i_am_color_1eab">#00001eab</color> + <color name="i_am_color_1eac">#00001eac</color> + <color name="i_am_color_1ead">#00001ead</color> + <color name="i_am_color_1eae">#00001eae</color> + <color name="i_am_color_1eaf">#00001eaf</color> + <color name="i_am_color_1eb0">#00001eb0</color> + <color name="i_am_color_1eb1">#00001eb1</color> + <color name="i_am_color_1eb2">#00001eb2</color> + <color name="i_am_color_1eb3">#00001eb3</color> + <color name="i_am_color_1eb4">#00001eb4</color> + <color name="i_am_color_1eb5">#00001eb5</color> + <color name="i_am_color_1eb6">#00001eb6</color> + <color name="i_am_color_1eb7">#00001eb7</color> + <color name="i_am_color_1eb8">#00001eb8</color> + <color name="i_am_color_1eb9">#00001eb9</color> + <color name="i_am_color_1eba">#00001eba</color> + <color name="i_am_color_1ebb">#00001ebb</color> + <color name="i_am_color_1ebc">#00001ebc</color> + <color name="i_am_color_1ebd">#00001ebd</color> + <color name="i_am_color_1ebe">#00001ebe</color> + <color name="i_am_color_1ebf">#00001ebf</color> + <color name="i_am_color_1ec0">#00001ec0</color> + <color name="i_am_color_1ec1">#00001ec1</color> + <color name="i_am_color_1ec2">#00001ec2</color> + <color name="i_am_color_1ec3">#00001ec3</color> + <color name="i_am_color_1ec4">#00001ec4</color> + <color name="i_am_color_1ec5">#00001ec5</color> + <color name="i_am_color_1ec6">#00001ec6</color> + <color name="i_am_color_1ec7">#00001ec7</color> + <color name="i_am_color_1ec8">#00001ec8</color> + <color name="i_am_color_1ec9">#00001ec9</color> + <color name="i_am_color_1eca">#00001eca</color> + <color name="i_am_color_1ecb">#00001ecb</color> + <color name="i_am_color_1ecc">#00001ecc</color> + <color name="i_am_color_1ecd">#00001ecd</color> + <color name="i_am_color_1ece">#00001ece</color> + <color name="i_am_color_1ecf">#00001ecf</color> + <color name="i_am_color_1ed0">#00001ed0</color> + <color name="i_am_color_1ed1">#00001ed1</color> + <color name="i_am_color_1ed2">#00001ed2</color> + <color name="i_am_color_1ed3">#00001ed3</color> + <color name="i_am_color_1ed4">#00001ed4</color> + <color name="i_am_color_1ed5">#00001ed5</color> + <color name="i_am_color_1ed6">#00001ed6</color> + <color name="i_am_color_1ed7">#00001ed7</color> + <color name="i_am_color_1ed8">#00001ed8</color> + <color name="i_am_color_1ed9">#00001ed9</color> + <color name="i_am_color_1eda">#00001eda</color> + <color name="i_am_color_1edb">#00001edb</color> + <color name="i_am_color_1edc">#00001edc</color> + <color name="i_am_color_1edd">#00001edd</color> + <color name="i_am_color_1ede">#00001ede</color> + <color name="i_am_color_1edf">#00001edf</color> + <color name="i_am_color_1ee0">#00001ee0</color> + <color name="i_am_color_1ee1">#00001ee1</color> + <color name="i_am_color_1ee2">#00001ee2</color> + <color name="i_am_color_1ee3">#00001ee3</color> + <color name="i_am_color_1ee4">#00001ee4</color> + <color name="i_am_color_1ee5">#00001ee5</color> + <color name="i_am_color_1ee6">#00001ee6</color> + <color name="i_am_color_1ee7">#00001ee7</color> + <color name="i_am_color_1ee8">#00001ee8</color> + <color name="i_am_color_1ee9">#00001ee9</color> + <color name="i_am_color_1eea">#00001eea</color> + <color name="i_am_color_1eeb">#00001eeb</color> + <color name="i_am_color_1eec">#00001eec</color> + <color name="i_am_color_1eed">#00001eed</color> + <color name="i_am_color_1eee">#00001eee</color> + <color name="i_am_color_1eef">#00001eef</color> + <color name="i_am_color_1ef0">#00001ef0</color> + <color name="i_am_color_1ef1">#00001ef1</color> + <color name="i_am_color_1ef2">#00001ef2</color> + <color name="i_am_color_1ef3">#00001ef3</color> + <color name="i_am_color_1ef4">#00001ef4</color> + <color name="i_am_color_1ef5">#00001ef5</color> + <color name="i_am_color_1ef6">#00001ef6</color> + <color name="i_am_color_1ef7">#00001ef7</color> + <color name="i_am_color_1ef8">#00001ef8</color> + <color name="i_am_color_1ef9">#00001ef9</color> + <color name="i_am_color_1efa">#00001efa</color> + <color name="i_am_color_1efb">#00001efb</color> + <color name="i_am_color_1efc">#00001efc</color> + <color name="i_am_color_1efd">#00001efd</color> + <color name="i_am_color_1efe">#00001efe</color> + <color name="i_am_color_1eff">#00001eff</color> + <color name="i_am_color_1f00">#00001f00</color> + <color name="i_am_color_1f01">#00001f01</color> + <color name="i_am_color_1f02">#00001f02</color> + <color name="i_am_color_1f03">#00001f03</color> + <color name="i_am_color_1f04">#00001f04</color> + <color name="i_am_color_1f05">#00001f05</color> + <color name="i_am_color_1f06">#00001f06</color> + <color name="i_am_color_1f07">#00001f07</color> + <color name="i_am_color_1f08">#00001f08</color> + <color name="i_am_color_1f09">#00001f09</color> + <color name="i_am_color_1f0a">#00001f0a</color> + <color name="i_am_color_1f0b">#00001f0b</color> + <color name="i_am_color_1f0c">#00001f0c</color> + <color name="i_am_color_1f0d">#00001f0d</color> + <color name="i_am_color_1f0e">#00001f0e</color> + <color name="i_am_color_1f0f">#00001f0f</color> + <color name="i_am_color_1f10">#00001f10</color> + <color name="i_am_color_1f11">#00001f11</color> + <color name="i_am_color_1f12">#00001f12</color> + <color name="i_am_color_1f13">#00001f13</color> + <color name="i_am_color_1f14">#00001f14</color> + <color name="i_am_color_1f15">#00001f15</color> + <color name="i_am_color_1f16">#00001f16</color> + <color name="i_am_color_1f17">#00001f17</color> + <color name="i_am_color_1f18">#00001f18</color> + <color name="i_am_color_1f19">#00001f19</color> + <color name="i_am_color_1f1a">#00001f1a</color> + <color name="i_am_color_1f1b">#00001f1b</color> + <color name="i_am_color_1f1c">#00001f1c</color> + <color name="i_am_color_1f1d">#00001f1d</color> + <color name="i_am_color_1f1e">#00001f1e</color> + <color name="i_am_color_1f1f">#00001f1f</color> + <color name="i_am_color_1f20">#00001f20</color> + <color name="i_am_color_1f21">#00001f21</color> + <color name="i_am_color_1f22">#00001f22</color> + <color name="i_am_color_1f23">#00001f23</color> + <color name="i_am_color_1f24">#00001f24</color> + <color name="i_am_color_1f25">#00001f25</color> + <color name="i_am_color_1f26">#00001f26</color> + <color name="i_am_color_1f27">#00001f27</color> + <color name="i_am_color_1f28">#00001f28</color> + <color name="i_am_color_1f29">#00001f29</color> + <color name="i_am_color_1f2a">#00001f2a</color> + <color name="i_am_color_1f2b">#00001f2b</color> + <color name="i_am_color_1f2c">#00001f2c</color> + <color name="i_am_color_1f2d">#00001f2d</color> + <color name="i_am_color_1f2e">#00001f2e</color> + <color name="i_am_color_1f2f">#00001f2f</color> + <color name="i_am_color_1f30">#00001f30</color> + <color name="i_am_color_1f31">#00001f31</color> + <color name="i_am_color_1f32">#00001f32</color> + <color name="i_am_color_1f33">#00001f33</color> + <color name="i_am_color_1f34">#00001f34</color> + <color name="i_am_color_1f35">#00001f35</color> + <color name="i_am_color_1f36">#00001f36</color> + <color name="i_am_color_1f37">#00001f37</color> + <color name="i_am_color_1f38">#00001f38</color> + <color name="i_am_color_1f39">#00001f39</color> + <color name="i_am_color_1f3a">#00001f3a</color> + <color name="i_am_color_1f3b">#00001f3b</color> + <color name="i_am_color_1f3c">#00001f3c</color> + <color name="i_am_color_1f3d">#00001f3d</color> + <color name="i_am_color_1f3e">#00001f3e</color> + <color name="i_am_color_1f3f">#00001f3f</color> + <color name="i_am_color_1f40">#00001f40</color> + <color name="i_am_color_1f41">#00001f41</color> + <color name="i_am_color_1f42">#00001f42</color> + <color name="i_am_color_1f43">#00001f43</color> + <color name="i_am_color_1f44">#00001f44</color> + <color name="i_am_color_1f45">#00001f45</color> + <color name="i_am_color_1f46">#00001f46</color> + <color name="i_am_color_1f47">#00001f47</color> + <color name="i_am_color_1f48">#00001f48</color> + <color name="i_am_color_1f49">#00001f49</color> + <color name="i_am_color_1f4a">#00001f4a</color> + <color name="i_am_color_1f4b">#00001f4b</color> + <color name="i_am_color_1f4c">#00001f4c</color> + <color name="i_am_color_1f4d">#00001f4d</color> + <color name="i_am_color_1f4e">#00001f4e</color> + <color name="i_am_color_1f4f">#00001f4f</color> + <color name="i_am_color_1f50">#00001f50</color> + <color name="i_am_color_1f51">#00001f51</color> + <color name="i_am_color_1f52">#00001f52</color> + <color name="i_am_color_1f53">#00001f53</color> + <color name="i_am_color_1f54">#00001f54</color> + <color name="i_am_color_1f55">#00001f55</color> + <color name="i_am_color_1f56">#00001f56</color> + <color name="i_am_color_1f57">#00001f57</color> + <color name="i_am_color_1f58">#00001f58</color> + <color name="i_am_color_1f59">#00001f59</color> + <color name="i_am_color_1f5a">#00001f5a</color> + <color name="i_am_color_1f5b">#00001f5b</color> + <color name="i_am_color_1f5c">#00001f5c</color> + <color name="i_am_color_1f5d">#00001f5d</color> + <color name="i_am_color_1f5e">#00001f5e</color> + <color name="i_am_color_1f5f">#00001f5f</color> + <color name="i_am_color_1f60">#00001f60</color> + <color name="i_am_color_1f61">#00001f61</color> + <color name="i_am_color_1f62">#00001f62</color> + <color name="i_am_color_1f63">#00001f63</color> + <color name="i_am_color_1f64">#00001f64</color> + <color name="i_am_color_1f65">#00001f65</color> + <color name="i_am_color_1f66">#00001f66</color> + <color name="i_am_color_1f67">#00001f67</color> + <color name="i_am_color_1f68">#00001f68</color> + <color name="i_am_color_1f69">#00001f69</color> + <color name="i_am_color_1f6a">#00001f6a</color> + <color name="i_am_color_1f6b">#00001f6b</color> + <color name="i_am_color_1f6c">#00001f6c</color> + <color name="i_am_color_1f6d">#00001f6d</color> + <color name="i_am_color_1f6e">#00001f6e</color> + <color name="i_am_color_1f6f">#00001f6f</color> + <color name="i_am_color_1f70">#00001f70</color> + <color name="i_am_color_1f71">#00001f71</color> + <color name="i_am_color_1f72">#00001f72</color> + <color name="i_am_color_1f73">#00001f73</color> + <color name="i_am_color_1f74">#00001f74</color> + <color name="i_am_color_1f75">#00001f75</color> + <color name="i_am_color_1f76">#00001f76</color> + <color name="i_am_color_1f77">#00001f77</color> + <color name="i_am_color_1f78">#00001f78</color> + <color name="i_am_color_1f79">#00001f79</color> + <color name="i_am_color_1f7a">#00001f7a</color> + <color name="i_am_color_1f7b">#00001f7b</color> + <color name="i_am_color_1f7c">#00001f7c</color> + <color name="i_am_color_1f7d">#00001f7d</color> + <color name="i_am_color_1f7e">#00001f7e</color> + <color name="i_am_color_1f7f">#00001f7f</color> + <color name="i_am_color_1f80">#00001f80</color> + <color name="i_am_color_1f81">#00001f81</color> + <color name="i_am_color_1f82">#00001f82</color> + <color name="i_am_color_1f83">#00001f83</color> + <color name="i_am_color_1f84">#00001f84</color> + <color name="i_am_color_1f85">#00001f85</color> + <color name="i_am_color_1f86">#00001f86</color> + <color name="i_am_color_1f87">#00001f87</color> + <color name="i_am_color_1f88">#00001f88</color> + <color name="i_am_color_1f89">#00001f89</color> + <color name="i_am_color_1f8a">#00001f8a</color> + <color name="i_am_color_1f8b">#00001f8b</color> + <color name="i_am_color_1f8c">#00001f8c</color> + <color name="i_am_color_1f8d">#00001f8d</color> + <color name="i_am_color_1f8e">#00001f8e</color> + <color name="i_am_color_1f8f">#00001f8f</color> + <color name="i_am_color_1f90">#00001f90</color> + <color name="i_am_color_1f91">#00001f91</color> + <color name="i_am_color_1f92">#00001f92</color> + <color name="i_am_color_1f93">#00001f93</color> + <color name="i_am_color_1f94">#00001f94</color> + <color name="i_am_color_1f95">#00001f95</color> + <color name="i_am_color_1f96">#00001f96</color> + <color name="i_am_color_1f97">#00001f97</color> + <color name="i_am_color_1f98">#00001f98</color> + <color name="i_am_color_1f99">#00001f99</color> + <color name="i_am_color_1f9a">#00001f9a</color> + <color name="i_am_color_1f9b">#00001f9b</color> + <color name="i_am_color_1f9c">#00001f9c</color> + <color name="i_am_color_1f9d">#00001f9d</color> + <color name="i_am_color_1f9e">#00001f9e</color> + <color name="i_am_color_1f9f">#00001f9f</color> + <color name="i_am_color_1fa0">#00001fa0</color> + <color name="i_am_color_1fa1">#00001fa1</color> + <color name="i_am_color_1fa2">#00001fa2</color> + <color name="i_am_color_1fa3">#00001fa3</color> + <color name="i_am_color_1fa4">#00001fa4</color> + <color name="i_am_color_1fa5">#00001fa5</color> + <color name="i_am_color_1fa6">#00001fa6</color> + <color name="i_am_color_1fa7">#00001fa7</color> + <color name="i_am_color_1fa8">#00001fa8</color> + <color name="i_am_color_1fa9">#00001fa9</color> + <color name="i_am_color_1faa">#00001faa</color> + <color name="i_am_color_1fab">#00001fab</color> + <color name="i_am_color_1fac">#00001fac</color> + <color name="i_am_color_1fad">#00001fad</color> + <color name="i_am_color_1fae">#00001fae</color> + <color name="i_am_color_1faf">#00001faf</color> + <color name="i_am_color_1fb0">#00001fb0</color> + <color name="i_am_color_1fb1">#00001fb1</color> + <color name="i_am_color_1fb2">#00001fb2</color> + <color name="i_am_color_1fb3">#00001fb3</color> + <color name="i_am_color_1fb4">#00001fb4</color> + <color name="i_am_color_1fb5">#00001fb5</color> + <color name="i_am_color_1fb6">#00001fb6</color> + <color name="i_am_color_1fb7">#00001fb7</color> + <color name="i_am_color_1fb8">#00001fb8</color> + <color name="i_am_color_1fb9">#00001fb9</color> + <color name="i_am_color_1fba">#00001fba</color> + <color name="i_am_color_1fbb">#00001fbb</color> + <color name="i_am_color_1fbc">#00001fbc</color> + <color name="i_am_color_1fbd">#00001fbd</color> + <color name="i_am_color_1fbe">#00001fbe</color> + <color name="i_am_color_1fbf">#00001fbf</color> + <color name="i_am_color_1fc0">#00001fc0</color> + <color name="i_am_color_1fc1">#00001fc1</color> + <color name="i_am_color_1fc2">#00001fc2</color> + <color name="i_am_color_1fc3">#00001fc3</color> + <color name="i_am_color_1fc4">#00001fc4</color> + <color name="i_am_color_1fc5">#00001fc5</color> + <color name="i_am_color_1fc6">#00001fc6</color> + <color name="i_am_color_1fc7">#00001fc7</color> + <color name="i_am_color_1fc8">#00001fc8</color> + <color name="i_am_color_1fc9">#00001fc9</color> + <color name="i_am_color_1fca">#00001fca</color> + <color name="i_am_color_1fcb">#00001fcb</color> + <color name="i_am_color_1fcc">#00001fcc</color> + <color name="i_am_color_1fcd">#00001fcd</color> + <color name="i_am_color_1fce">#00001fce</color> + <color name="i_am_color_1fcf">#00001fcf</color> + <color name="i_am_color_1fd0">#00001fd0</color> + <color name="i_am_color_1fd1">#00001fd1</color> + <color name="i_am_color_1fd2">#00001fd2</color> + <color name="i_am_color_1fd3">#00001fd3</color> + <color name="i_am_color_1fd4">#00001fd4</color> + <color name="i_am_color_1fd5">#00001fd5</color> + <color name="i_am_color_1fd6">#00001fd6</color> + <color name="i_am_color_1fd7">#00001fd7</color> + <color name="i_am_color_1fd8">#00001fd8</color> + <color name="i_am_color_1fd9">#00001fd9</color> + <color name="i_am_color_1fda">#00001fda</color> + <color name="i_am_color_1fdb">#00001fdb</color> + <color name="i_am_color_1fdc">#00001fdc</color> + <color name="i_am_color_1fdd">#00001fdd</color> + <color name="i_am_color_1fde">#00001fde</color> + <color name="i_am_color_1fdf">#00001fdf</color> + <color name="i_am_color_1fe0">#00001fe0</color> + <color name="i_am_color_1fe1">#00001fe1</color> + <color name="i_am_color_1fe2">#00001fe2</color> + <color name="i_am_color_1fe3">#00001fe3</color> + <color name="i_am_color_1fe4">#00001fe4</color> + <color name="i_am_color_1fe5">#00001fe5</color> + <color name="i_am_color_1fe6">#00001fe6</color> + <color name="i_am_color_1fe7">#00001fe7</color> + <color name="i_am_color_1fe8">#00001fe8</color> + <color name="i_am_color_1fe9">#00001fe9</color> + <color name="i_am_color_1fea">#00001fea</color> + <color name="i_am_color_1feb">#00001feb</color> + <color name="i_am_color_1fec">#00001fec</color> + <color name="i_am_color_1fed">#00001fed</color> + <color name="i_am_color_1fee">#00001fee</color> + <color name="i_am_color_1fef">#00001fef</color> + <color name="i_am_color_1ff0">#00001ff0</color> + <color name="i_am_color_1ff1">#00001ff1</color> + <color name="i_am_color_1ff2">#00001ff2</color> + <color name="i_am_color_1ff3">#00001ff3</color> + <color name="i_am_color_1ff4">#00001ff4</color> + <color name="i_am_color_1ff5">#00001ff5</color> + <color name="i_am_color_1ff6">#00001ff6</color> + <color name="i_am_color_1ff7">#00001ff7</color> + <color name="i_am_color_1ff8">#00001ff8</color> + <color name="i_am_color_1ff9">#00001ff9</color> + <color name="i_am_color_1ffa">#00001ffa</color> + <color name="i_am_color_1ffb">#00001ffb</color> + <color name="i_am_color_1ffc">#00001ffc</color> + <color name="i_am_color_1ffd">#00001ffd</color> + <color name="i_am_color_1ffe">#00001ffe</color> + <color name="i_am_color_1fff">#00001fff</color> + <color name="i_am_color_2000">#00002000</color> + <color name="i_am_color_2001">#00002001</color> + <color name="i_am_color_2002">#00002002</color> + <color name="i_am_color_2003">#00002003</color> + <color name="i_am_color_2004">#00002004</color> + <color name="i_am_color_2005">#00002005</color> + <color name="i_am_color_2006">#00002006</color> + <color name="i_am_color_2007">#00002007</color> + <color name="i_am_color_2008">#00002008</color> + <color name="i_am_color_2009">#00002009</color> + <color name="i_am_color_200a">#0000200a</color> + <color name="i_am_color_200b">#0000200b</color> + <color name="i_am_color_200c">#0000200c</color> + <color name="i_am_color_200d">#0000200d</color> + <color name="i_am_color_200e">#0000200e</color> + <color name="i_am_color_200f">#0000200f</color> + <color name="i_am_color_2010">#00002010</color> + <color name="i_am_color_2011">#00002011</color> + <color name="i_am_color_2012">#00002012</color> + <color name="i_am_color_2013">#00002013</color> + <color name="i_am_color_2014">#00002014</color> + <color name="i_am_color_2015">#00002015</color> + <color name="i_am_color_2016">#00002016</color> + <color name="i_am_color_2017">#00002017</color> + <color name="i_am_color_2018">#00002018</color> + <color name="i_am_color_2019">#00002019</color> + <color name="i_am_color_201a">#0000201a</color> + <color name="i_am_color_201b">#0000201b</color> + <color name="i_am_color_201c">#0000201c</color> + <color name="i_am_color_201d">#0000201d</color> + <color name="i_am_color_201e">#0000201e</color> + <color name="i_am_color_201f">#0000201f</color> + <color name="i_am_color_2020">#00002020</color> + <color name="i_am_color_2021">#00002021</color> + <color name="i_am_color_2022">#00002022</color> + <color name="i_am_color_2023">#00002023</color> + <color name="i_am_color_2024">#00002024</color> + <color name="i_am_color_2025">#00002025</color> + <color name="i_am_color_2026">#00002026</color> + <color name="i_am_color_2027">#00002027</color> + <color name="i_am_color_2028">#00002028</color> + <color name="i_am_color_2029">#00002029</color> + <color name="i_am_color_202a">#0000202a</color> + <color name="i_am_color_202b">#0000202b</color> + <color name="i_am_color_202c">#0000202c</color> + <color name="i_am_color_202d">#0000202d</color> + <color name="i_am_color_202e">#0000202e</color> + <color name="i_am_color_202f">#0000202f</color> + <color name="i_am_color_2030">#00002030</color> + <color name="i_am_color_2031">#00002031</color> + <color name="i_am_color_2032">#00002032</color> + <color name="i_am_color_2033">#00002033</color> + <color name="i_am_color_2034">#00002034</color> + <color name="i_am_color_2035">#00002035</color> + <color name="i_am_color_2036">#00002036</color> + <color name="i_am_color_2037">#00002037</color> + <color name="i_am_color_2038">#00002038</color> + <color name="i_am_color_2039">#00002039</color> + <color name="i_am_color_203a">#0000203a</color> + <color name="i_am_color_203b">#0000203b</color> + <color name="i_am_color_203c">#0000203c</color> + <color name="i_am_color_203d">#0000203d</color> + <color name="i_am_color_203e">#0000203e</color> + <color name="i_am_color_203f">#0000203f</color> + <color name="i_am_color_2040">#00002040</color> + <color name="i_am_color_2041">#00002041</color> + <color name="i_am_color_2042">#00002042</color> + <color name="i_am_color_2043">#00002043</color> + <color name="i_am_color_2044">#00002044</color> + <color name="i_am_color_2045">#00002045</color> + <color name="i_am_color_2046">#00002046</color> + <color name="i_am_color_2047">#00002047</color> + <color name="i_am_color_2048">#00002048</color> + <color name="i_am_color_2049">#00002049</color> + <color name="i_am_color_204a">#0000204a</color> + <color name="i_am_color_204b">#0000204b</color> + <color name="i_am_color_204c">#0000204c</color> + <color name="i_am_color_204d">#0000204d</color> + <color name="i_am_color_204e">#0000204e</color> + <color name="i_am_color_204f">#0000204f</color> + <color name="i_am_color_2050">#00002050</color> + <color name="i_am_color_2051">#00002051</color> + <color name="i_am_color_2052">#00002052</color> + <color name="i_am_color_2053">#00002053</color> + <color name="i_am_color_2054">#00002054</color> + <color name="i_am_color_2055">#00002055</color> + <color name="i_am_color_2056">#00002056</color> + <color name="i_am_color_2057">#00002057</color> + <color name="i_am_color_2058">#00002058</color> + <color name="i_am_color_2059">#00002059</color> + <color name="i_am_color_205a">#0000205a</color> + <color name="i_am_color_205b">#0000205b</color> + <color name="i_am_color_205c">#0000205c</color> + <color name="i_am_color_205d">#0000205d</color> + <color name="i_am_color_205e">#0000205e</color> + <color name="i_am_color_205f">#0000205f</color> + <color name="i_am_color_2060">#00002060</color> + <color name="i_am_color_2061">#00002061</color> + <color name="i_am_color_2062">#00002062</color> + <color name="i_am_color_2063">#00002063</color> + <color name="i_am_color_2064">#00002064</color> + <color name="i_am_color_2065">#00002065</color> + <color name="i_am_color_2066">#00002066</color> + <color name="i_am_color_2067">#00002067</color> + <color name="i_am_color_2068">#00002068</color> + <color name="i_am_color_2069">#00002069</color> + <color name="i_am_color_206a">#0000206a</color> + <color name="i_am_color_206b">#0000206b</color> + <color name="i_am_color_206c">#0000206c</color> + <color name="i_am_color_206d">#0000206d</color> + <color name="i_am_color_206e">#0000206e</color> + <color name="i_am_color_206f">#0000206f</color> + <color name="i_am_color_2070">#00002070</color> + <color name="i_am_color_2071">#00002071</color> + <color name="i_am_color_2072">#00002072</color> + <color name="i_am_color_2073">#00002073</color> + <color name="i_am_color_2074">#00002074</color> + <color name="i_am_color_2075">#00002075</color> + <color name="i_am_color_2076">#00002076</color> + <color name="i_am_color_2077">#00002077</color> + <color name="i_am_color_2078">#00002078</color> + <color name="i_am_color_2079">#00002079</color> + <color name="i_am_color_207a">#0000207a</color> + <color name="i_am_color_207b">#0000207b</color> + <color name="i_am_color_207c">#0000207c</color> + <color name="i_am_color_207d">#0000207d</color> + <color name="i_am_color_207e">#0000207e</color> + <color name="i_am_color_207f">#0000207f</color> + <color name="i_am_color_2080">#00002080</color> + <color name="i_am_color_2081">#00002081</color> + <color name="i_am_color_2082">#00002082</color> + <color name="i_am_color_2083">#00002083</color> + <color name="i_am_color_2084">#00002084</color> + <color name="i_am_color_2085">#00002085</color> + <color name="i_am_color_2086">#00002086</color> + <color name="i_am_color_2087">#00002087</color> + <color name="i_am_color_2088">#00002088</color> + <color name="i_am_color_2089">#00002089</color> + <color name="i_am_color_208a">#0000208a</color> + <color name="i_am_color_208b">#0000208b</color> + <color name="i_am_color_208c">#0000208c</color> + <color name="i_am_color_208d">#0000208d</color> + <color name="i_am_color_208e">#0000208e</color> + <color name="i_am_color_208f">#0000208f</color> + <color name="i_am_color_2090">#00002090</color> + <color name="i_am_color_2091">#00002091</color> + <color name="i_am_color_2092">#00002092</color> + <color name="i_am_color_2093">#00002093</color> + <color name="i_am_color_2094">#00002094</color> + <color name="i_am_color_2095">#00002095</color> + <color name="i_am_color_2096">#00002096</color> + <color name="i_am_color_2097">#00002097</color> + <color name="i_am_color_2098">#00002098</color> + <color name="i_am_color_2099">#00002099</color> + <color name="i_am_color_209a">#0000209a</color> + <color name="i_am_color_209b">#0000209b</color> + <color name="i_am_color_209c">#0000209c</color> + <color name="i_am_color_209d">#0000209d</color> + <color name="i_am_color_209e">#0000209e</color> + <color name="i_am_color_209f">#0000209f</color> + <color name="i_am_color_20a0">#000020a0</color> + <color name="i_am_color_20a1">#000020a1</color> + <color name="i_am_color_20a2">#000020a2</color> + <color name="i_am_color_20a3">#000020a3</color> + <color name="i_am_color_20a4">#000020a4</color> + <color name="i_am_color_20a5">#000020a5</color> + <color name="i_am_color_20a6">#000020a6</color> + <color name="i_am_color_20a7">#000020a7</color> + <color name="i_am_color_20a8">#000020a8</color> + <color name="i_am_color_20a9">#000020a9</color> + <color name="i_am_color_20aa">#000020aa</color> + <color name="i_am_color_20ab">#000020ab</color> + <color name="i_am_color_20ac">#000020ac</color> + <color name="i_am_color_20ad">#000020ad</color> + <color name="i_am_color_20ae">#000020ae</color> + <color name="i_am_color_20af">#000020af</color> + <color name="i_am_color_20b0">#000020b0</color> + <color name="i_am_color_20b1">#000020b1</color> + <color name="i_am_color_20b2">#000020b2</color> + <color name="i_am_color_20b3">#000020b3</color> + <color name="i_am_color_20b4">#000020b4</color> + <color name="i_am_color_20b5">#000020b5</color> + <color name="i_am_color_20b6">#000020b6</color> + <color name="i_am_color_20b7">#000020b7</color> + <color name="i_am_color_20b8">#000020b8</color> + <color name="i_am_color_20b9">#000020b9</color> + <color name="i_am_color_20ba">#000020ba</color> + <color name="i_am_color_20bb">#000020bb</color> + <color name="i_am_color_20bc">#000020bc</color> + <color name="i_am_color_20bd">#000020bd</color> + <color name="i_am_color_20be">#000020be</color> + <color name="i_am_color_20bf">#000020bf</color> + <color name="i_am_color_20c0">#000020c0</color> + <color name="i_am_color_20c1">#000020c1</color> + <color name="i_am_color_20c2">#000020c2</color> + <color name="i_am_color_20c3">#000020c3</color> + <color name="i_am_color_20c4">#000020c4</color> + <color name="i_am_color_20c5">#000020c5</color> + <color name="i_am_color_20c6">#000020c6</color> + <color name="i_am_color_20c7">#000020c7</color> + <color name="i_am_color_20c8">#000020c8</color> + <color name="i_am_color_20c9">#000020c9</color> + <color name="i_am_color_20ca">#000020ca</color> + <color name="i_am_color_20cb">#000020cb</color> + <color name="i_am_color_20cc">#000020cc</color> + <color name="i_am_color_20cd">#000020cd</color> + <color name="i_am_color_20ce">#000020ce</color> + <color name="i_am_color_20cf">#000020cf</color> + <color name="i_am_color_20d0">#000020d0</color> + <color name="i_am_color_20d1">#000020d1</color> + <color name="i_am_color_20d2">#000020d2</color> + <color name="i_am_color_20d3">#000020d3</color> + <color name="i_am_color_20d4">#000020d4</color> + <color name="i_am_color_20d5">#000020d5</color> + <color name="i_am_color_20d6">#000020d6</color> + <color name="i_am_color_20d7">#000020d7</color> + <color name="i_am_color_20d8">#000020d8</color> + <color name="i_am_color_20d9">#000020d9</color> + <color name="i_am_color_20da">#000020da</color> + <color name="i_am_color_20db">#000020db</color> + <color name="i_am_color_20dc">#000020dc</color> + <color name="i_am_color_20dd">#000020dd</color> + <color name="i_am_color_20de">#000020de</color> + <color name="i_am_color_20df">#000020df</color> + <color name="i_am_color_20e0">#000020e0</color> + <color name="i_am_color_20e1">#000020e1</color> + <color name="i_am_color_20e2">#000020e2</color> + <color name="i_am_color_20e3">#000020e3</color> + <color name="i_am_color_20e4">#000020e4</color> + <color name="i_am_color_20e5">#000020e5</color> + <color name="i_am_color_20e6">#000020e6</color> + <color name="i_am_color_20e7">#000020e7</color> + <color name="i_am_color_20e8">#000020e8</color> + <color name="i_am_color_20e9">#000020e9</color> + <color name="i_am_color_20ea">#000020ea</color> + <color name="i_am_color_20eb">#000020eb</color> + <color name="i_am_color_20ec">#000020ec</color> + <color name="i_am_color_20ed">#000020ed</color> + <color name="i_am_color_20ee">#000020ee</color> + <color name="i_am_color_20ef">#000020ef</color> + <color name="i_am_color_20f0">#000020f0</color> + <color name="i_am_color_20f1">#000020f1</color> + <color name="i_am_color_20f2">#000020f2</color> + <color name="i_am_color_20f3">#000020f3</color> + <color name="i_am_color_20f4">#000020f4</color> + <color name="i_am_color_20f5">#000020f5</color> + <color name="i_am_color_20f6">#000020f6</color> + <color name="i_am_color_20f7">#000020f7</color> + <color name="i_am_color_20f8">#000020f8</color> + <color name="i_am_color_20f9">#000020f9</color> + <color name="i_am_color_20fa">#000020fa</color> + <color name="i_am_color_20fb">#000020fb</color> + <color name="i_am_color_20fc">#000020fc</color> + <color name="i_am_color_20fd">#000020fd</color> + <color name="i_am_color_20fe">#000020fe</color> + <color name="i_am_color_20ff">#000020ff</color> + <color name="i_am_color_2100">#00002100</color> + <color name="i_am_color_2101">#00002101</color> + <color name="i_am_color_2102">#00002102</color> + <color name="i_am_color_2103">#00002103</color> + <color name="i_am_color_2104">#00002104</color> + <color name="i_am_color_2105">#00002105</color> + <color name="i_am_color_2106">#00002106</color> + <color name="i_am_color_2107">#00002107</color> + <color name="i_am_color_2108">#00002108</color> + <color name="i_am_color_2109">#00002109</color> + <color name="i_am_color_210a">#0000210a</color> + <color name="i_am_color_210b">#0000210b</color> + <color name="i_am_color_210c">#0000210c</color> + <color name="i_am_color_210d">#0000210d</color> + <color name="i_am_color_210e">#0000210e</color> + <color name="i_am_color_210f">#0000210f</color> + <color name="i_am_color_2110">#00002110</color> + <color name="i_am_color_2111">#00002111</color> + <color name="i_am_color_2112">#00002112</color> + <color name="i_am_color_2113">#00002113</color> + <color name="i_am_color_2114">#00002114</color> + <color name="i_am_color_2115">#00002115</color> + <color name="i_am_color_2116">#00002116</color> + <color name="i_am_color_2117">#00002117</color> + <color name="i_am_color_2118">#00002118</color> + <color name="i_am_color_2119">#00002119</color> + <color name="i_am_color_211a">#0000211a</color> + <color name="i_am_color_211b">#0000211b</color> + <color name="i_am_color_211c">#0000211c</color> + <color name="i_am_color_211d">#0000211d</color> + <color name="i_am_color_211e">#0000211e</color> + <color name="i_am_color_211f">#0000211f</color> + <color name="i_am_color_2120">#00002120</color> + <color name="i_am_color_2121">#00002121</color> + <color name="i_am_color_2122">#00002122</color> + <color name="i_am_color_2123">#00002123</color> + <color name="i_am_color_2124">#00002124</color> + <color name="i_am_color_2125">#00002125</color> + <color name="i_am_color_2126">#00002126</color> + <color name="i_am_color_2127">#00002127</color> + <color name="i_am_color_2128">#00002128</color> + <color name="i_am_color_2129">#00002129</color> + <color name="i_am_color_212a">#0000212a</color> + <color name="i_am_color_212b">#0000212b</color> + <color name="i_am_color_212c">#0000212c</color> + <color name="i_am_color_212d">#0000212d</color> + <color name="i_am_color_212e">#0000212e</color> + <color name="i_am_color_212f">#0000212f</color> + <color name="i_am_color_2130">#00002130</color> + <color name="i_am_color_2131">#00002131</color> + <color name="i_am_color_2132">#00002132</color> + <color name="i_am_color_2133">#00002133</color> + <color name="i_am_color_2134">#00002134</color> + <color name="i_am_color_2135">#00002135</color> + <color name="i_am_color_2136">#00002136</color> + <color name="i_am_color_2137">#00002137</color> + <color name="i_am_color_2138">#00002138</color> + <color name="i_am_color_2139">#00002139</color> + <color name="i_am_color_213a">#0000213a</color> + <color name="i_am_color_213b">#0000213b</color> + <color name="i_am_color_213c">#0000213c</color> + <color name="i_am_color_213d">#0000213d</color> + <color name="i_am_color_213e">#0000213e</color> + <color name="i_am_color_213f">#0000213f</color> + <color name="i_am_color_2140">#00002140</color> + <color name="i_am_color_2141">#00002141</color> + <color name="i_am_color_2142">#00002142</color> + <color name="i_am_color_2143">#00002143</color> + <color name="i_am_color_2144">#00002144</color> + <color name="i_am_color_2145">#00002145</color> + <color name="i_am_color_2146">#00002146</color> + <color name="i_am_color_2147">#00002147</color> + <color name="i_am_color_2148">#00002148</color> + <color name="i_am_color_2149">#00002149</color> + <color name="i_am_color_214a">#0000214a</color> + <color name="i_am_color_214b">#0000214b</color> + <color name="i_am_color_214c">#0000214c</color> + <color name="i_am_color_214d">#0000214d</color> + <color name="i_am_color_214e">#0000214e</color> + <color name="i_am_color_214f">#0000214f</color> + <color name="i_am_color_2150">#00002150</color> + <color name="i_am_color_2151">#00002151</color> + <color name="i_am_color_2152">#00002152</color> + <color name="i_am_color_2153">#00002153</color> + <color name="i_am_color_2154">#00002154</color> + <color name="i_am_color_2155">#00002155</color> + <color name="i_am_color_2156">#00002156</color> + <color name="i_am_color_2157">#00002157</color> + <color name="i_am_color_2158">#00002158</color> + <color name="i_am_color_2159">#00002159</color> + <color name="i_am_color_215a">#0000215a</color> + <color name="i_am_color_215b">#0000215b</color> + <color name="i_am_color_215c">#0000215c</color> + <color name="i_am_color_215d">#0000215d</color> + <color name="i_am_color_215e">#0000215e</color> + <color name="i_am_color_215f">#0000215f</color> + <color name="i_am_color_2160">#00002160</color> + <color name="i_am_color_2161">#00002161</color> + <color name="i_am_color_2162">#00002162</color> + <color name="i_am_color_2163">#00002163</color> + <color name="i_am_color_2164">#00002164</color> + <color name="i_am_color_2165">#00002165</color> + <color name="i_am_color_2166">#00002166</color> + <color name="i_am_color_2167">#00002167</color> + <color name="i_am_color_2168">#00002168</color> + <color name="i_am_color_2169">#00002169</color> + <color name="i_am_color_216a">#0000216a</color> + <color name="i_am_color_216b">#0000216b</color> + <color name="i_am_color_216c">#0000216c</color> + <color name="i_am_color_216d">#0000216d</color> + <color name="i_am_color_216e">#0000216e</color> + <color name="i_am_color_216f">#0000216f</color> + <color name="i_am_color_2170">#00002170</color> + <color name="i_am_color_2171">#00002171</color> + <color name="i_am_color_2172">#00002172</color> + <color name="i_am_color_2173">#00002173</color> + <color name="i_am_color_2174">#00002174</color> + <color name="i_am_color_2175">#00002175</color> + <color name="i_am_color_2176">#00002176</color> + <color name="i_am_color_2177">#00002177</color> + <color name="i_am_color_2178">#00002178</color> + <color name="i_am_color_2179">#00002179</color> + <color name="i_am_color_217a">#0000217a</color> + <color name="i_am_color_217b">#0000217b</color> + <color name="i_am_color_217c">#0000217c</color> + <color name="i_am_color_217d">#0000217d</color> + <color name="i_am_color_217e">#0000217e</color> + <color name="i_am_color_217f">#0000217f</color> + <color name="i_am_color_2180">#00002180</color> + <color name="i_am_color_2181">#00002181</color> + <color name="i_am_color_2182">#00002182</color> + <color name="i_am_color_2183">#00002183</color> + <color name="i_am_color_2184">#00002184</color> + <color name="i_am_color_2185">#00002185</color> + <color name="i_am_color_2186">#00002186</color> + <color name="i_am_color_2187">#00002187</color> + <color name="i_am_color_2188">#00002188</color> + <color name="i_am_color_2189">#00002189</color> + <color name="i_am_color_218a">#0000218a</color> + <color name="i_am_color_218b">#0000218b</color> + <color name="i_am_color_218c">#0000218c</color> + <color name="i_am_color_218d">#0000218d</color> + <color name="i_am_color_218e">#0000218e</color> + <color name="i_am_color_218f">#0000218f</color> + <color name="i_am_color_2190">#00002190</color> + <color name="i_am_color_2191">#00002191</color> + <color name="i_am_color_2192">#00002192</color> + <color name="i_am_color_2193">#00002193</color> + <color name="i_am_color_2194">#00002194</color> + <color name="i_am_color_2195">#00002195</color> + <color name="i_am_color_2196">#00002196</color> + <color name="i_am_color_2197">#00002197</color> + <color name="i_am_color_2198">#00002198</color> + <color name="i_am_color_2199">#00002199</color> + <color name="i_am_color_219a">#0000219a</color> + <color name="i_am_color_219b">#0000219b</color> + <color name="i_am_color_219c">#0000219c</color> + <color name="i_am_color_219d">#0000219d</color> + <color name="i_am_color_219e">#0000219e</color> + <color name="i_am_color_219f">#0000219f</color> + <color name="i_am_color_21a0">#000021a0</color> + <color name="i_am_color_21a1">#000021a1</color> + <color name="i_am_color_21a2">#000021a2</color> + <color name="i_am_color_21a3">#000021a3</color> + <color name="i_am_color_21a4">#000021a4</color> + <color name="i_am_color_21a5">#000021a5</color> + <color name="i_am_color_21a6">#000021a6</color> + <color name="i_am_color_21a7">#000021a7</color> + <color name="i_am_color_21a8">#000021a8</color> + <color name="i_am_color_21a9">#000021a9</color> + <color name="i_am_color_21aa">#000021aa</color> + <color name="i_am_color_21ab">#000021ab</color> + <color name="i_am_color_21ac">#000021ac</color> + <color name="i_am_color_21ad">#000021ad</color> + <color name="i_am_color_21ae">#000021ae</color> + <color name="i_am_color_21af">#000021af</color> + <color name="i_am_color_21b0">#000021b0</color> + <color name="i_am_color_21b1">#000021b1</color> + <color name="i_am_color_21b2">#000021b2</color> + <color name="i_am_color_21b3">#000021b3</color> + <color name="i_am_color_21b4">#000021b4</color> + <color name="i_am_color_21b5">#000021b5</color> + <color name="i_am_color_21b6">#000021b6</color> + <color name="i_am_color_21b7">#000021b7</color> + <color name="i_am_color_21b8">#000021b8</color> + <color name="i_am_color_21b9">#000021b9</color> + <color name="i_am_color_21ba">#000021ba</color> + <color name="i_am_color_21bb">#000021bb</color> + <color name="i_am_color_21bc">#000021bc</color> + <color name="i_am_color_21bd">#000021bd</color> + <color name="i_am_color_21be">#000021be</color> + <color name="i_am_color_21bf">#000021bf</color> + <color name="i_am_color_21c0">#000021c0</color> + <color name="i_am_color_21c1">#000021c1</color> + <color name="i_am_color_21c2">#000021c2</color> + <color name="i_am_color_21c3">#000021c3</color> + <color name="i_am_color_21c4">#000021c4</color> + <color name="i_am_color_21c5">#000021c5</color> + <color name="i_am_color_21c6">#000021c6</color> + <color name="i_am_color_21c7">#000021c7</color> + <color name="i_am_color_21c8">#000021c8</color> + <color name="i_am_color_21c9">#000021c9</color> + <color name="i_am_color_21ca">#000021ca</color> + <color name="i_am_color_21cb">#000021cb</color> + <color name="i_am_color_21cc">#000021cc</color> + <color name="i_am_color_21cd">#000021cd</color> + <color name="i_am_color_21ce">#000021ce</color> + <color name="i_am_color_21cf">#000021cf</color> + <color name="i_am_color_21d0">#000021d0</color> + <color name="i_am_color_21d1">#000021d1</color> + <color name="i_am_color_21d2">#000021d2</color> + <color name="i_am_color_21d3">#000021d3</color> + <color name="i_am_color_21d4">#000021d4</color> + <color name="i_am_color_21d5">#000021d5</color> + <color name="i_am_color_21d6">#000021d6</color> + <color name="i_am_color_21d7">#000021d7</color> + <color name="i_am_color_21d8">#000021d8</color> + <color name="i_am_color_21d9">#000021d9</color> + <color name="i_am_color_21da">#000021da</color> + <color name="i_am_color_21db">#000021db</color> + <color name="i_am_color_21dc">#000021dc</color> + <color name="i_am_color_21dd">#000021dd</color> + <color name="i_am_color_21de">#000021de</color> + <color name="i_am_color_21df">#000021df</color> + <color name="i_am_color_21e0">#000021e0</color> + <color name="i_am_color_21e1">#000021e1</color> + <color name="i_am_color_21e2">#000021e2</color> + <color name="i_am_color_21e3">#000021e3</color> + <color name="i_am_color_21e4">#000021e4</color> + <color name="i_am_color_21e5">#000021e5</color> + <color name="i_am_color_21e6">#000021e6</color> + <color name="i_am_color_21e7">#000021e7</color> + <color name="i_am_color_21e8">#000021e8</color> + <color name="i_am_color_21e9">#000021e9</color> + <color name="i_am_color_21ea">#000021ea</color> + <color name="i_am_color_21eb">#000021eb</color> + <color name="i_am_color_21ec">#000021ec</color> + <color name="i_am_color_21ed">#000021ed</color> + <color name="i_am_color_21ee">#000021ee</color> + <color name="i_am_color_21ef">#000021ef</color> + <color name="i_am_color_21f0">#000021f0</color> + <color name="i_am_color_21f1">#000021f1</color> + <color name="i_am_color_21f2">#000021f2</color> + <color name="i_am_color_21f3">#000021f3</color> + <color name="i_am_color_21f4">#000021f4</color> + <color name="i_am_color_21f5">#000021f5</color> + <color name="i_am_color_21f6">#000021f6</color> + <color name="i_am_color_21f7">#000021f7</color> + <color name="i_am_color_21f8">#000021f8</color> + <color name="i_am_color_21f9">#000021f9</color> + <color name="i_am_color_21fa">#000021fa</color> + <color name="i_am_color_21fb">#000021fb</color> + <color name="i_am_color_21fc">#000021fc</color> + <color name="i_am_color_21fd">#000021fd</color> + <color name="i_am_color_21fe">#000021fe</color> + <color name="i_am_color_21ff">#000021ff</color> + <color name="i_am_color_2200">#00002200</color> + <color name="i_am_color_2201">#00002201</color> + <color name="i_am_color_2202">#00002202</color> + <color name="i_am_color_2203">#00002203</color> + <color name="i_am_color_2204">#00002204</color> + <color name="i_am_color_2205">#00002205</color> + <color name="i_am_color_2206">#00002206</color> + <color name="i_am_color_2207">#00002207</color> + <color name="i_am_color_2208">#00002208</color> + <color name="i_am_color_2209">#00002209</color> + <color name="i_am_color_220a">#0000220a</color> + <color name="i_am_color_220b">#0000220b</color> + <color name="i_am_color_220c">#0000220c</color> + <color name="i_am_color_220d">#0000220d</color> + <color name="i_am_color_220e">#0000220e</color> + <color name="i_am_color_220f">#0000220f</color> + <color name="i_am_color_2210">#00002210</color> + <color name="i_am_color_2211">#00002211</color> + <color name="i_am_color_2212">#00002212</color> + <color name="i_am_color_2213">#00002213</color> + <color name="i_am_color_2214">#00002214</color> + <color name="i_am_color_2215">#00002215</color> + <color name="i_am_color_2216">#00002216</color> + <color name="i_am_color_2217">#00002217</color> + <color name="i_am_color_2218">#00002218</color> + <color name="i_am_color_2219">#00002219</color> + <color name="i_am_color_221a">#0000221a</color> + <color name="i_am_color_221b">#0000221b</color> + <color name="i_am_color_221c">#0000221c</color> + <color name="i_am_color_221d">#0000221d</color> + <color name="i_am_color_221e">#0000221e</color> + <color name="i_am_color_221f">#0000221f</color> + <color name="i_am_color_2220">#00002220</color> + <color name="i_am_color_2221">#00002221</color> + <color name="i_am_color_2222">#00002222</color> + <color name="i_am_color_2223">#00002223</color> + <color name="i_am_color_2224">#00002224</color> + <color name="i_am_color_2225">#00002225</color> + <color name="i_am_color_2226">#00002226</color> + <color name="i_am_color_2227">#00002227</color> + <color name="i_am_color_2228">#00002228</color> + <color name="i_am_color_2229">#00002229</color> + <color name="i_am_color_222a">#0000222a</color> + <color name="i_am_color_222b">#0000222b</color> + <color name="i_am_color_222c">#0000222c</color> + <color name="i_am_color_222d">#0000222d</color> + <color name="i_am_color_222e">#0000222e</color> + <color name="i_am_color_222f">#0000222f</color> + <color name="i_am_color_2230">#00002230</color> + <color name="i_am_color_2231">#00002231</color> + <color name="i_am_color_2232">#00002232</color> + <color name="i_am_color_2233">#00002233</color> + <color name="i_am_color_2234">#00002234</color> + <color name="i_am_color_2235">#00002235</color> + <color name="i_am_color_2236">#00002236</color> + <color name="i_am_color_2237">#00002237</color> + <color name="i_am_color_2238">#00002238</color> + <color name="i_am_color_2239">#00002239</color> + <color name="i_am_color_223a">#0000223a</color> + <color name="i_am_color_223b">#0000223b</color> + <color name="i_am_color_223c">#0000223c</color> + <color name="i_am_color_223d">#0000223d</color> + <color name="i_am_color_223e">#0000223e</color> + <color name="i_am_color_223f">#0000223f</color> + <color name="i_am_color_2240">#00002240</color> + <color name="i_am_color_2241">#00002241</color> + <color name="i_am_color_2242">#00002242</color> + <color name="i_am_color_2243">#00002243</color> + <color name="i_am_color_2244">#00002244</color> + <color name="i_am_color_2245">#00002245</color> + <color name="i_am_color_2246">#00002246</color> + <color name="i_am_color_2247">#00002247</color> + <color name="i_am_color_2248">#00002248</color> + <color name="i_am_color_2249">#00002249</color> + <color name="i_am_color_224a">#0000224a</color> + <color name="i_am_color_224b">#0000224b</color> + <color name="i_am_color_224c">#0000224c</color> + <color name="i_am_color_224d">#0000224d</color> + <color name="i_am_color_224e">#0000224e</color> + <color name="i_am_color_224f">#0000224f</color> + <color name="i_am_color_2250">#00002250</color> + <color name="i_am_color_2251">#00002251</color> + <color name="i_am_color_2252">#00002252</color> + <color name="i_am_color_2253">#00002253</color> + <color name="i_am_color_2254">#00002254</color> + <color name="i_am_color_2255">#00002255</color> + <color name="i_am_color_2256">#00002256</color> + <color name="i_am_color_2257">#00002257</color> + <color name="i_am_color_2258">#00002258</color> + <color name="i_am_color_2259">#00002259</color> + <color name="i_am_color_225a">#0000225a</color> + <color name="i_am_color_225b">#0000225b</color> + <color name="i_am_color_225c">#0000225c</color> + <color name="i_am_color_225d">#0000225d</color> + <color name="i_am_color_225e">#0000225e</color> + <color name="i_am_color_225f">#0000225f</color> + <color name="i_am_color_2260">#00002260</color> + <color name="i_am_color_2261">#00002261</color> + <color name="i_am_color_2262">#00002262</color> + <color name="i_am_color_2263">#00002263</color> + <color name="i_am_color_2264">#00002264</color> + <color name="i_am_color_2265">#00002265</color> + <color name="i_am_color_2266">#00002266</color> + <color name="i_am_color_2267">#00002267</color> + <color name="i_am_color_2268">#00002268</color> + <color name="i_am_color_2269">#00002269</color> + <color name="i_am_color_226a">#0000226a</color> + <color name="i_am_color_226b">#0000226b</color> + <color name="i_am_color_226c">#0000226c</color> + <color name="i_am_color_226d">#0000226d</color> + <color name="i_am_color_226e">#0000226e</color> + <color name="i_am_color_226f">#0000226f</color> + <color name="i_am_color_2270">#00002270</color> + <color name="i_am_color_2271">#00002271</color> + <color name="i_am_color_2272">#00002272</color> + <color name="i_am_color_2273">#00002273</color> + <color name="i_am_color_2274">#00002274</color> + <color name="i_am_color_2275">#00002275</color> + <color name="i_am_color_2276">#00002276</color> + <color name="i_am_color_2277">#00002277</color> + <color name="i_am_color_2278">#00002278</color> + <color name="i_am_color_2279">#00002279</color> + <color name="i_am_color_227a">#0000227a</color> + <color name="i_am_color_227b">#0000227b</color> + <color name="i_am_color_227c">#0000227c</color> + <color name="i_am_color_227d">#0000227d</color> + <color name="i_am_color_227e">#0000227e</color> + <color name="i_am_color_227f">#0000227f</color> + <color name="i_am_color_2280">#00002280</color> + <color name="i_am_color_2281">#00002281</color> + <color name="i_am_color_2282">#00002282</color> + <color name="i_am_color_2283">#00002283</color> + <color name="i_am_color_2284">#00002284</color> + <color name="i_am_color_2285">#00002285</color> + <color name="i_am_color_2286">#00002286</color> + <color name="i_am_color_2287">#00002287</color> + <color name="i_am_color_2288">#00002288</color> + <color name="i_am_color_2289">#00002289</color> + <color name="i_am_color_228a">#0000228a</color> + <color name="i_am_color_228b">#0000228b</color> + <color name="i_am_color_228c">#0000228c</color> + <color name="i_am_color_228d">#0000228d</color> + <color name="i_am_color_228e">#0000228e</color> + <color name="i_am_color_228f">#0000228f</color> + <color name="i_am_color_2290">#00002290</color> + <color name="i_am_color_2291">#00002291</color> + <color name="i_am_color_2292">#00002292</color> + <color name="i_am_color_2293">#00002293</color> + <color name="i_am_color_2294">#00002294</color> + <color name="i_am_color_2295">#00002295</color> + <color name="i_am_color_2296">#00002296</color> + <color name="i_am_color_2297">#00002297</color> + <color name="i_am_color_2298">#00002298</color> + <color name="i_am_color_2299">#00002299</color> + <color name="i_am_color_229a">#0000229a</color> + <color name="i_am_color_229b">#0000229b</color> + <color name="i_am_color_229c">#0000229c</color> + <color name="i_am_color_229d">#0000229d</color> + <color name="i_am_color_229e">#0000229e</color> + <color name="i_am_color_229f">#0000229f</color> + <color name="i_am_color_22a0">#000022a0</color> + <color name="i_am_color_22a1">#000022a1</color> + <color name="i_am_color_22a2">#000022a2</color> + <color name="i_am_color_22a3">#000022a3</color> + <color name="i_am_color_22a4">#000022a4</color> + <color name="i_am_color_22a5">#000022a5</color> + <color name="i_am_color_22a6">#000022a6</color> + <color name="i_am_color_22a7">#000022a7</color> + <color name="i_am_color_22a8">#000022a8</color> + <color name="i_am_color_22a9">#000022a9</color> + <color name="i_am_color_22aa">#000022aa</color> + <color name="i_am_color_22ab">#000022ab</color> + <color name="i_am_color_22ac">#000022ac</color> + <color name="i_am_color_22ad">#000022ad</color> + <color name="i_am_color_22ae">#000022ae</color> + <color name="i_am_color_22af">#000022af</color> + <color name="i_am_color_22b0">#000022b0</color> + <color name="i_am_color_22b1">#000022b1</color> + <color name="i_am_color_22b2">#000022b2</color> + <color name="i_am_color_22b3">#000022b3</color> + <color name="i_am_color_22b4">#000022b4</color> + <color name="i_am_color_22b5">#000022b5</color> + <color name="i_am_color_22b6">#000022b6</color> + <color name="i_am_color_22b7">#000022b7</color> + <color name="i_am_color_22b8">#000022b8</color> + <color name="i_am_color_22b9">#000022b9</color> + <color name="i_am_color_22ba">#000022ba</color> + <color name="i_am_color_22bb">#000022bb</color> + <color name="i_am_color_22bc">#000022bc</color> + <color name="i_am_color_22bd">#000022bd</color> + <color name="i_am_color_22be">#000022be</color> + <color name="i_am_color_22bf">#000022bf</color> + <color name="i_am_color_22c0">#000022c0</color> + <color name="i_am_color_22c1">#000022c1</color> + <color name="i_am_color_22c2">#000022c2</color> + <color name="i_am_color_22c3">#000022c3</color> + <color name="i_am_color_22c4">#000022c4</color> + <color name="i_am_color_22c5">#000022c5</color> + <color name="i_am_color_22c6">#000022c6</color> + <color name="i_am_color_22c7">#000022c7</color> + <color name="i_am_color_22c8">#000022c8</color> + <color name="i_am_color_22c9">#000022c9</color> + <color name="i_am_color_22ca">#000022ca</color> + <color name="i_am_color_22cb">#000022cb</color> + <color name="i_am_color_22cc">#000022cc</color> + <color name="i_am_color_22cd">#000022cd</color> + <color name="i_am_color_22ce">#000022ce</color> + <color name="i_am_color_22cf">#000022cf</color> + <color name="i_am_color_22d0">#000022d0</color> + <color name="i_am_color_22d1">#000022d1</color> + <color name="i_am_color_22d2">#000022d2</color> + <color name="i_am_color_22d3">#000022d3</color> + <color name="i_am_color_22d4">#000022d4</color> + <color name="i_am_color_22d5">#000022d5</color> + <color name="i_am_color_22d6">#000022d6</color> + <color name="i_am_color_22d7">#000022d7</color> + <color name="i_am_color_22d8">#000022d8</color> + <color name="i_am_color_22d9">#000022d9</color> + <color name="i_am_color_22da">#000022da</color> + <color name="i_am_color_22db">#000022db</color> + <color name="i_am_color_22dc">#000022dc</color> + <color name="i_am_color_22dd">#000022dd</color> + <color name="i_am_color_22de">#000022de</color> + <color name="i_am_color_22df">#000022df</color> + <color name="i_am_color_22e0">#000022e0</color> + <color name="i_am_color_22e1">#000022e1</color> + <color name="i_am_color_22e2">#000022e2</color> + <color name="i_am_color_22e3">#000022e3</color> + <color name="i_am_color_22e4">#000022e4</color> + <color name="i_am_color_22e5">#000022e5</color> + <color name="i_am_color_22e6">#000022e6</color> + <color name="i_am_color_22e7">#000022e7</color> + <color name="i_am_color_22e8">#000022e8</color> + <color name="i_am_color_22e9">#000022e9</color> + <color name="i_am_color_22ea">#000022ea</color> + <color name="i_am_color_22eb">#000022eb</color> + <color name="i_am_color_22ec">#000022ec</color> + <color name="i_am_color_22ed">#000022ed</color> + <color name="i_am_color_22ee">#000022ee</color> + <color name="i_am_color_22ef">#000022ef</color> + <color name="i_am_color_22f0">#000022f0</color> + <color name="i_am_color_22f1">#000022f1</color> + <color name="i_am_color_22f2">#000022f2</color> + <color name="i_am_color_22f3">#000022f3</color> + <color name="i_am_color_22f4">#000022f4</color> + <color name="i_am_color_22f5">#000022f5</color> + <color name="i_am_color_22f6">#000022f6</color> + <color name="i_am_color_22f7">#000022f7</color> + <color name="i_am_color_22f8">#000022f8</color> + <color name="i_am_color_22f9">#000022f9</color> + <color name="i_am_color_22fa">#000022fa</color> + <color name="i_am_color_22fb">#000022fb</color> + <color name="i_am_color_22fc">#000022fc</color> + <color name="i_am_color_22fd">#000022fd</color> + <color name="i_am_color_22fe">#000022fe</color> + <color name="i_am_color_22ff">#000022ff</color> + <color name="i_am_color_2300">#00002300</color> + <color name="i_am_color_2301">#00002301</color> + <color name="i_am_color_2302">#00002302</color> + <color name="i_am_color_2303">#00002303</color> + <color name="i_am_color_2304">#00002304</color> + <color name="i_am_color_2305">#00002305</color> + <color name="i_am_color_2306">#00002306</color> + <color name="i_am_color_2307">#00002307</color> + <color name="i_am_color_2308">#00002308</color> + <color name="i_am_color_2309">#00002309</color> + <color name="i_am_color_230a">#0000230a</color> + <color name="i_am_color_230b">#0000230b</color> + <color name="i_am_color_230c">#0000230c</color> + <color name="i_am_color_230d">#0000230d</color> + <color name="i_am_color_230e">#0000230e</color> + <color name="i_am_color_230f">#0000230f</color> + <color name="i_am_color_2310">#00002310</color> + <color name="i_am_color_2311">#00002311</color> + <color name="i_am_color_2312">#00002312</color> + <color name="i_am_color_2313">#00002313</color> + <color name="i_am_color_2314">#00002314</color> + <color name="i_am_color_2315">#00002315</color> + <color name="i_am_color_2316">#00002316</color> + <color name="i_am_color_2317">#00002317</color> + <color name="i_am_color_2318">#00002318</color> + <color name="i_am_color_2319">#00002319</color> + <color name="i_am_color_231a">#0000231a</color> + <color name="i_am_color_231b">#0000231b</color> + <color name="i_am_color_231c">#0000231c</color> + <color name="i_am_color_231d">#0000231d</color> + <color name="i_am_color_231e">#0000231e</color> + <color name="i_am_color_231f">#0000231f</color> + <color name="i_am_color_2320">#00002320</color> + <color name="i_am_color_2321">#00002321</color> + <color name="i_am_color_2322">#00002322</color> + <color name="i_am_color_2323">#00002323</color> + <color name="i_am_color_2324">#00002324</color> + <color name="i_am_color_2325">#00002325</color> + <color name="i_am_color_2326">#00002326</color> + <color name="i_am_color_2327">#00002327</color> + <color name="i_am_color_2328">#00002328</color> + <color name="i_am_color_2329">#00002329</color> + <color name="i_am_color_232a">#0000232a</color> + <color name="i_am_color_232b">#0000232b</color> + <color name="i_am_color_232c">#0000232c</color> + <color name="i_am_color_232d">#0000232d</color> + <color name="i_am_color_232e">#0000232e</color> + <color name="i_am_color_232f">#0000232f</color> + <color name="i_am_color_2330">#00002330</color> + <color name="i_am_color_2331">#00002331</color> + <color name="i_am_color_2332">#00002332</color> + <color name="i_am_color_2333">#00002333</color> + <color name="i_am_color_2334">#00002334</color> + <color name="i_am_color_2335">#00002335</color> + <color name="i_am_color_2336">#00002336</color> + <color name="i_am_color_2337">#00002337</color> + <color name="i_am_color_2338">#00002338</color> + <color name="i_am_color_2339">#00002339</color> + <color name="i_am_color_233a">#0000233a</color> + <color name="i_am_color_233b">#0000233b</color> + <color name="i_am_color_233c">#0000233c</color> + <color name="i_am_color_233d">#0000233d</color> + <color name="i_am_color_233e">#0000233e</color> + <color name="i_am_color_233f">#0000233f</color> + <color name="i_am_color_2340">#00002340</color> + <color name="i_am_color_2341">#00002341</color> + <color name="i_am_color_2342">#00002342</color> + <color name="i_am_color_2343">#00002343</color> + <color name="i_am_color_2344">#00002344</color> + <color name="i_am_color_2345">#00002345</color> + <color name="i_am_color_2346">#00002346</color> + <color name="i_am_color_2347">#00002347</color> + <color name="i_am_color_2348">#00002348</color> + <color name="i_am_color_2349">#00002349</color> + <color name="i_am_color_234a">#0000234a</color> + <color name="i_am_color_234b">#0000234b</color> + <color name="i_am_color_234c">#0000234c</color> + <color name="i_am_color_234d">#0000234d</color> + <color name="i_am_color_234e">#0000234e</color> + <color name="i_am_color_234f">#0000234f</color> + <color name="i_am_color_2350">#00002350</color> + <color name="i_am_color_2351">#00002351</color> + <color name="i_am_color_2352">#00002352</color> + <color name="i_am_color_2353">#00002353</color> + <color name="i_am_color_2354">#00002354</color> + <color name="i_am_color_2355">#00002355</color> + <color name="i_am_color_2356">#00002356</color> + <color name="i_am_color_2357">#00002357</color> + <color name="i_am_color_2358">#00002358</color> + <color name="i_am_color_2359">#00002359</color> + <color name="i_am_color_235a">#0000235a</color> + <color name="i_am_color_235b">#0000235b</color> + <color name="i_am_color_235c">#0000235c</color> + <color name="i_am_color_235d">#0000235d</color> + <color name="i_am_color_235e">#0000235e</color> + <color name="i_am_color_235f">#0000235f</color> + <color name="i_am_color_2360">#00002360</color> + <color name="i_am_color_2361">#00002361</color> + <color name="i_am_color_2362">#00002362</color> + <color name="i_am_color_2363">#00002363</color> + <color name="i_am_color_2364">#00002364</color> + <color name="i_am_color_2365">#00002365</color> + <color name="i_am_color_2366">#00002366</color> + <color name="i_am_color_2367">#00002367</color> + <color name="i_am_color_2368">#00002368</color> + <color name="i_am_color_2369">#00002369</color> + <color name="i_am_color_236a">#0000236a</color> + <color name="i_am_color_236b">#0000236b</color> + <color name="i_am_color_236c">#0000236c</color> + <color name="i_am_color_236d">#0000236d</color> + <color name="i_am_color_236e">#0000236e</color> + <color name="i_am_color_236f">#0000236f</color> + <color name="i_am_color_2370">#00002370</color> + <color name="i_am_color_2371">#00002371</color> + <color name="i_am_color_2372">#00002372</color> + <color name="i_am_color_2373">#00002373</color> + <color name="i_am_color_2374">#00002374</color> + <color name="i_am_color_2375">#00002375</color> + <color name="i_am_color_2376">#00002376</color> + <color name="i_am_color_2377">#00002377</color> + <color name="i_am_color_2378">#00002378</color> + <color name="i_am_color_2379">#00002379</color> + <color name="i_am_color_237a">#0000237a</color> + <color name="i_am_color_237b">#0000237b</color> + <color name="i_am_color_237c">#0000237c</color> + <color name="i_am_color_237d">#0000237d</color> + <color name="i_am_color_237e">#0000237e</color> + <color name="i_am_color_237f">#0000237f</color> + <color name="i_am_color_2380">#00002380</color> + <color name="i_am_color_2381">#00002381</color> + <color name="i_am_color_2382">#00002382</color> + <color name="i_am_color_2383">#00002383</color> + <color name="i_am_color_2384">#00002384</color> + <color name="i_am_color_2385">#00002385</color> + <color name="i_am_color_2386">#00002386</color> + <color name="i_am_color_2387">#00002387</color> + <color name="i_am_color_2388">#00002388</color> + <color name="i_am_color_2389">#00002389</color> + <color name="i_am_color_238a">#0000238a</color> + <color name="i_am_color_238b">#0000238b</color> + <color name="i_am_color_238c">#0000238c</color> + <color name="i_am_color_238d">#0000238d</color> + <color name="i_am_color_238e">#0000238e</color> + <color name="i_am_color_238f">#0000238f</color> + <color name="i_am_color_2390">#00002390</color> + <color name="i_am_color_2391">#00002391</color> + <color name="i_am_color_2392">#00002392</color> + <color name="i_am_color_2393">#00002393</color> + <color name="i_am_color_2394">#00002394</color> + <color name="i_am_color_2395">#00002395</color> + <color name="i_am_color_2396">#00002396</color> + <color name="i_am_color_2397">#00002397</color> + <color name="i_am_color_2398">#00002398</color> + <color name="i_am_color_2399">#00002399</color> + <color name="i_am_color_239a">#0000239a</color> + <color name="i_am_color_239b">#0000239b</color> + <color name="i_am_color_239c">#0000239c</color> + <color name="i_am_color_239d">#0000239d</color> + <color name="i_am_color_239e">#0000239e</color> + <color name="i_am_color_239f">#0000239f</color> + <color name="i_am_color_23a0">#000023a0</color> + <color name="i_am_color_23a1">#000023a1</color> + <color name="i_am_color_23a2">#000023a2</color> + <color name="i_am_color_23a3">#000023a3</color> + <color name="i_am_color_23a4">#000023a4</color> + <color name="i_am_color_23a5">#000023a5</color> + <color name="i_am_color_23a6">#000023a6</color> + <color name="i_am_color_23a7">#000023a7</color> + <color name="i_am_color_23a8">#000023a8</color> + <color name="i_am_color_23a9">#000023a9</color> + <color name="i_am_color_23aa">#000023aa</color> + <color name="i_am_color_23ab">#000023ab</color> + <color name="i_am_color_23ac">#000023ac</color> + <color name="i_am_color_23ad">#000023ad</color> + <color name="i_am_color_23ae">#000023ae</color> + <color name="i_am_color_23af">#000023af</color> + <color name="i_am_color_23b0">#000023b0</color> + <color name="i_am_color_23b1">#000023b1</color> + <color name="i_am_color_23b2">#000023b2</color> + <color name="i_am_color_23b3">#000023b3</color> + <color name="i_am_color_23b4">#000023b4</color> + <color name="i_am_color_23b5">#000023b5</color> + <color name="i_am_color_23b6">#000023b6</color> + <color name="i_am_color_23b7">#000023b7</color> + <color name="i_am_color_23b8">#000023b8</color> + <color name="i_am_color_23b9">#000023b9</color> + <color name="i_am_color_23ba">#000023ba</color> + <color name="i_am_color_23bb">#000023bb</color> + <color name="i_am_color_23bc">#000023bc</color> + <color name="i_am_color_23bd">#000023bd</color> + <color name="i_am_color_23be">#000023be</color> + <color name="i_am_color_23bf">#000023bf</color> + <color name="i_am_color_23c0">#000023c0</color> + <color name="i_am_color_23c1">#000023c1</color> + <color name="i_am_color_23c2">#000023c2</color> + <color name="i_am_color_23c3">#000023c3</color> + <color name="i_am_color_23c4">#000023c4</color> + <color name="i_am_color_23c5">#000023c5</color> + <color name="i_am_color_23c6">#000023c6</color> + <color name="i_am_color_23c7">#000023c7</color> + <color name="i_am_color_23c8">#000023c8</color> + <color name="i_am_color_23c9">#000023c9</color> + <color name="i_am_color_23ca">#000023ca</color> + <color name="i_am_color_23cb">#000023cb</color> + <color name="i_am_color_23cc">#000023cc</color> + <color name="i_am_color_23cd">#000023cd</color> + <color name="i_am_color_23ce">#000023ce</color> + <color name="i_am_color_23cf">#000023cf</color> + <color name="i_am_color_23d0">#000023d0</color> + <color name="i_am_color_23d1">#000023d1</color> + <color name="i_am_color_23d2">#000023d2</color> + <color name="i_am_color_23d3">#000023d3</color> + <color name="i_am_color_23d4">#000023d4</color> + <color name="i_am_color_23d5">#000023d5</color> + <color name="i_am_color_23d6">#000023d6</color> + <color name="i_am_color_23d7">#000023d7</color> + <color name="i_am_color_23d8">#000023d8</color> + <color name="i_am_color_23d9">#000023d9</color> + <color name="i_am_color_23da">#000023da</color> + <color name="i_am_color_23db">#000023db</color> + <color name="i_am_color_23dc">#000023dc</color> + <color name="i_am_color_23dd">#000023dd</color> + <color name="i_am_color_23de">#000023de</color> + <color name="i_am_color_23df">#000023df</color> + <color name="i_am_color_23e0">#000023e0</color> + <color name="i_am_color_23e1">#000023e1</color> + <color name="i_am_color_23e2">#000023e2</color> + <color name="i_am_color_23e3">#000023e3</color> + <color name="i_am_color_23e4">#000023e4</color> + <color name="i_am_color_23e5">#000023e5</color> + <color name="i_am_color_23e6">#000023e6</color> + <color name="i_am_color_23e7">#000023e7</color> + <color name="i_am_color_23e8">#000023e8</color> + <color name="i_am_color_23e9">#000023e9</color> + <color name="i_am_color_23ea">#000023ea</color> + <color name="i_am_color_23eb">#000023eb</color> + <color name="i_am_color_23ec">#000023ec</color> + <color name="i_am_color_23ed">#000023ed</color> + <color name="i_am_color_23ee">#000023ee</color> + <color name="i_am_color_23ef">#000023ef</color> + <color name="i_am_color_23f0">#000023f0</color> + <color name="i_am_color_23f1">#000023f1</color> + <color name="i_am_color_23f2">#000023f2</color> + <color name="i_am_color_23f3">#000023f3</color> + <color name="i_am_color_23f4">#000023f4</color> + <color name="i_am_color_23f5">#000023f5</color> + <color name="i_am_color_23f6">#000023f6</color> + <color name="i_am_color_23f7">#000023f7</color> + <color name="i_am_color_23f8">#000023f8</color> + <color name="i_am_color_23f9">#000023f9</color> + <color name="i_am_color_23fa">#000023fa</color> + <color name="i_am_color_23fb">#000023fb</color> + <color name="i_am_color_23fc">#000023fc</color> + <color name="i_am_color_23fd">#000023fd</color> + <color name="i_am_color_23fe">#000023fe</color> + <color name="i_am_color_23ff">#000023ff</color> + <color name="i_am_color_2400">#00002400</color> + <color name="i_am_color_2401">#00002401</color> + <color name="i_am_color_2402">#00002402</color> + <color name="i_am_color_2403">#00002403</color> + <color name="i_am_color_2404">#00002404</color> + <color name="i_am_color_2405">#00002405</color> + <color name="i_am_color_2406">#00002406</color> + <color name="i_am_color_2407">#00002407</color> + <color name="i_am_color_2408">#00002408</color> + <color name="i_am_color_2409">#00002409</color> + <color name="i_am_color_240a">#0000240a</color> + <color name="i_am_color_240b">#0000240b</color> + <color name="i_am_color_240c">#0000240c</color> + <color name="i_am_color_240d">#0000240d</color> + <color name="i_am_color_240e">#0000240e</color> + <color name="i_am_color_240f">#0000240f</color> + <color name="i_am_color_2410">#00002410</color> + <color name="i_am_color_2411">#00002411</color> + <color name="i_am_color_2412">#00002412</color> + <color name="i_am_color_2413">#00002413</color> + <color name="i_am_color_2414">#00002414</color> + <color name="i_am_color_2415">#00002415</color> + <color name="i_am_color_2416">#00002416</color> + <color name="i_am_color_2417">#00002417</color> + <color name="i_am_color_2418">#00002418</color> + <color name="i_am_color_2419">#00002419</color> + <color name="i_am_color_241a">#0000241a</color> + <color name="i_am_color_241b">#0000241b</color> + <color name="i_am_color_241c">#0000241c</color> + <color name="i_am_color_241d">#0000241d</color> + <color name="i_am_color_241e">#0000241e</color> + <color name="i_am_color_241f">#0000241f</color> + <color name="i_am_color_2420">#00002420</color> + <color name="i_am_color_2421">#00002421</color> + <color name="i_am_color_2422">#00002422</color> + <color name="i_am_color_2423">#00002423</color> + <color name="i_am_color_2424">#00002424</color> + <color name="i_am_color_2425">#00002425</color> + <color name="i_am_color_2426">#00002426</color> + <color name="i_am_color_2427">#00002427</color> + <color name="i_am_color_2428">#00002428</color> + <color name="i_am_color_2429">#00002429</color> + <color name="i_am_color_242a">#0000242a</color> + <color name="i_am_color_242b">#0000242b</color> + <color name="i_am_color_242c">#0000242c</color> + <color name="i_am_color_242d">#0000242d</color> + <color name="i_am_color_242e">#0000242e</color> + <color name="i_am_color_242f">#0000242f</color> + <color name="i_am_color_2430">#00002430</color> + <color name="i_am_color_2431">#00002431</color> + <color name="i_am_color_2432">#00002432</color> + <color name="i_am_color_2433">#00002433</color> + <color name="i_am_color_2434">#00002434</color> + <color name="i_am_color_2435">#00002435</color> + <color name="i_am_color_2436">#00002436</color> + <color name="i_am_color_2437">#00002437</color> + <color name="i_am_color_2438">#00002438</color> + <color name="i_am_color_2439">#00002439</color> + <color name="i_am_color_243a">#0000243a</color> + <color name="i_am_color_243b">#0000243b</color> + <color name="i_am_color_243c">#0000243c</color> + <color name="i_am_color_243d">#0000243d</color> + <color name="i_am_color_243e">#0000243e</color> + <color name="i_am_color_243f">#0000243f</color> + <color name="i_am_color_2440">#00002440</color> + <color name="i_am_color_2441">#00002441</color> + <color name="i_am_color_2442">#00002442</color> + <color name="i_am_color_2443">#00002443</color> + <color name="i_am_color_2444">#00002444</color> + <color name="i_am_color_2445">#00002445</color> + <color name="i_am_color_2446">#00002446</color> + <color name="i_am_color_2447">#00002447</color> + <color name="i_am_color_2448">#00002448</color> + <color name="i_am_color_2449">#00002449</color> + <color name="i_am_color_244a">#0000244a</color> + <color name="i_am_color_244b">#0000244b</color> + <color name="i_am_color_244c">#0000244c</color> + <color name="i_am_color_244d">#0000244d</color> + <color name="i_am_color_244e">#0000244e</color> + <color name="i_am_color_244f">#0000244f</color> + <color name="i_am_color_2450">#00002450</color> + <color name="i_am_color_2451">#00002451</color> + <color name="i_am_color_2452">#00002452</color> + <color name="i_am_color_2453">#00002453</color> + <color name="i_am_color_2454">#00002454</color> + <color name="i_am_color_2455">#00002455</color> + <color name="i_am_color_2456">#00002456</color> + <color name="i_am_color_2457">#00002457</color> + <color name="i_am_color_2458">#00002458</color> + <color name="i_am_color_2459">#00002459</color> + <color name="i_am_color_245a">#0000245a</color> + <color name="i_am_color_245b">#0000245b</color> + <color name="i_am_color_245c">#0000245c</color> + <color name="i_am_color_245d">#0000245d</color> + <color name="i_am_color_245e">#0000245e</color> + <color name="i_am_color_245f">#0000245f</color> + <color name="i_am_color_2460">#00002460</color> + <color name="i_am_color_2461">#00002461</color> + <color name="i_am_color_2462">#00002462</color> + <color name="i_am_color_2463">#00002463</color> + <color name="i_am_color_2464">#00002464</color> + <color name="i_am_color_2465">#00002465</color> + <color name="i_am_color_2466">#00002466</color> + <color name="i_am_color_2467">#00002467</color> + <color name="i_am_color_2468">#00002468</color> + <color name="i_am_color_2469">#00002469</color> + <color name="i_am_color_246a">#0000246a</color> + <color name="i_am_color_246b">#0000246b</color> + <color name="i_am_color_246c">#0000246c</color> + <color name="i_am_color_246d">#0000246d</color> + <color name="i_am_color_246e">#0000246e</color> + <color name="i_am_color_246f">#0000246f</color> + <color name="i_am_color_2470">#00002470</color> + <color name="i_am_color_2471">#00002471</color> + <color name="i_am_color_2472">#00002472</color> + <color name="i_am_color_2473">#00002473</color> + <color name="i_am_color_2474">#00002474</color> + <color name="i_am_color_2475">#00002475</color> + <color name="i_am_color_2476">#00002476</color> + <color name="i_am_color_2477">#00002477</color> + <color name="i_am_color_2478">#00002478</color> + <color name="i_am_color_2479">#00002479</color> + <color name="i_am_color_247a">#0000247a</color> + <color name="i_am_color_247b">#0000247b</color> + <color name="i_am_color_247c">#0000247c</color> + <color name="i_am_color_247d">#0000247d</color> + <color name="i_am_color_247e">#0000247e</color> + <color name="i_am_color_247f">#0000247f</color> + <color name="i_am_color_2480">#00002480</color> + <color name="i_am_color_2481">#00002481</color> + <color name="i_am_color_2482">#00002482</color> + <color name="i_am_color_2483">#00002483</color> + <color name="i_am_color_2484">#00002484</color> + <color name="i_am_color_2485">#00002485</color> + <color name="i_am_color_2486">#00002486</color> + <color name="i_am_color_2487">#00002487</color> + <color name="i_am_color_2488">#00002488</color> + <color name="i_am_color_2489">#00002489</color> + <color name="i_am_color_248a">#0000248a</color> + <color name="i_am_color_248b">#0000248b</color> + <color name="i_am_color_248c">#0000248c</color> + <color name="i_am_color_248d">#0000248d</color> + <color name="i_am_color_248e">#0000248e</color> + <color name="i_am_color_248f">#0000248f</color> + <color name="i_am_color_2490">#00002490</color> + <color name="i_am_color_2491">#00002491</color> + <color name="i_am_color_2492">#00002492</color> + <color name="i_am_color_2493">#00002493</color> + <color name="i_am_color_2494">#00002494</color> + <color name="i_am_color_2495">#00002495</color> + <color name="i_am_color_2496">#00002496</color> + <color name="i_am_color_2497">#00002497</color> + <color name="i_am_color_2498">#00002498</color> + <color name="i_am_color_2499">#00002499</color> + <color name="i_am_color_249a">#0000249a</color> + <color name="i_am_color_249b">#0000249b</color> + <color name="i_am_color_249c">#0000249c</color> + <color name="i_am_color_249d">#0000249d</color> + <color name="i_am_color_249e">#0000249e</color> + <color name="i_am_color_249f">#0000249f</color> + <color name="i_am_color_24a0">#000024a0</color> + <color name="i_am_color_24a1">#000024a1</color> + <color name="i_am_color_24a2">#000024a2</color> + <color name="i_am_color_24a3">#000024a3</color> + <color name="i_am_color_24a4">#000024a4</color> + <color name="i_am_color_24a5">#000024a5</color> + <color name="i_am_color_24a6">#000024a6</color> + <color name="i_am_color_24a7">#000024a7</color> + <color name="i_am_color_24a8">#000024a8</color> + <color name="i_am_color_24a9">#000024a9</color> + <color name="i_am_color_24aa">#000024aa</color> + <color name="i_am_color_24ab">#000024ab</color> + <color name="i_am_color_24ac">#000024ac</color> + <color name="i_am_color_24ad">#000024ad</color> + <color name="i_am_color_24ae">#000024ae</color> + <color name="i_am_color_24af">#000024af</color> + <color name="i_am_color_24b0">#000024b0</color> + <color name="i_am_color_24b1">#000024b1</color> + <color name="i_am_color_24b2">#000024b2</color> + <color name="i_am_color_24b3">#000024b3</color> + <color name="i_am_color_24b4">#000024b4</color> + <color name="i_am_color_24b5">#000024b5</color> + <color name="i_am_color_24b6">#000024b6</color> + <color name="i_am_color_24b7">#000024b7</color> + <color name="i_am_color_24b8">#000024b8</color> + <color name="i_am_color_24b9">#000024b9</color> + <color name="i_am_color_24ba">#000024ba</color> + <color name="i_am_color_24bb">#000024bb</color> + <color name="i_am_color_24bc">#000024bc</color> + <color name="i_am_color_24bd">#000024bd</color> + <color name="i_am_color_24be">#000024be</color> + <color name="i_am_color_24bf">#000024bf</color> + <color name="i_am_color_24c0">#000024c0</color> + <color name="i_am_color_24c1">#000024c1</color> + <color name="i_am_color_24c2">#000024c2</color> + <color name="i_am_color_24c3">#000024c3</color> + <color name="i_am_color_24c4">#000024c4</color> + <color name="i_am_color_24c5">#000024c5</color> + <color name="i_am_color_24c6">#000024c6</color> + <color name="i_am_color_24c7">#000024c7</color> + <color name="i_am_color_24c8">#000024c8</color> + <color name="i_am_color_24c9">#000024c9</color> + <color name="i_am_color_24ca">#000024ca</color> + <color name="i_am_color_24cb">#000024cb</color> + <color name="i_am_color_24cc">#000024cc</color> + <color name="i_am_color_24cd">#000024cd</color> + <color name="i_am_color_24ce">#000024ce</color> + <color name="i_am_color_24cf">#000024cf</color> + <color name="i_am_color_24d0">#000024d0</color> + <color name="i_am_color_24d1">#000024d1</color> + <color name="i_am_color_24d2">#000024d2</color> + <color name="i_am_color_24d3">#000024d3</color> + <color name="i_am_color_24d4">#000024d4</color> + <color name="i_am_color_24d5">#000024d5</color> + <color name="i_am_color_24d6">#000024d6</color> + <color name="i_am_color_24d7">#000024d7</color> + <color name="i_am_color_24d8">#000024d8</color> + <color name="i_am_color_24d9">#000024d9</color> + <color name="i_am_color_24da">#000024da</color> + <color name="i_am_color_24db">#000024db</color> + <color name="i_am_color_24dc">#000024dc</color> + <color name="i_am_color_24dd">#000024dd</color> + <color name="i_am_color_24de">#000024de</color> + <color name="i_am_color_24df">#000024df</color> + <color name="i_am_color_24e0">#000024e0</color> + <color name="i_am_color_24e1">#000024e1</color> + <color name="i_am_color_24e2">#000024e2</color> + <color name="i_am_color_24e3">#000024e3</color> + <color name="i_am_color_24e4">#000024e4</color> + <color name="i_am_color_24e5">#000024e5</color> + <color name="i_am_color_24e6">#000024e6</color> + <color name="i_am_color_24e7">#000024e7</color> + <color name="i_am_color_24e8">#000024e8</color> + <color name="i_am_color_24e9">#000024e9</color> + <color name="i_am_color_24ea">#000024ea</color> + <color name="i_am_color_24eb">#000024eb</color> + <color name="i_am_color_24ec">#000024ec</color> + <color name="i_am_color_24ed">#000024ed</color> + <color name="i_am_color_24ee">#000024ee</color> + <color name="i_am_color_24ef">#000024ef</color> + <color name="i_am_color_24f0">#000024f0</color> + <color name="i_am_color_24f1">#000024f1</color> + <color name="i_am_color_24f2">#000024f2</color> + <color name="i_am_color_24f3">#000024f3</color> + <color name="i_am_color_24f4">#000024f4</color> + <color name="i_am_color_24f5">#000024f5</color> + <color name="i_am_color_24f6">#000024f6</color> + <color name="i_am_color_24f7">#000024f7</color> + <color name="i_am_color_24f8">#000024f8</color> + <color name="i_am_color_24f9">#000024f9</color> + <color name="i_am_color_24fa">#000024fa</color> + <color name="i_am_color_24fb">#000024fb</color> + <color name="i_am_color_24fc">#000024fc</color> + <color name="i_am_color_24fd">#000024fd</color> + <color name="i_am_color_24fe">#000024fe</color> + <color name="i_am_color_24ff">#000024ff</color> + <color name="i_am_color_2500">#00002500</color> + <color name="i_am_color_2501">#00002501</color> + <color name="i_am_color_2502">#00002502</color> + <color name="i_am_color_2503">#00002503</color> + <color name="i_am_color_2504">#00002504</color> + <color name="i_am_color_2505">#00002505</color> + <color name="i_am_color_2506">#00002506</color> + <color name="i_am_color_2507">#00002507</color> + <color name="i_am_color_2508">#00002508</color> + <color name="i_am_color_2509">#00002509</color> + <color name="i_am_color_250a">#0000250a</color> + <color name="i_am_color_250b">#0000250b</color> + <color name="i_am_color_250c">#0000250c</color> + <color name="i_am_color_250d">#0000250d</color> + <color name="i_am_color_250e">#0000250e</color> + <color name="i_am_color_250f">#0000250f</color> + <color name="i_am_color_2510">#00002510</color> + <color name="i_am_color_2511">#00002511</color> + <color name="i_am_color_2512">#00002512</color> + <color name="i_am_color_2513">#00002513</color> + <color name="i_am_color_2514">#00002514</color> + <color name="i_am_color_2515">#00002515</color> + <color name="i_am_color_2516">#00002516</color> + <color name="i_am_color_2517">#00002517</color> + <color name="i_am_color_2518">#00002518</color> + <color name="i_am_color_2519">#00002519</color> + <color name="i_am_color_251a">#0000251a</color> + <color name="i_am_color_251b">#0000251b</color> + <color name="i_am_color_251c">#0000251c</color> + <color name="i_am_color_251d">#0000251d</color> + <color name="i_am_color_251e">#0000251e</color> + <color name="i_am_color_251f">#0000251f</color> + <color name="i_am_color_2520">#00002520</color> + <color name="i_am_color_2521">#00002521</color> + <color name="i_am_color_2522">#00002522</color> + <color name="i_am_color_2523">#00002523</color> + <color name="i_am_color_2524">#00002524</color> + <color name="i_am_color_2525">#00002525</color> + <color name="i_am_color_2526">#00002526</color> + <color name="i_am_color_2527">#00002527</color> + <color name="i_am_color_2528">#00002528</color> + <color name="i_am_color_2529">#00002529</color> + <color name="i_am_color_252a">#0000252a</color> + <color name="i_am_color_252b">#0000252b</color> + <color name="i_am_color_252c">#0000252c</color> + <color name="i_am_color_252d">#0000252d</color> + <color name="i_am_color_252e">#0000252e</color> + <color name="i_am_color_252f">#0000252f</color> + <color name="i_am_color_2530">#00002530</color> + <color name="i_am_color_2531">#00002531</color> + <color name="i_am_color_2532">#00002532</color> + <color name="i_am_color_2533">#00002533</color> + <color name="i_am_color_2534">#00002534</color> + <color name="i_am_color_2535">#00002535</color> + <color name="i_am_color_2536">#00002536</color> + <color name="i_am_color_2537">#00002537</color> + <color name="i_am_color_2538">#00002538</color> + <color name="i_am_color_2539">#00002539</color> + <color name="i_am_color_253a">#0000253a</color> + <color name="i_am_color_253b">#0000253b</color> + <color name="i_am_color_253c">#0000253c</color> + <color name="i_am_color_253d">#0000253d</color> + <color name="i_am_color_253e">#0000253e</color> + <color name="i_am_color_253f">#0000253f</color> + <color name="i_am_color_2540">#00002540</color> + <color name="i_am_color_2541">#00002541</color> + <color name="i_am_color_2542">#00002542</color> + <color name="i_am_color_2543">#00002543</color> + <color name="i_am_color_2544">#00002544</color> + <color name="i_am_color_2545">#00002545</color> + <color name="i_am_color_2546">#00002546</color> + <color name="i_am_color_2547">#00002547</color> + <color name="i_am_color_2548">#00002548</color> + <color name="i_am_color_2549">#00002549</color> + <color name="i_am_color_254a">#0000254a</color> + <color name="i_am_color_254b">#0000254b</color> + <color name="i_am_color_254c">#0000254c</color> + <color name="i_am_color_254d">#0000254d</color> + <color name="i_am_color_254e">#0000254e</color> + <color name="i_am_color_254f">#0000254f</color> + <color name="i_am_color_2550">#00002550</color> + <color name="i_am_color_2551">#00002551</color> + <color name="i_am_color_2552">#00002552</color> + <color name="i_am_color_2553">#00002553</color> + <color name="i_am_color_2554">#00002554</color> + <color name="i_am_color_2555">#00002555</color> + <color name="i_am_color_2556">#00002556</color> + <color name="i_am_color_2557">#00002557</color> + <color name="i_am_color_2558">#00002558</color> + <color name="i_am_color_2559">#00002559</color> + <color name="i_am_color_255a">#0000255a</color> + <color name="i_am_color_255b">#0000255b</color> + <color name="i_am_color_255c">#0000255c</color> + <color name="i_am_color_255d">#0000255d</color> + <color name="i_am_color_255e">#0000255e</color> + <color name="i_am_color_255f">#0000255f</color> + <color name="i_am_color_2560">#00002560</color> + <color name="i_am_color_2561">#00002561</color> + <color name="i_am_color_2562">#00002562</color> + <color name="i_am_color_2563">#00002563</color> + <color name="i_am_color_2564">#00002564</color> + <color name="i_am_color_2565">#00002565</color> + <color name="i_am_color_2566">#00002566</color> + <color name="i_am_color_2567">#00002567</color> + <color name="i_am_color_2568">#00002568</color> + <color name="i_am_color_2569">#00002569</color> + <color name="i_am_color_256a">#0000256a</color> + <color name="i_am_color_256b">#0000256b</color> + <color name="i_am_color_256c">#0000256c</color> + <color name="i_am_color_256d">#0000256d</color> + <color name="i_am_color_256e">#0000256e</color> + <color name="i_am_color_256f">#0000256f</color> + <color name="i_am_color_2570">#00002570</color> + <color name="i_am_color_2571">#00002571</color> + <color name="i_am_color_2572">#00002572</color> + <color name="i_am_color_2573">#00002573</color> + <color name="i_am_color_2574">#00002574</color> + <color name="i_am_color_2575">#00002575</color> + <color name="i_am_color_2576">#00002576</color> + <color name="i_am_color_2577">#00002577</color> + <color name="i_am_color_2578">#00002578</color> + <color name="i_am_color_2579">#00002579</color> + <color name="i_am_color_257a">#0000257a</color> + <color name="i_am_color_257b">#0000257b</color> + <color name="i_am_color_257c">#0000257c</color> + <color name="i_am_color_257d">#0000257d</color> + <color name="i_am_color_257e">#0000257e</color> + <color name="i_am_color_257f">#0000257f</color> + <color name="i_am_color_2580">#00002580</color> + <color name="i_am_color_2581">#00002581</color> + <color name="i_am_color_2582">#00002582</color> + <color name="i_am_color_2583">#00002583</color> + <color name="i_am_color_2584">#00002584</color> + <color name="i_am_color_2585">#00002585</color> + <color name="i_am_color_2586">#00002586</color> + <color name="i_am_color_2587">#00002587</color> + <color name="i_am_color_2588">#00002588</color> + <color name="i_am_color_2589">#00002589</color> + <color name="i_am_color_258a">#0000258a</color> + <color name="i_am_color_258b">#0000258b</color> + <color name="i_am_color_258c">#0000258c</color> + <color name="i_am_color_258d">#0000258d</color> + <color name="i_am_color_258e">#0000258e</color> + <color name="i_am_color_258f">#0000258f</color> + <color name="i_am_color_2590">#00002590</color> + <color name="i_am_color_2591">#00002591</color> + <color name="i_am_color_2592">#00002592</color> + <color name="i_am_color_2593">#00002593</color> + <color name="i_am_color_2594">#00002594</color> + <color name="i_am_color_2595">#00002595</color> + <color name="i_am_color_2596">#00002596</color> + <color name="i_am_color_2597">#00002597</color> + <color name="i_am_color_2598">#00002598</color> + <color name="i_am_color_2599">#00002599</color> + <color name="i_am_color_259a">#0000259a</color> + <color name="i_am_color_259b">#0000259b</color> + <color name="i_am_color_259c">#0000259c</color> + <color name="i_am_color_259d">#0000259d</color> + <color name="i_am_color_259e">#0000259e</color> + <color name="i_am_color_259f">#0000259f</color> + <color name="i_am_color_25a0">#000025a0</color> + <color name="i_am_color_25a1">#000025a1</color> + <color name="i_am_color_25a2">#000025a2</color> + <color name="i_am_color_25a3">#000025a3</color> + <color name="i_am_color_25a4">#000025a4</color> + <color name="i_am_color_25a5">#000025a5</color> + <color name="i_am_color_25a6">#000025a6</color> + <color name="i_am_color_25a7">#000025a7</color> + <color name="i_am_color_25a8">#000025a8</color> + <color name="i_am_color_25a9">#000025a9</color> + <color name="i_am_color_25aa">#000025aa</color> + <color name="i_am_color_25ab">#000025ab</color> + <color name="i_am_color_25ac">#000025ac</color> + <color name="i_am_color_25ad">#000025ad</color> + <color name="i_am_color_25ae">#000025ae</color> + <color name="i_am_color_25af">#000025af</color> + <color name="i_am_color_25b0">#000025b0</color> + <color name="i_am_color_25b1">#000025b1</color> + <color name="i_am_color_25b2">#000025b2</color> + <color name="i_am_color_25b3">#000025b3</color> + <color name="i_am_color_25b4">#000025b4</color> + <color name="i_am_color_25b5">#000025b5</color> + <color name="i_am_color_25b6">#000025b6</color> + <color name="i_am_color_25b7">#000025b7</color> + <color name="i_am_color_25b8">#000025b8</color> + <color name="i_am_color_25b9">#000025b9</color> + <color name="i_am_color_25ba">#000025ba</color> + <color name="i_am_color_25bb">#000025bb</color> + <color name="i_am_color_25bc">#000025bc</color> + <color name="i_am_color_25bd">#000025bd</color> + <color name="i_am_color_25be">#000025be</color> + <color name="i_am_color_25bf">#000025bf</color> + <color name="i_am_color_25c0">#000025c0</color> + <color name="i_am_color_25c1">#000025c1</color> + <color name="i_am_color_25c2">#000025c2</color> + <color name="i_am_color_25c3">#000025c3</color> + <color name="i_am_color_25c4">#000025c4</color> + <color name="i_am_color_25c5">#000025c5</color> + <color name="i_am_color_25c6">#000025c6</color> + <color name="i_am_color_25c7">#000025c7</color> + <color name="i_am_color_25c8">#000025c8</color> + <color name="i_am_color_25c9">#000025c9</color> + <color name="i_am_color_25ca">#000025ca</color> + <color name="i_am_color_25cb">#000025cb</color> + <color name="i_am_color_25cc">#000025cc</color> + <color name="i_am_color_25cd">#000025cd</color> + <color name="i_am_color_25ce">#000025ce</color> + <color name="i_am_color_25cf">#000025cf</color> + <color name="i_am_color_25d0">#000025d0</color> + <color name="i_am_color_25d1">#000025d1</color> + <color name="i_am_color_25d2">#000025d2</color> + <color name="i_am_color_25d3">#000025d3</color> + <color name="i_am_color_25d4">#000025d4</color> + <color name="i_am_color_25d5">#000025d5</color> + <color name="i_am_color_25d6">#000025d6</color> + <color name="i_am_color_25d7">#000025d7</color> + <color name="i_am_color_25d8">#000025d8</color> + <color name="i_am_color_25d9">#000025d9</color> + <color name="i_am_color_25da">#000025da</color> + <color name="i_am_color_25db">#000025db</color> + <color name="i_am_color_25dc">#000025dc</color> + <color name="i_am_color_25dd">#000025dd</color> + <color name="i_am_color_25de">#000025de</color> + <color name="i_am_color_25df">#000025df</color> + <color name="i_am_color_25e0">#000025e0</color> + <color name="i_am_color_25e1">#000025e1</color> + <color name="i_am_color_25e2">#000025e2</color> + <color name="i_am_color_25e3">#000025e3</color> + <color name="i_am_color_25e4">#000025e4</color> + <color name="i_am_color_25e5">#000025e5</color> + <color name="i_am_color_25e6">#000025e6</color> + <color name="i_am_color_25e7">#000025e7</color> + <color name="i_am_color_25e8">#000025e8</color> + <color name="i_am_color_25e9">#000025e9</color> + <color name="i_am_color_25ea">#000025ea</color> + <color name="i_am_color_25eb">#000025eb</color> + <color name="i_am_color_25ec">#000025ec</color> + <color name="i_am_color_25ed">#000025ed</color> + <color name="i_am_color_25ee">#000025ee</color> + <color name="i_am_color_25ef">#000025ef</color> + <color name="i_am_color_25f0">#000025f0</color> + <color name="i_am_color_25f1">#000025f1</color> + <color name="i_am_color_25f2">#000025f2</color> + <color name="i_am_color_25f3">#000025f3</color> + <color name="i_am_color_25f4">#000025f4</color> + <color name="i_am_color_25f5">#000025f5</color> + <color name="i_am_color_25f6">#000025f6</color> + <color name="i_am_color_25f7">#000025f7</color> + <color name="i_am_color_25f8">#000025f8</color> + <color name="i_am_color_25f9">#000025f9</color> + <color name="i_am_color_25fa">#000025fa</color> + <color name="i_am_color_25fb">#000025fb</color> + <color name="i_am_color_25fc">#000025fc</color> + <color name="i_am_color_25fd">#000025fd</color> + <color name="i_am_color_25fe">#000025fe</color> + <color name="i_am_color_25ff">#000025ff</color> + <color name="i_am_color_2600">#00002600</color> + <color name="i_am_color_2601">#00002601</color> + <color name="i_am_color_2602">#00002602</color> + <color name="i_am_color_2603">#00002603</color> + <color name="i_am_color_2604">#00002604</color> + <color name="i_am_color_2605">#00002605</color> + <color name="i_am_color_2606">#00002606</color> + <color name="i_am_color_2607">#00002607</color> + <color name="i_am_color_2608">#00002608</color> + <color name="i_am_color_2609">#00002609</color> + <color name="i_am_color_260a">#0000260a</color> + <color name="i_am_color_260b">#0000260b</color> + <color name="i_am_color_260c">#0000260c</color> + <color name="i_am_color_260d">#0000260d</color> + <color name="i_am_color_260e">#0000260e</color> + <color name="i_am_color_260f">#0000260f</color> + <color name="i_am_color_2610">#00002610</color> + <color name="i_am_color_2611">#00002611</color> + <color name="i_am_color_2612">#00002612</color> + <color name="i_am_color_2613">#00002613</color> + <color name="i_am_color_2614">#00002614</color> + <color name="i_am_color_2615">#00002615</color> + <color name="i_am_color_2616">#00002616</color> + <color name="i_am_color_2617">#00002617</color> + <color name="i_am_color_2618">#00002618</color> + <color name="i_am_color_2619">#00002619</color> + <color name="i_am_color_261a">#0000261a</color> + <color name="i_am_color_261b">#0000261b</color> + <color name="i_am_color_261c">#0000261c</color> + <color name="i_am_color_261d">#0000261d</color> + <color name="i_am_color_261e">#0000261e</color> + <color name="i_am_color_261f">#0000261f</color> + <color name="i_am_color_2620">#00002620</color> + <color name="i_am_color_2621">#00002621</color> + <color name="i_am_color_2622">#00002622</color> + <color name="i_am_color_2623">#00002623</color> + <color name="i_am_color_2624">#00002624</color> + <color name="i_am_color_2625">#00002625</color> + <color name="i_am_color_2626">#00002626</color> + <color name="i_am_color_2627">#00002627</color> + <color name="i_am_color_2628">#00002628</color> + <color name="i_am_color_2629">#00002629</color> + <color name="i_am_color_262a">#0000262a</color> + <color name="i_am_color_262b">#0000262b</color> + <color name="i_am_color_262c">#0000262c</color> + <color name="i_am_color_262d">#0000262d</color> + <color name="i_am_color_262e">#0000262e</color> + <color name="i_am_color_262f">#0000262f</color> + <color name="i_am_color_2630">#00002630</color> + <color name="i_am_color_2631">#00002631</color> + <color name="i_am_color_2632">#00002632</color> + <color name="i_am_color_2633">#00002633</color> + <color name="i_am_color_2634">#00002634</color> + <color name="i_am_color_2635">#00002635</color> + <color name="i_am_color_2636">#00002636</color> + <color name="i_am_color_2637">#00002637</color> + <color name="i_am_color_2638">#00002638</color> + <color name="i_am_color_2639">#00002639</color> + <color name="i_am_color_263a">#0000263a</color> + <color name="i_am_color_263b">#0000263b</color> + <color name="i_am_color_263c">#0000263c</color> + <color name="i_am_color_263d">#0000263d</color> + <color name="i_am_color_263e">#0000263e</color> + <color name="i_am_color_263f">#0000263f</color> + <color name="i_am_color_2640">#00002640</color> + <color name="i_am_color_2641">#00002641</color> + <color name="i_am_color_2642">#00002642</color> + <color name="i_am_color_2643">#00002643</color> + <color name="i_am_color_2644">#00002644</color> + <color name="i_am_color_2645">#00002645</color> + <color name="i_am_color_2646">#00002646</color> + <color name="i_am_color_2647">#00002647</color> + <color name="i_am_color_2648">#00002648</color> + <color name="i_am_color_2649">#00002649</color> + <color name="i_am_color_264a">#0000264a</color> + <color name="i_am_color_264b">#0000264b</color> + <color name="i_am_color_264c">#0000264c</color> + <color name="i_am_color_264d">#0000264d</color> + <color name="i_am_color_264e">#0000264e</color> + <color name="i_am_color_264f">#0000264f</color> + <color name="i_am_color_2650">#00002650</color> + <color name="i_am_color_2651">#00002651</color> + <color name="i_am_color_2652">#00002652</color> + <color name="i_am_color_2653">#00002653</color> + <color name="i_am_color_2654">#00002654</color> + <color name="i_am_color_2655">#00002655</color> + <color name="i_am_color_2656">#00002656</color> + <color name="i_am_color_2657">#00002657</color> + <color name="i_am_color_2658">#00002658</color> + <color name="i_am_color_2659">#00002659</color> + <color name="i_am_color_265a">#0000265a</color> + <color name="i_am_color_265b">#0000265b</color> + <color name="i_am_color_265c">#0000265c</color> + <color name="i_am_color_265d">#0000265d</color> + <color name="i_am_color_265e">#0000265e</color> + <color name="i_am_color_265f">#0000265f</color> + <color name="i_am_color_2660">#00002660</color> + <color name="i_am_color_2661">#00002661</color> + <color name="i_am_color_2662">#00002662</color> + <color name="i_am_color_2663">#00002663</color> + <color name="i_am_color_2664">#00002664</color> + <color name="i_am_color_2665">#00002665</color> + <color name="i_am_color_2666">#00002666</color> + <color name="i_am_color_2667">#00002667</color> + <color name="i_am_color_2668">#00002668</color> + <color name="i_am_color_2669">#00002669</color> + <color name="i_am_color_266a">#0000266a</color> + <color name="i_am_color_266b">#0000266b</color> + <color name="i_am_color_266c">#0000266c</color> + <color name="i_am_color_266d">#0000266d</color> + <color name="i_am_color_266e">#0000266e</color> + <color name="i_am_color_266f">#0000266f</color> + <color name="i_am_color_2670">#00002670</color> + <color name="i_am_color_2671">#00002671</color> + <color name="i_am_color_2672">#00002672</color> + <color name="i_am_color_2673">#00002673</color> + <color name="i_am_color_2674">#00002674</color> + <color name="i_am_color_2675">#00002675</color> + <color name="i_am_color_2676">#00002676</color> + <color name="i_am_color_2677">#00002677</color> + <color name="i_am_color_2678">#00002678</color> + <color name="i_am_color_2679">#00002679</color> + <color name="i_am_color_267a">#0000267a</color> + <color name="i_am_color_267b">#0000267b</color> + <color name="i_am_color_267c">#0000267c</color> + <color name="i_am_color_267d">#0000267d</color> + <color name="i_am_color_267e">#0000267e</color> + <color name="i_am_color_267f">#0000267f</color> + <color name="i_am_color_2680">#00002680</color> + <color name="i_am_color_2681">#00002681</color> + <color name="i_am_color_2682">#00002682</color> + <color name="i_am_color_2683">#00002683</color> + <color name="i_am_color_2684">#00002684</color> + <color name="i_am_color_2685">#00002685</color> + <color name="i_am_color_2686">#00002686</color> + <color name="i_am_color_2687">#00002687</color> + <color name="i_am_color_2688">#00002688</color> + <color name="i_am_color_2689">#00002689</color> + <color name="i_am_color_268a">#0000268a</color> + <color name="i_am_color_268b">#0000268b</color> + <color name="i_am_color_268c">#0000268c</color> + <color name="i_am_color_268d">#0000268d</color> + <color name="i_am_color_268e">#0000268e</color> + <color name="i_am_color_268f">#0000268f</color> + <color name="i_am_color_2690">#00002690</color> + <color name="i_am_color_2691">#00002691</color> + <color name="i_am_color_2692">#00002692</color> + <color name="i_am_color_2693">#00002693</color> + <color name="i_am_color_2694">#00002694</color> + <color name="i_am_color_2695">#00002695</color> + <color name="i_am_color_2696">#00002696</color> + <color name="i_am_color_2697">#00002697</color> + <color name="i_am_color_2698">#00002698</color> + <color name="i_am_color_2699">#00002699</color> + <color name="i_am_color_269a">#0000269a</color> + <color name="i_am_color_269b">#0000269b</color> + <color name="i_am_color_269c">#0000269c</color> + <color name="i_am_color_269d">#0000269d</color> + <color name="i_am_color_269e">#0000269e</color> + <color name="i_am_color_269f">#0000269f</color> + <color name="i_am_color_26a0">#000026a0</color> + <color name="i_am_color_26a1">#000026a1</color> + <color name="i_am_color_26a2">#000026a2</color> + <color name="i_am_color_26a3">#000026a3</color> + <color name="i_am_color_26a4">#000026a4</color> + <color name="i_am_color_26a5">#000026a5</color> + <color name="i_am_color_26a6">#000026a6</color> + <color name="i_am_color_26a7">#000026a7</color> + <color name="i_am_color_26a8">#000026a8</color> + <color name="i_am_color_26a9">#000026a9</color> + <color name="i_am_color_26aa">#000026aa</color> + <color name="i_am_color_26ab">#000026ab</color> + <color name="i_am_color_26ac">#000026ac</color> + <color name="i_am_color_26ad">#000026ad</color> + <color name="i_am_color_26ae">#000026ae</color> + <color name="i_am_color_26af">#000026af</color> + <color name="i_am_color_26b0">#000026b0</color> + <color name="i_am_color_26b1">#000026b1</color> + <color name="i_am_color_26b2">#000026b2</color> + <color name="i_am_color_26b3">#000026b3</color> + <color name="i_am_color_26b4">#000026b4</color> + <color name="i_am_color_26b5">#000026b5</color> + <color name="i_am_color_26b6">#000026b6</color> + <color name="i_am_color_26b7">#000026b7</color> + <color name="i_am_color_26b8">#000026b8</color> + <color name="i_am_color_26b9">#000026b9</color> + <color name="i_am_color_26ba">#000026ba</color> + <color name="i_am_color_26bb">#000026bb</color> + <color name="i_am_color_26bc">#000026bc</color> + <color name="i_am_color_26bd">#000026bd</color> + <color name="i_am_color_26be">#000026be</color> + <color name="i_am_color_26bf">#000026bf</color> + <color name="i_am_color_26c0">#000026c0</color> + <color name="i_am_color_26c1">#000026c1</color> + <color name="i_am_color_26c2">#000026c2</color> + <color name="i_am_color_26c3">#000026c3</color> + <color name="i_am_color_26c4">#000026c4</color> + <color name="i_am_color_26c5">#000026c5</color> + <color name="i_am_color_26c6">#000026c6</color> + <color name="i_am_color_26c7">#000026c7</color> + <color name="i_am_color_26c8">#000026c8</color> + <color name="i_am_color_26c9">#000026c9</color> + <color name="i_am_color_26ca">#000026ca</color> + <color name="i_am_color_26cb">#000026cb</color> + <color name="i_am_color_26cc">#000026cc</color> + <color name="i_am_color_26cd">#000026cd</color> + <color name="i_am_color_26ce">#000026ce</color> + <color name="i_am_color_26cf">#000026cf</color> + <color name="i_am_color_26d0">#000026d0</color> + <color name="i_am_color_26d1">#000026d1</color> + <color name="i_am_color_26d2">#000026d2</color> + <color name="i_am_color_26d3">#000026d3</color> + <color name="i_am_color_26d4">#000026d4</color> + <color name="i_am_color_26d5">#000026d5</color> + <color name="i_am_color_26d6">#000026d6</color> + <color name="i_am_color_26d7">#000026d7</color> + <color name="i_am_color_26d8">#000026d8</color> + <color name="i_am_color_26d9">#000026d9</color> + <color name="i_am_color_26da">#000026da</color> + <color name="i_am_color_26db">#000026db</color> + <color name="i_am_color_26dc">#000026dc</color> + <color name="i_am_color_26dd">#000026dd</color> + <color name="i_am_color_26de">#000026de</color> + <color name="i_am_color_26df">#000026df</color> + <color name="i_am_color_26e0">#000026e0</color> + <color name="i_am_color_26e1">#000026e1</color> + <color name="i_am_color_26e2">#000026e2</color> + <color name="i_am_color_26e3">#000026e3</color> + <color name="i_am_color_26e4">#000026e4</color> + <color name="i_am_color_26e5">#000026e5</color> + <color name="i_am_color_26e6">#000026e6</color> + <color name="i_am_color_26e7">#000026e7</color> + <color name="i_am_color_26e8">#000026e8</color> + <color name="i_am_color_26e9">#000026e9</color> + <color name="i_am_color_26ea">#000026ea</color> + <color name="i_am_color_26eb">#000026eb</color> + <color name="i_am_color_26ec">#000026ec</color> + <color name="i_am_color_26ed">#000026ed</color> + <color name="i_am_color_26ee">#000026ee</color> + <color name="i_am_color_26ef">#000026ef</color> + <color name="i_am_color_26f0">#000026f0</color> + <color name="i_am_color_26f1">#000026f1</color> + <color name="i_am_color_26f2">#000026f2</color> + <color name="i_am_color_26f3">#000026f3</color> + <color name="i_am_color_26f4">#000026f4</color> + <color name="i_am_color_26f5">#000026f5</color> + <color name="i_am_color_26f6">#000026f6</color> + <color name="i_am_color_26f7">#000026f7</color> + <color name="i_am_color_26f8">#000026f8</color> + <color name="i_am_color_26f9">#000026f9</color> + <color name="i_am_color_26fa">#000026fa</color> + <color name="i_am_color_26fb">#000026fb</color> + <color name="i_am_color_26fc">#000026fc</color> + <color name="i_am_color_26fd">#000026fd</color> + <color name="i_am_color_26fe">#000026fe</color> + <color name="i_am_color_26ff">#000026ff</color> + <color name="i_am_color_2700">#00002700</color> + <color name="i_am_color_2701">#00002701</color> + <color name="i_am_color_2702">#00002702</color> + <color name="i_am_color_2703">#00002703</color> + <color name="i_am_color_2704">#00002704</color> + <color name="i_am_color_2705">#00002705</color> + <color name="i_am_color_2706">#00002706</color> + <color name="i_am_color_2707">#00002707</color> + <color name="i_am_color_2708">#00002708</color> + <color name="i_am_color_2709">#00002709</color> + <color name="i_am_color_270a">#0000270a</color> + <color name="i_am_color_270b">#0000270b</color> + <color name="i_am_color_270c">#0000270c</color> + <color name="i_am_color_270d">#0000270d</color> + <color name="i_am_color_270e">#0000270e</color> + <color name="i_am_color_270f">#0000270f</color> + <color name="i_am_color_2710">#00002710</color> +</resources> diff --git a/apct-tests/perftests/core/src/android/app/ResourcesPerfTest.java b/apct-tests/perftests/core/src/android/app/ResourcesPerfTest.java index 72162448a2e0..54b79b4fb926 100644 --- a/apct-tests/perftests/core/src/android/app/ResourcesPerfTest.java +++ b/apct-tests/perftests/core/src/android/app/ResourcesPerfTest.java @@ -37,6 +37,7 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; +import java.util.Random; /** * Benchmarks for {@link android.content.res.Resources}. @@ -222,4 +223,24 @@ public class ResourcesPerfTest { state.resumeTiming(); } } -}
\ No newline at end of file + + @Test + public void getIdentifier() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + final Random random = new Random(System.currentTimeMillis()); + final Context context = InstrumentationRegistry.getTargetContext(); + final String packageName = context.getPackageName(); + while (state.keepRunning()) { + state.pauseTiming(); + final int expectedInteger = random.nextInt(10001); + final String expectedString = Integer.toHexString(expectedInteger); + final String entryName = "i_am_color_" + expectedString; + state.resumeTiming(); + + final int resIdentifier = mRes.getIdentifier(entryName, "color", packageName); + if (resIdentifier == 0) { + fail("Color \"" + entryName + "\" is not found"); + } + } + } +} diff --git a/apex/OWNERS b/apex/OWNERS index b3e81b925ddc..e867586c11f9 100644 --- a/apex/OWNERS +++ b/apex/OWNERS @@ -1 +1 @@ -file:platform/packages/modules/common:/OWNERS +file:platform/packages/modules/common:/OWNERS #{LAST_RESORT_SUGGESTION} diff --git a/apex/media/Android.bp b/apex/media/Android.bp deleted file mode 100644 index 1a710a98b0a9..000000000000 --- a/apex/media/Android.bp +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (C) 2020 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_visibility: [ - ":__subpackages__", - "//frameworks/av/apex", - "//frameworks/av/apex/testing", - ], - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "frameworks_base_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["frameworks_base_license"], -} - -sdk { - name: "media-module-sdk", - bootclasspath_fragments: ["com.android.media-bootclasspath-fragment"], - systemserverclasspath_fragments: ["com.android.media-systemserverclasspath-fragment"], - java_sdk_libs: [ - "framework-media", - ], -} diff --git a/apex/media/OWNERS b/apex/media/OWNERS deleted file mode 100644 index 2c5965c300e3..000000000000 --- a/apex/media/OWNERS +++ /dev/null @@ -1,12 +0,0 @@ -# Bug component: 1344 -hdmoon@google.com -jinpark@google.com -klhyun@google.com -lnilsson@google.com -sungsoo@google.com - -# go/android-fwk-media-solutions for info on areas of ownership. -include platform/frameworks/av:/media/janitors/media_solutions_OWNERS - -# media reliability team packages/delivers the media mainline builds. -include platform/frameworks/av:/media/janitors/reliability_mainline_OWNERS diff --git a/apex/media/aidl/Android.bp b/apex/media/aidl/Android.bp deleted file mode 100644 index 545a0cd884dc..000000000000 --- a/apex/media/aidl/Android.bp +++ /dev/null @@ -1,44 +0,0 @@ -// -// Copyright 2020 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 { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "frameworks_base_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["frameworks_base_license"], -} - -filegroup { - name: "stable-media-aidl-srcs", - srcs: ["stable/**/*.aidl"], - path: "stable", -} - -filegroup { - name: "private-media-aidl-srcs", - srcs: ["private/**/I*.aidl"], - path: "private", -} - -filegroup { - name: "media-aidl-srcs", - srcs: [ - ":private-media-aidl-srcs", - ":stable-media-aidl-srcs", - ], -} diff --git a/apex/media/aidl/private/android/media/IMediaCommunicationService.aidl b/apex/media/aidl/private/android/media/IMediaCommunicationService.aidl deleted file mode 100644 index fb3172b8c764..000000000000 --- a/apex/media/aidl/private/android/media/IMediaCommunicationService.aidl +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright 2020 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 android.media; - -import android.media.Session2Token; -import android.media.IMediaCommunicationServiceCallback; -import android.media.MediaParceledListSlice; - -/** {@hide} */ -interface IMediaCommunicationService { - void notifySession2Created(in Session2Token sessionToken); - boolean isTrusted(String controllerPackageName, int controllerPid, int controllerUid); - MediaParceledListSlice getSession2Tokens(int userId); - - void registerCallback(IMediaCommunicationServiceCallback callback, String packageName); - void unregisterCallback(IMediaCommunicationServiceCallback callback); -} - diff --git a/apex/media/aidl/private/android/media/IMediaCommunicationServiceCallback.aidl b/apex/media/aidl/private/android/media/IMediaCommunicationServiceCallback.aidl deleted file mode 100644 index e347ebf4a983..000000000000 --- a/apex/media/aidl/private/android/media/IMediaCommunicationServiceCallback.aidl +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright 2021 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 android.media; - -import android.media.Session2Token; -import android.media.MediaParceledListSlice; - -/** {@hide} */ -oneway interface IMediaCommunicationServiceCallback { - void onSession2Created(in Session2Token token); - void onSession2Changed(in MediaParceledListSlice tokens); -} - diff --git a/apex/media/aidl/private/android/media/IMediaController2.aidl b/apex/media/aidl/private/android/media/IMediaController2.aidl deleted file mode 100644 index 42c6e70529ec..000000000000 --- a/apex/media/aidl/private/android/media/IMediaController2.aidl +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2018 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 android.media; - -import android.os.Bundle; -import android.os.ResultReceiver; -import android.media.Session2Command; - -/** - * Interface from MediaSession2 to MediaController2. - * <p> - * Keep this interface oneway. Otherwise a malicious app may implement fake version of this, - * and holds calls from session to make session owner(s) frozen. - * @hide - */ - // Code for AML only -oneway interface IMediaController2 { - void notifyConnected(int seq, in Bundle connectionResult) = 0; - void notifyDisconnected(int seq) = 1; - void notifyPlaybackActiveChanged(int seq, boolean playbackActive) = 2; - void sendSessionCommand(int seq, in Session2Command command, in Bundle args, - in ResultReceiver resultReceiver) = 3; - void cancelSessionCommand(int seq) = 4; - // Next Id : 5 -} diff --git a/apex/media/aidl/private/android/media/IMediaSession2.aidl b/apex/media/aidl/private/android/media/IMediaSession2.aidl deleted file mode 100644 index 26e717b39afc..000000000000 --- a/apex/media/aidl/private/android/media/IMediaSession2.aidl +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2018 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 android.media; - -import android.os.Bundle; -import android.os.ResultReceiver; -import android.media.Controller2Link; -import android.media.Session2Command; - -/** - * Interface from MediaController2 to MediaSession2. - * <p> - * Keep this interface oneway. Otherwise a malicious app may implement fake version of this, - * and holds calls from session to make session owner(s) frozen. - * @hide - */ - // Code for AML only -oneway interface IMediaSession2 { - void connect(in Controller2Link caller, int seq, in Bundle connectionRequest) = 0; - void disconnect(in Controller2Link caller, int seq) = 1; - void sendSessionCommand(in Controller2Link caller, int seq, in Session2Command sessionCommand, - in Bundle args, in ResultReceiver resultReceiver) = 2; - void cancelSessionCommand(in Controller2Link caller, int seq) = 3; - // Next Id : 4 -} diff --git a/apex/media/aidl/stable/android/media/MediaParceledListSlice.aidl b/apex/media/aidl/stable/android/media/MediaParceledListSlice.aidl deleted file mode 100644 index 92d673fd25cb..000000000000 --- a/apex/media/aidl/stable/android/media/MediaParceledListSlice.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2020, 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 android.media; - -parcelable MediaParceledListSlice<T>; diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp deleted file mode 100644 index d963e68d80ec..000000000000 --- a/apex/media/framework/Android.bp +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright (C) 2020 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 { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "frameworks_base_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["frameworks_base_license"], -} - -java_library { - name: "updatable-media", - - srcs: [ - ":updatable-media-srcs", - ], - - permitted_packages: [ - "android.media", - ], - - optimize: { - enabled: true, - shrink: true, - proguard_flags_files: ["updatable-media-proguard.flags"], - }, - - installable: true, - - sdk_version: "module_current", - libs: [ - "androidx.annotation_annotation", - "framework-annotations-lib", - ], - static_libs: [ - "exoplayer2-extractor", - "mediatranscoding_aidl_interface-java", - "modules-annotation-minsdk", - "modules-utils-build", - ], - jarjar_rules: "jarjar_rules.txt", - - plugins: ["java_api_finder"], - - hostdex: true, // for hiddenapi check - apex_available: [ - "com.android.media", - "test_com.android.media", - ], - min_sdk_version: "29", - visibility: [ - "//frameworks/av/apex:__subpackages__", - "//frameworks/base", // For framework-all - "//frameworks/base/apex/media/service", - ], -} - -filegroup { - name: "updatable-media-srcs", - srcs: [ - "java/android/media/MediaFrameworkInitializer.java", - ":media-aidl-srcs", - ":mediaparceledlistslice-java-srcs", - ":mediaparser-srcs", - ":mediasession2-java-srcs", - ":mediatranscoding-srcs", - ], - visibility: ["//frameworks/base"], -} - -filegroup { - name: "mediasession2-java-srcs", - srcs: [ - "java/android/media/Controller2Link.java", - "java/android/media/MediaConstants.java", - "java/android/media/MediaController2.java", - "java/android/media/MediaSession2.java", - "java/android/media/MediaSession2Service.java", - "java/android/media/Session2Command.java", - "java/android/media/Session2CommandGroup.java", - "java/android/media/Session2Link.java", - "java/android/media/Session2Token.java", - "java/android/media/MediaCommunicationManager.java", - ], - path: "java", -} - -filegroup { - name: "mediaparceledlistslice-java-srcs", - srcs: [ - "java/android/media/MediaParceledListSlice.java", - "java/android/media/BaseMediaParceledListSlice.java", - ], - path: "java", -} - -filegroup { - name: "mediaparser-srcs", - srcs: [ - "java/android/media/MediaParser.java", - ], - path: "java", -} - -filegroup { - name: "mediatranscoding-srcs", - srcs: [ - "java/android/media/ApplicationMediaCapabilities.java", - "java/android/media/MediaFeature.java", - "java/android/media/MediaTranscodingManager.java", - ], - path: "java", -} - -java_sdk_library { - name: "framework-media", - defaults: ["framework-module-defaults"], - - // This is only used to define the APIs for updatable-media. - api_only: true, - - srcs: [ - ":updatable-media-srcs", - ], - - impl_library_visibility: ["//frameworks/av/apex:__subpackages__"], -} - -cc_library_shared { - name: "libmediaparser-jni", - srcs: [ - "jni/android_media_MediaParserJNI.cpp", - ], - header_libs: ["jni_headers"], - shared_libs: [ - "libandroid", - "liblog", - "libmediametrics", - ], - cflags: [ - "-Wall", - "-Werror", - "-Wno-unused-parameter", - "-Wunreachable-code", - "-Wunused", - ], - apex_available: [ - "com.android.media", - ], - min_sdk_version: "29", -} diff --git a/apex/media/framework/TEST_MAPPING b/apex/media/framework/TEST_MAPPING deleted file mode 100644 index 3d2191410413..000000000000 --- a/apex/media/framework/TEST_MAPPING +++ /dev/null @@ -1,10 +0,0 @@ -{ - "presubmit": [ - { - "name": "CtsMediaParserTestCases" - }, - { - "name": "CtsMediaParserHostTestCases" - } - ] -} diff --git a/apex/media/framework/api/current.txt b/apex/media/framework/api/current.txt deleted file mode 100644 index b7d7ed866c89..000000000000 --- a/apex/media/framework/api/current.txt +++ /dev/null @@ -1,267 +0,0 @@ -// Signature format: 2.0 -package android.media { - - public final class ApplicationMediaCapabilities implements android.os.Parcelable { - method @NonNull public static android.media.ApplicationMediaCapabilities createFromXml(@NonNull org.xmlpull.v1.XmlPullParser); - method public int describeContents(); - method @NonNull public java.util.List<java.lang.String> getSupportedHdrTypes(); - method @NonNull public java.util.List<java.lang.String> getSupportedVideoMimeTypes(); - method @NonNull public java.util.List<java.lang.String> getUnsupportedHdrTypes(); - method @NonNull public java.util.List<java.lang.String> getUnsupportedVideoMimeTypes(); - method public boolean isFormatSpecified(@NonNull String); - method public boolean isHdrTypeSupported(@NonNull String); - method public boolean isVideoMimeTypeSupported(@NonNull String); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.media.ApplicationMediaCapabilities> CREATOR; - } - - public static final class ApplicationMediaCapabilities.Builder { - ctor public ApplicationMediaCapabilities.Builder(); - method @NonNull public android.media.ApplicationMediaCapabilities.Builder addSupportedHdrType(@NonNull String); - method @NonNull public android.media.ApplicationMediaCapabilities.Builder addSupportedVideoMimeType(@NonNull String); - method @NonNull public android.media.ApplicationMediaCapabilities.Builder addUnsupportedHdrType(@NonNull String); - method @NonNull public android.media.ApplicationMediaCapabilities.Builder addUnsupportedVideoMimeType(@NonNull String); - method @NonNull public android.media.ApplicationMediaCapabilities build(); - } - - public class MediaCommunicationManager { - method @NonNull public java.util.List<android.media.Session2Token> getSession2Tokens(); - method @IntRange(from=1) public int getVersion(); - } - - public class MediaController2 implements java.lang.AutoCloseable { - method public void cancelSessionCommand(@NonNull Object); - method public void close(); - method @Nullable public android.media.Session2Token getConnectedToken(); - method public boolean isPlaybackActive(); - method @NonNull public Object sendSessionCommand(@NonNull android.media.Session2Command, @Nullable android.os.Bundle); - } - - public static final class MediaController2.Builder { - ctor public MediaController2.Builder(@NonNull android.content.Context, @NonNull android.media.Session2Token); - method @NonNull public android.media.MediaController2 build(); - method @NonNull public android.media.MediaController2.Builder setConnectionHints(@NonNull android.os.Bundle); - method @NonNull public android.media.MediaController2.Builder setControllerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaController2.ControllerCallback); - } - - public abstract static class MediaController2.ControllerCallback { - ctor public MediaController2.ControllerCallback(); - method public void onCommandResult(@NonNull android.media.MediaController2, @NonNull Object, @NonNull android.media.Session2Command, @NonNull android.media.Session2Command.Result); - method public void onConnected(@NonNull android.media.MediaController2, @NonNull android.media.Session2CommandGroup); - method public void onDisconnected(@NonNull android.media.MediaController2); - method public void onPlaybackActiveChanged(@NonNull android.media.MediaController2, boolean); - method @Nullable public android.media.Session2Command.Result onSessionCommand(@NonNull android.media.MediaController2, @NonNull android.media.Session2Command, @Nullable android.os.Bundle); - } - - public final class MediaFeature { - ctor public MediaFeature(); - } - - public static final class MediaFeature.HdrType { - field public static final String DOLBY_VISION = "android.media.feature.hdr.dolby_vision"; - field public static final String HDR10 = "android.media.feature.hdr.hdr10"; - field public static final String HDR10_PLUS = "android.media.feature.hdr.hdr10_plus"; - field public static final String HLG = "android.media.feature.hdr.hlg"; - } - - public final class MediaParser { - method public boolean advance(@NonNull android.media.MediaParser.SeekableInputReader) throws java.io.IOException; - method @NonNull public static android.media.MediaParser create(@NonNull android.media.MediaParser.OutputConsumer, @NonNull java.lang.String...); - method @NonNull public static android.media.MediaParser createByName(@NonNull String, @NonNull android.media.MediaParser.OutputConsumer); - method @NonNull public android.media.metrics.LogSessionId getLogSessionId(); - method @NonNull public String getParserName(); - method @NonNull public static java.util.List<java.lang.String> getParserNames(@NonNull android.media.MediaFormat); - method public void release(); - method public void seek(@NonNull android.media.MediaParser.SeekPoint); - method public void setLogSessionId(@NonNull android.media.metrics.LogSessionId); - method @NonNull public android.media.MediaParser setParameter(@NonNull String, @NonNull Object); - method public boolean supportsParameter(@NonNull String); - field public static final String PARAMETER_ADTS_ENABLE_CBR_SEEKING = "android.media.mediaparser.adts.enableCbrSeeking"; - field public static final String PARAMETER_AMR_ENABLE_CBR_SEEKING = "android.media.mediaparser.amr.enableCbrSeeking"; - field public static final String PARAMETER_FLAC_DISABLE_ID3 = "android.media.mediaparser.flac.disableId3"; - field public static final String PARAMETER_MATROSKA_DISABLE_CUES_SEEKING = "android.media.mediaparser.matroska.disableCuesSeeking"; - field public static final String PARAMETER_MP3_DISABLE_ID3 = "android.media.mediaparser.mp3.disableId3"; - field public static final String PARAMETER_MP3_ENABLE_CBR_SEEKING = "android.media.mediaparser.mp3.enableCbrSeeking"; - field public static final String PARAMETER_MP3_ENABLE_INDEX_SEEKING = "android.media.mediaparser.mp3.enableIndexSeeking"; - field public static final String PARAMETER_MP4_IGNORE_EDIT_LISTS = "android.media.mediaparser.mp4.ignoreEditLists"; - field public static final String PARAMETER_MP4_IGNORE_TFDT_BOX = "android.media.mediaparser.mp4.ignoreTfdtBox"; - field public static final String PARAMETER_MP4_TREAT_VIDEO_FRAMES_AS_KEYFRAMES = "android.media.mediaparser.mp4.treatVideoFramesAsKeyframes"; - field public static final String PARAMETER_TS_ALLOW_NON_IDR_AVC_KEYFRAMES = "android.media.mediaparser.ts.allowNonIdrAvcKeyframes"; - field public static final String PARAMETER_TS_DETECT_ACCESS_UNITS = "android.media.mediaparser.ts.ignoreDetectAccessUnits"; - field public static final String PARAMETER_TS_ENABLE_HDMV_DTS_AUDIO_STREAMS = "android.media.mediaparser.ts.enableHdmvDtsAudioStreams"; - field public static final String PARAMETER_TS_IGNORE_AAC_STREAM = "android.media.mediaparser.ts.ignoreAacStream"; - field public static final String PARAMETER_TS_IGNORE_AVC_STREAM = "android.media.mediaparser.ts.ignoreAvcStream"; - field public static final String PARAMETER_TS_IGNORE_SPLICE_INFO_STREAM = "android.media.mediaparser.ts.ignoreSpliceInfoStream"; - field public static final String PARAMETER_TS_MODE = "android.media.mediaparser.ts.mode"; - field public static final String PARSER_NAME_AC3 = "android.media.mediaparser.Ac3Parser"; - field public static final String PARSER_NAME_AC4 = "android.media.mediaparser.Ac4Parser"; - field public static final String PARSER_NAME_ADTS = "android.media.mediaparser.AdtsParser"; - field public static final String PARSER_NAME_AMR = "android.media.mediaparser.AmrParser"; - field public static final String PARSER_NAME_FLAC = "android.media.mediaparser.FlacParser"; - field public static final String PARSER_NAME_FLV = "android.media.mediaparser.FlvParser"; - field public static final String PARSER_NAME_FMP4 = "android.media.mediaparser.FragmentedMp4Parser"; - field public static final String PARSER_NAME_MATROSKA = "android.media.mediaparser.MatroskaParser"; - field public static final String PARSER_NAME_MP3 = "android.media.mediaparser.Mp3Parser"; - field public static final String PARSER_NAME_MP4 = "android.media.mediaparser.Mp4Parser"; - field public static final String PARSER_NAME_OGG = "android.media.mediaparser.OggParser"; - field public static final String PARSER_NAME_PS = "android.media.mediaparser.PsParser"; - field public static final String PARSER_NAME_TS = "android.media.mediaparser.TsParser"; - field public static final String PARSER_NAME_UNKNOWN = "android.media.mediaparser.UNKNOWN"; - field public static final String PARSER_NAME_WAV = "android.media.mediaparser.WavParser"; - field public static final int SAMPLE_FLAG_DECODE_ONLY = -2147483648; // 0x80000000 - field public static final int SAMPLE_FLAG_ENCRYPTED = 1073741824; // 0x40000000 - field public static final int SAMPLE_FLAG_HAS_SUPPLEMENTAL_DATA = 268435456; // 0x10000000 - field public static final int SAMPLE_FLAG_KEY_FRAME = 1; // 0x1 - field public static final int SAMPLE_FLAG_LAST_SAMPLE = 536870912; // 0x20000000 - } - - public static interface MediaParser.InputReader { - method public long getLength(); - method public long getPosition(); - method public int read(@NonNull byte[], int, int) throws java.io.IOException; - } - - public static interface MediaParser.OutputConsumer { - method public void onSampleCompleted(int, long, int, int, int, @Nullable android.media.MediaCodec.CryptoInfo); - method public void onSampleDataFound(int, @NonNull android.media.MediaParser.InputReader) throws java.io.IOException; - method public void onSeekMapFound(@NonNull android.media.MediaParser.SeekMap); - method public void onTrackCountFound(int); - method public void onTrackDataFound(int, @NonNull android.media.MediaParser.TrackData); - } - - public static final class MediaParser.ParsingException extends java.io.IOException { - } - - public static final class MediaParser.SeekMap { - method public long getDurationMicros(); - method @NonNull public android.util.Pair<android.media.MediaParser.SeekPoint,android.media.MediaParser.SeekPoint> getSeekPoints(long); - method public boolean isSeekable(); - field public static final int UNKNOWN_DURATION = -2147483648; // 0x80000000 - } - - public static final class MediaParser.SeekPoint { - field @NonNull public static final android.media.MediaParser.SeekPoint START; - field public final long position; - field public final long timeMicros; - } - - public static interface MediaParser.SeekableInputReader extends android.media.MediaParser.InputReader { - method public void seekToPosition(long); - } - - public static final class MediaParser.TrackData { - field @Nullable public final android.media.DrmInitData drmInitData; - field @NonNull public final android.media.MediaFormat mediaFormat; - } - - public static final class MediaParser.UnrecognizedInputFormatException extends java.io.IOException { - } - - public class MediaSession2 implements java.lang.AutoCloseable { - method public void broadcastSessionCommand(@NonNull android.media.Session2Command, @Nullable android.os.Bundle); - method public void cancelSessionCommand(@NonNull android.media.MediaSession2.ControllerInfo, @NonNull Object); - method public void close(); - method @NonNull public java.util.List<android.media.MediaSession2.ControllerInfo> getConnectedControllers(); - method @NonNull public String getId(); - method @NonNull public android.media.Session2Token getToken(); - method public boolean isPlaybackActive(); - method @NonNull public Object sendSessionCommand(@NonNull android.media.MediaSession2.ControllerInfo, @NonNull android.media.Session2Command, @Nullable android.os.Bundle); - method public void setPlaybackActive(boolean); - } - - public static final class MediaSession2.Builder { - ctor public MediaSession2.Builder(@NonNull android.content.Context); - method @NonNull public android.media.MediaSession2 build(); - method @NonNull public android.media.MediaSession2.Builder setExtras(@NonNull android.os.Bundle); - method @NonNull public android.media.MediaSession2.Builder setId(@NonNull String); - method @NonNull public android.media.MediaSession2.Builder setSessionActivity(@Nullable android.app.PendingIntent); - method @NonNull public android.media.MediaSession2.Builder setSessionCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaSession2.SessionCallback); - } - - public static final class MediaSession2.ControllerInfo { - method @NonNull public android.os.Bundle getConnectionHints(); - method @NonNull public String getPackageName(); - method @NonNull public android.media.session.MediaSessionManager.RemoteUserInfo getRemoteUserInfo(); - method public int getUid(); - } - - public abstract static class MediaSession2.SessionCallback { - ctor public MediaSession2.SessionCallback(); - method public void onCommandResult(@NonNull android.media.MediaSession2, @NonNull android.media.MediaSession2.ControllerInfo, @NonNull Object, @NonNull android.media.Session2Command, @NonNull android.media.Session2Command.Result); - method @Nullable public android.media.Session2CommandGroup onConnect(@NonNull android.media.MediaSession2, @NonNull android.media.MediaSession2.ControllerInfo); - method public void onDisconnected(@NonNull android.media.MediaSession2, @NonNull android.media.MediaSession2.ControllerInfo); - method public void onPostConnect(@NonNull android.media.MediaSession2, @NonNull android.media.MediaSession2.ControllerInfo); - method @Nullable public android.media.Session2Command.Result onSessionCommand(@NonNull android.media.MediaSession2, @NonNull android.media.MediaSession2.ControllerInfo, @NonNull android.media.Session2Command, @Nullable android.os.Bundle); - } - - public abstract class MediaSession2Service extends android.app.Service { - ctor public MediaSession2Service(); - method public final void addSession(@NonNull android.media.MediaSession2); - method @NonNull public final java.util.List<android.media.MediaSession2> getSessions(); - method @CallSuper @Nullable public android.os.IBinder onBind(@NonNull android.content.Intent); - method @Nullable public abstract android.media.MediaSession2 onGetSession(@NonNull android.media.MediaSession2.ControllerInfo); - method @Nullable public abstract android.media.MediaSession2Service.MediaNotification onUpdateNotification(@NonNull android.media.MediaSession2); - method public final void removeSession(@NonNull android.media.MediaSession2); - field public static final String SERVICE_INTERFACE = "android.media.MediaSession2Service"; - } - - public static class MediaSession2Service.MediaNotification { - ctor public MediaSession2Service.MediaNotification(int, @NonNull android.app.Notification); - method @NonNull public android.app.Notification getNotification(); - method public int getNotificationId(); - } - - public final class Session2Command implements android.os.Parcelable { - ctor public Session2Command(int); - ctor public Session2Command(@NonNull String, @Nullable android.os.Bundle); - method public int describeContents(); - method public int getCommandCode(); - method @Nullable public String getCustomAction(); - method @Nullable public android.os.Bundle getCustomExtras(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field public static final int COMMAND_CODE_CUSTOM = 0; // 0x0 - field @NonNull public static final android.os.Parcelable.Creator<android.media.Session2Command> CREATOR; - } - - public static final class Session2Command.Result { - ctor public Session2Command.Result(int, @Nullable android.os.Bundle); - method public int getResultCode(); - method @Nullable public android.os.Bundle getResultData(); - field public static final int RESULT_ERROR_UNKNOWN_ERROR = -1; // 0xffffffff - field public static final int RESULT_INFO_SKIPPED = 1; // 0x1 - field public static final int RESULT_SUCCESS = 0; // 0x0 - } - - public final class Session2CommandGroup implements android.os.Parcelable { - method public int describeContents(); - method @NonNull public java.util.Set<android.media.Session2Command> getCommands(); - method public boolean hasCommand(@NonNull android.media.Session2Command); - method public boolean hasCommand(int); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.media.Session2CommandGroup> CREATOR; - } - - public static final class Session2CommandGroup.Builder { - ctor public Session2CommandGroup.Builder(); - ctor public Session2CommandGroup.Builder(@NonNull android.media.Session2CommandGroup); - method @NonNull public android.media.Session2CommandGroup.Builder addCommand(@NonNull android.media.Session2Command); - method @NonNull public android.media.Session2CommandGroup build(); - method @NonNull public android.media.Session2CommandGroup.Builder removeCommand(@NonNull android.media.Session2Command); - } - - public final class Session2Token implements android.os.Parcelable { - ctor public Session2Token(@NonNull android.content.Context, @NonNull android.content.ComponentName); - method public int describeContents(); - method @NonNull public android.os.Bundle getExtras(); - method @NonNull public String getPackageName(); - method @Nullable public String getServiceName(); - method public int getType(); - method public int getUid(); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.media.Session2Token> CREATOR; - field public static final int TYPE_SESSION = 0; // 0x0 - field public static final int TYPE_SESSION_SERVICE = 1; // 0x1 - } - -} - diff --git a/apex/media/framework/api/module-lib-current.txt b/apex/media/framework/api/module-lib-current.txt deleted file mode 100644 index eb6397a1826b..000000000000 --- a/apex/media/framework/api/module-lib-current.txt +++ /dev/null @@ -1,30 +0,0 @@ -// Signature format: 2.0 -package android.media { - - public class MediaCommunicationManager { - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void registerSessionCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaCommunicationManager.SessionCallback); - method public void unregisterSessionCallback(@NonNull android.media.MediaCommunicationManager.SessionCallback); - } - - public static interface MediaCommunicationManager.SessionCallback { - method public default void onSession2TokenCreated(@NonNull android.media.Session2Token); - method public default void onSession2TokensChanged(@NonNull java.util.List<android.media.Session2Token>); - } - - public class MediaFrameworkInitializer { - method public static void registerServiceWrappers(); - method public static void setMediaServiceManager(@NonNull android.media.MediaServiceManager); - } - - @Deprecated public final class MediaParceledListSlice<T extends android.os.Parcelable> implements android.os.Parcelable { - ctor @Deprecated public MediaParceledListSlice(@NonNull java.util.List<T>); - method @Deprecated public int describeContents(); - method @Deprecated @NonNull public static <T extends android.os.Parcelable> android.media.MediaParceledListSlice<T> emptyList(); - method @Deprecated public java.util.List<T> getList(); - method @Deprecated public void setInlineCountLimit(int); - method @Deprecated public void writeToParcel(android.os.Parcel, int); - field @Deprecated @NonNull public static final android.os.Parcelable.ClassLoaderCreator<android.media.MediaParceledListSlice> CREATOR; - } - -} - diff --git a/apex/media/framework/api/module-lib-removed.txt b/apex/media/framework/api/module-lib-removed.txt deleted file mode 100644 index d802177e249b..000000000000 --- a/apex/media/framework/api/module-lib-removed.txt +++ /dev/null @@ -1 +0,0 @@ -// Signature format: 2.0 diff --git a/apex/media/framework/api/system-current.txt b/apex/media/framework/api/system-current.txt deleted file mode 100644 index 6eea769d9f57..000000000000 --- a/apex/media/framework/api/system-current.txt +++ /dev/null @@ -1,68 +0,0 @@ -// Signature format: 2.0 -package android.media { - - public final class MediaTranscodingManager { - method @Nullable public android.media.MediaTranscodingManager.TranscodingSession enqueueRequest(@NonNull android.media.MediaTranscodingManager.TranscodingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaTranscodingManager.OnTranscodingFinishedListener); - } - - @java.lang.FunctionalInterface public static interface MediaTranscodingManager.OnTranscodingFinishedListener { - method public void onTranscodingFinished(@NonNull android.media.MediaTranscodingManager.TranscodingSession); - } - - public abstract static class MediaTranscodingManager.TranscodingRequest { - method public int getClientPid(); - method public int getClientUid(); - method @Nullable public android.os.ParcelFileDescriptor getDestinationFileDescriptor(); - method @NonNull public android.net.Uri getDestinationUri(); - method @Nullable public android.os.ParcelFileDescriptor getSourceFileDescriptor(); - method @NonNull public android.net.Uri getSourceUri(); - } - - public static class MediaTranscodingManager.TranscodingRequest.VideoFormatResolver { - ctor public MediaTranscodingManager.TranscodingRequest.VideoFormatResolver(@NonNull android.media.ApplicationMediaCapabilities, @NonNull android.media.MediaFormat); - method @Nullable public android.media.MediaFormat resolveVideoFormat(); - method public boolean shouldTranscode(); - } - - public static final class MediaTranscodingManager.TranscodingSession { - method public boolean addClientUid(int); - method public void cancel(); - method @NonNull public java.util.List<java.lang.Integer> getClientUids(); - method public int getErrorCode(); - method @IntRange(from=0, to=100) public int getProgress(); - method public int getResult(); - method public int getSessionId(); - method public int getStatus(); - method public void setOnProgressUpdateListener(@NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodingManager.TranscodingSession.OnProgressUpdateListener); - field public static final int ERROR_DROPPED_BY_SERVICE = 1; // 0x1 - field public static final int ERROR_NONE = 0; // 0x0 - field public static final int ERROR_SERVICE_DIED = 2; // 0x2 - field public static final int RESULT_CANCELED = 4; // 0x4 - field public static final int RESULT_ERROR = 3; // 0x3 - field public static final int RESULT_NONE = 1; // 0x1 - field public static final int RESULT_SUCCESS = 2; // 0x2 - field public static final int STATUS_FINISHED = 3; // 0x3 - field public static final int STATUS_PAUSED = 4; // 0x4 - field public static final int STATUS_PENDING = 1; // 0x1 - field public static final int STATUS_RUNNING = 2; // 0x2 - } - - @java.lang.FunctionalInterface public static interface MediaTranscodingManager.TranscodingSession.OnProgressUpdateListener { - method public void onProgressUpdate(@NonNull android.media.MediaTranscodingManager.TranscodingSession, @IntRange(from=0, to=100) int); - } - - public static final class MediaTranscodingManager.VideoTranscodingRequest extends android.media.MediaTranscodingManager.TranscodingRequest { - method @NonNull public android.media.MediaFormat getVideoTrackFormat(); - } - - public static final class MediaTranscodingManager.VideoTranscodingRequest.Builder { - ctor public MediaTranscodingManager.VideoTranscodingRequest.Builder(@NonNull android.net.Uri, @NonNull android.net.Uri, @NonNull android.media.MediaFormat); - method @NonNull public android.media.MediaTranscodingManager.VideoTranscodingRequest build(); - method @NonNull public android.media.MediaTranscodingManager.VideoTranscodingRequest.Builder setClientPid(int); - method @NonNull public android.media.MediaTranscodingManager.VideoTranscodingRequest.Builder setClientUid(int); - method @NonNull public android.media.MediaTranscodingManager.VideoTranscodingRequest.Builder setDestinationFileDescriptor(@NonNull android.os.ParcelFileDescriptor); - method @NonNull public android.media.MediaTranscodingManager.VideoTranscodingRequest.Builder setSourceFileDescriptor(@NonNull android.os.ParcelFileDescriptor); - } - -} - diff --git a/apex/media/framework/api/system-removed.txt b/apex/media/framework/api/system-removed.txt deleted file mode 100644 index d802177e249b..000000000000 --- a/apex/media/framework/api/system-removed.txt +++ /dev/null @@ -1 +0,0 @@ -// Signature format: 2.0 diff --git a/apex/media/framework/jarjar_rules.txt b/apex/media/framework/jarjar_rules.txt deleted file mode 100644 index 91489dcee0a1..000000000000 --- a/apex/media/framework/jarjar_rules.txt +++ /dev/null @@ -1,2 +0,0 @@ -rule com.android.modules.** android.media.internal.@1 -rule com.google.android.exoplayer2.** android.media.internal.exo.@1 diff --git a/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java b/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java deleted file mode 100644 index 97fa0eca0862..000000000000 --- a/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java +++ /dev/null @@ -1,626 +0,0 @@ -/* - * Copyright (C) 2020 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 android.media; - -import android.annotation.NonNull; -import android.content.ContentResolver; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.os.Parcel; -import android.os.Parcelable; -import android.util.Log; - -import com.android.modules.annotation.MinSdk; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - ApplicationMediaCapabilities is an immutable class that encapsulates an application's capabilities - for handling newer video codec format and media features. - - <p> - Android 12 introduces Compatible media transcoding feature. See - <a href="https://developer.android.com/about/versions/12/features#compatible_media_transcoding"> - Compatible media transcoding</a>. By default, Android assumes apps can support playback of all - media formats. Apps that would like to request that media be transcoded into a more compatible - format should declare their media capabilities in a media_capabilities.xml resource file and add it - as a property tag in the AndroidManifest.xml file. Here is a example: - <pre> - {@code - <media-capabilities xmlns:android="http://schemas.android.com/apk/res/android"> - <format android:name="HEVC" supported="true"/> - <format android:name="HDR10" supported="false"/> - <format android:name="HDR10Plus" supported="false"/> - </media-capabilities> - } - </pre> - The ApplicationMediaCapabilities class is generated from this xml and used by the platform to - represent an application's media capabilities in order to determine whether modern media files need - to be transcoded for that application. - </p> - - <p> - ApplicationMediaCapabilities objects can also be built by applications at runtime for use with - {@link ContentResolver#openTypedAssetFileDescriptor(Uri, String, Bundle)} to provide more - control over the transcoding that is built into the platform. ApplicationMediaCapabilities - provided by applications at runtime like this override the default manifest capabilities for that - media access.The object could be build either through {@link #createFromXml(XmlPullParser)} or - through the builder class {@link ApplicationMediaCapabilities.Builder} - - <h3> Video Codec Support</h3> - <p> - Newer video codes include HEVC, VP9 and AV1. Application only needs to indicate their support - for newer format with this class as they are assumed to support older format like h.264. - - <h3>Capability of handling HDR(high dynamic range) video</h3> - <p> - There are four types of HDR video(Dolby-Vision, HDR10, HDR10+, HLG) supported by the platform, - application will only need to specify individual types they supported. - */ -@MinSdk(Build.VERSION_CODES.S) -public final class ApplicationMediaCapabilities implements Parcelable { - private static final String TAG = "ApplicationMediaCapabilities"; - - /** List of supported video codec mime types. */ - private Set<String> mSupportedVideoMimeTypes = new HashSet<>(); - - /** List of unsupported video codec mime types. */ - private Set<String> mUnsupportedVideoMimeTypes = new HashSet<>(); - - /** List of supported hdr types. */ - private Set<String> mSupportedHdrTypes = new HashSet<>(); - - /** List of unsupported hdr types. */ - private Set<String> mUnsupportedHdrTypes = new HashSet<>(); - - private boolean mIsSlowMotionSupported = false; - - private ApplicationMediaCapabilities(Builder b) { - mSupportedVideoMimeTypes.addAll(b.getSupportedVideoMimeTypes()); - mUnsupportedVideoMimeTypes.addAll(b.getUnsupportedVideoMimeTypes()); - mSupportedHdrTypes.addAll(b.getSupportedHdrTypes()); - mUnsupportedHdrTypes.addAll(b.getUnsupportedHdrTypes()); - mIsSlowMotionSupported = b.mIsSlowMotionSupported; - } - - /** - * Query if a video codec format is supported by the application. - * <p> - * If the application has not specified supporting the format or not, this will return false. - * Use {@link #isFormatSpecified(String)} to query if a format is specified or not. - * - * @param videoMime The mime type of the video codec format. Must be the one used in - * {@link MediaFormat#KEY_MIME}. - * @return true if application supports the video codec format, false otherwise. - */ - public boolean isVideoMimeTypeSupported( - @NonNull String videoMime) { - if (mSupportedVideoMimeTypes.contains(videoMime.toLowerCase())) { - return true; - } - return false; - } - - /** - * Query if a HDR type is supported by the application. - * <p> - * If the application has not specified supporting the format or not, this will return false. - * Use {@link #isFormatSpecified(String)} to query if a format is specified or not. - * - * @param hdrType The type of the HDR format. - * @return true if application supports the HDR format, false otherwise. - */ - public boolean isHdrTypeSupported( - @NonNull @MediaFeature.MediaHdrType String hdrType) { - if (mSupportedHdrTypes.contains(hdrType)) { - return true; - } - return false; - } - - /** - * Query if a format is specified by the application. - * <p> - * The format could be either the video format or the hdr format. - * - * @param format The name of the format. - * @return true if application specifies the format, false otherwise. - */ - public boolean isFormatSpecified(@NonNull String format) { - if (mSupportedVideoMimeTypes.contains(format) || mUnsupportedVideoMimeTypes.contains(format) - || mSupportedHdrTypes.contains(format) || mUnsupportedHdrTypes.contains(format)) { - return true; - - } - return false; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - // Write out the supported video mime types. - dest.writeInt(mSupportedVideoMimeTypes.size()); - for (String cap : mSupportedVideoMimeTypes) { - dest.writeString(cap); - } - // Write out the unsupported video mime types. - dest.writeInt(mUnsupportedVideoMimeTypes.size()); - for (String cap : mUnsupportedVideoMimeTypes) { - dest.writeString(cap); - } - // Write out the supported hdr types. - dest.writeInt(mSupportedHdrTypes.size()); - for (String cap : mSupportedHdrTypes) { - dest.writeString(cap); - } - // Write out the unsupported hdr types. - dest.writeInt(mUnsupportedHdrTypes.size()); - for (String cap : mUnsupportedHdrTypes) { - dest.writeString(cap); - } - // Write out the supported slow motion. - dest.writeBoolean(mIsSlowMotionSupported); - } - - @Override - public String toString() { - String caps = new String( - "Supported Video MimeTypes: " + mSupportedVideoMimeTypes.toString()); - caps += "Unsupported Video MimeTypes: " + mUnsupportedVideoMimeTypes.toString(); - caps += "Supported HDR types: " + mSupportedHdrTypes.toString(); - caps += "Unsupported HDR types: " + mUnsupportedHdrTypes.toString(); - caps += "Supported slow motion: " + mIsSlowMotionSupported; - return caps; - } - - @NonNull - public static final Creator<ApplicationMediaCapabilities> CREATOR = - new Creator<ApplicationMediaCapabilities>() { - public ApplicationMediaCapabilities createFromParcel(Parcel in) { - ApplicationMediaCapabilities.Builder builder = - new ApplicationMediaCapabilities.Builder(); - - // Parse supported video codec mime types. - int count = in.readInt(); - for (int readCount = 0; readCount < count; ++readCount) { - builder.addSupportedVideoMimeType(in.readString()); - } - - // Parse unsupported video codec mime types. - count = in.readInt(); - for (int readCount = 0; readCount < count; ++readCount) { - builder.addUnsupportedVideoMimeType(in.readString()); - } - - // Parse supported hdr types. - count = in.readInt(); - for (int readCount = 0; readCount < count; ++readCount) { - builder.addSupportedHdrType(in.readString()); - } - - // Parse unsupported hdr types. - count = in.readInt(); - for (int readCount = 0; readCount < count; ++readCount) { - builder.addUnsupportedHdrType(in.readString()); - } - - boolean supported = in.readBoolean(); - builder.setSlowMotionSupported(supported); - - return builder.build(); - } - - public ApplicationMediaCapabilities[] newArray(int size) { - return new ApplicationMediaCapabilities[size]; - } - }; - - /** - * Query the video codec mime types supported by the application. - * @return List of supported video codec mime types. The list will be empty if there are none. - */ - @NonNull - public List<String> getSupportedVideoMimeTypes() { - return new ArrayList<>(mSupportedVideoMimeTypes); - } - - /** - * Query the video codec mime types that are not supported by the application. - * @return List of unsupported video codec mime types. The list will be empty if there are none. - */ - @NonNull - public List<String> getUnsupportedVideoMimeTypes() { - return new ArrayList<>(mUnsupportedVideoMimeTypes); - } - - /** - * Query all hdr types that are supported by the application. - * @return List of supported hdr types. The list will be empty if there are none. - */ - @NonNull - public List<String> getSupportedHdrTypes() { - return new ArrayList<>(mSupportedHdrTypes); - } - - /** - * Query all hdr types that are not supported by the application. - * @return List of unsupported hdr types. The list will be empty if there are none. - */ - @NonNull - public List<String> getUnsupportedHdrTypes() { - return new ArrayList<>(mUnsupportedHdrTypes); - } - - /** - * Whether handling of slow-motion video is supported - * @hide - */ - public boolean isSlowMotionSupported() { - return mIsSlowMotionSupported; - } - - /** - * Creates {@link ApplicationMediaCapabilities} from an xml. - * - * The xml's syntax is the same as the media_capabilities.xml used by the AndroidManifest.xml. - * <p> Here is an example: - * - * <pre> - * {@code - * <media-capabilities xmlns:android="http://schemas.android.com/apk/res/android"> - * <format android:name="HEVC" supported="true"/> - * <format android:name="HDR10" supported="false"/> - * <format android:name="HDR10Plus" supported="false"/> - * </media-capabilities> - * } - * </pre> - * <p> - * - * @param xmlParser The underlying {@link XmlPullParser} that will read the xml. - * @return An ApplicationMediaCapabilities object. - * @throws UnsupportedOperationException if the capabilities in xml config are invalid or - * incompatible. - */ - // TODO: Add developer.android.com link for the format of the xml. - @NonNull - public static ApplicationMediaCapabilities createFromXml(@NonNull XmlPullParser xmlParser) { - ApplicationMediaCapabilities.Builder builder = new ApplicationMediaCapabilities.Builder(); - builder.parseXml(xmlParser); - return builder.build(); - } - - /** - * Builder class for {@link ApplicationMediaCapabilities} objects. - * Use this class to configure and create an ApplicationMediaCapabilities instance. Builder - * could be created from an existing ApplicationMediaCapabilities object, from a xml file or - * MediaCodecList. - * //TODO(hkuang): Add xml parsing support to the builder. - */ - public final static class Builder { - /** List of supported video codec mime types. */ - private Set<String> mSupportedVideoMimeTypes = new HashSet<>(); - - /** List of supported hdr types. */ - private Set<String> mSupportedHdrTypes = new HashSet<>(); - - /** List of unsupported video codec mime types. */ - private Set<String> mUnsupportedVideoMimeTypes = new HashSet<>(); - - /** List of unsupported hdr types. */ - private Set<String> mUnsupportedHdrTypes = new HashSet<>(); - - private boolean mIsSlowMotionSupported = false; - - /* Map to save the format read from the xml. */ - private Map<String, Boolean> mFormatSupportedMap = new HashMap<String, Boolean>(); - - /** - * Constructs a new Builder with all the supports default to false. - */ - public Builder() { - } - - private void parseXml(@NonNull XmlPullParser xmlParser) - throws UnsupportedOperationException { - if (xmlParser == null) { - throw new IllegalArgumentException("XmlParser must not be null"); - } - - try { - while (xmlParser.next() != XmlPullParser.START_TAG) { - continue; - } - - // Validates the tag is "media-capabilities". - if (!xmlParser.getName().equals("media-capabilities")) { - throw new UnsupportedOperationException("Invalid tag"); - } - - xmlParser.next(); - while (xmlParser.getEventType() != XmlPullParser.END_TAG) { - while (xmlParser.getEventType() != XmlPullParser.START_TAG) { - if (xmlParser.getEventType() == XmlPullParser.END_DOCUMENT) { - return; - } - xmlParser.next(); - } - - // Validates the tag is "format". - if (xmlParser.getName().equals("format")) { - parseFormatTag(xmlParser); - } else { - throw new UnsupportedOperationException("Invalid tag"); - } - while (xmlParser.getEventType() != XmlPullParser.END_TAG) { - xmlParser.next(); - } - xmlParser.next(); - } - } catch (XmlPullParserException xppe) { - throw new UnsupportedOperationException("Ill-formatted xml file"); - } catch (java.io.IOException ioe) { - throw new UnsupportedOperationException("Unable to read xml file"); - } - } - - private void parseFormatTag(XmlPullParser xmlParser) { - String name = null; - String supported = null; - for (int i = 0; i < xmlParser.getAttributeCount(); i++) { - String attrName = xmlParser.getAttributeName(i); - if (attrName.equals("name")) { - name = xmlParser.getAttributeValue(i); - } else if (attrName.equals("supported")) { - supported = xmlParser.getAttributeValue(i); - } else { - throw new UnsupportedOperationException("Invalid attribute name " + attrName); - } - } - - if (name != null && supported != null) { - if (!supported.equals("true") && !supported.equals("false")) { - throw new UnsupportedOperationException( - ("Supported value must be either true or false")); - } - boolean isSupported = Boolean.parseBoolean(supported); - - // Check if the format is already found before. - if (mFormatSupportedMap.get(name) != null && mFormatSupportedMap.get(name) - != isSupported) { - throw new UnsupportedOperationException( - "Format: " + name + " has conflict supported value"); - } - - switch (name) { - case "HEVC": - if (isSupported) { - mSupportedVideoMimeTypes.add(MediaFormat.MIMETYPE_VIDEO_HEVC); - } else { - mUnsupportedVideoMimeTypes.add(MediaFormat.MIMETYPE_VIDEO_HEVC); - } - break; - case "VP9": - if (isSupported) { - mSupportedVideoMimeTypes.add(MediaFormat.MIMETYPE_VIDEO_VP9); - } else { - mUnsupportedVideoMimeTypes.add(MediaFormat.MIMETYPE_VIDEO_VP9); - } - break; - case "AV1": - if (isSupported) { - mSupportedVideoMimeTypes.add(MediaFormat.MIMETYPE_VIDEO_AV1); - } else { - mUnsupportedVideoMimeTypes.add(MediaFormat.MIMETYPE_VIDEO_AV1); - } - break; - case "HDR10": - if (isSupported) { - mSupportedHdrTypes.add(MediaFeature.HdrType.HDR10); - } else { - mUnsupportedHdrTypes.add(MediaFeature.HdrType.HDR10); - } - break; - case "HDR10Plus": - if (isSupported) { - mSupportedHdrTypes.add(MediaFeature.HdrType.HDR10_PLUS); - } else { - mUnsupportedHdrTypes.add(MediaFeature.HdrType.HDR10_PLUS); - } - break; - case "Dolby-Vision": - if (isSupported) { - mSupportedHdrTypes.add(MediaFeature.HdrType.DOLBY_VISION); - } else { - mUnsupportedHdrTypes.add(MediaFeature.HdrType.DOLBY_VISION); - } - break; - case "HLG": - if (isSupported) { - mSupportedHdrTypes.add(MediaFeature.HdrType.HLG); - } else { - mUnsupportedHdrTypes.add(MediaFeature.HdrType.HLG); - } - break; - case "SlowMotion": - mIsSlowMotionSupported = isSupported; - break; - default: - Log.w(TAG, "Invalid format name " + name); - } - // Save the name and isSupported into the map for validate later. - mFormatSupportedMap.put(name, isSupported); - } else { - throw new UnsupportedOperationException( - "Format name and supported must both be specified"); - } - } - - /** - * Builds a {@link ApplicationMediaCapabilities} object. - * - * @return a new {@link ApplicationMediaCapabilities} instance successfully initialized - * with all the parameters set on this <code>Builder</code>. - * @throws UnsupportedOperationException if the parameters set on the - * <code>Builder</code> were incompatible, or if they - * are not supported by the - * device. - */ - @NonNull - public ApplicationMediaCapabilities build() { - Log.d(TAG, - "Building ApplicationMediaCapabilities with: (Supported HDR: " - + mSupportedHdrTypes.toString() + " Unsupported HDR: " - + mUnsupportedHdrTypes.toString() + ") (Supported Codec: " - + " " + mSupportedVideoMimeTypes.toString() + " Unsupported Codec:" - + mUnsupportedVideoMimeTypes.toString() + ") " - + mIsSlowMotionSupported); - - // If hdr is supported, application must also support hevc. - if (!mSupportedHdrTypes.isEmpty() && !mSupportedVideoMimeTypes.contains( - MediaFormat.MIMETYPE_VIDEO_HEVC)) { - throw new UnsupportedOperationException("Only support HEVC mime type"); - } - return new ApplicationMediaCapabilities(this); - } - - /** - * Adds a supported video codec mime type. - * - * @param codecMime Supported codec mime types. Must be one of the mime type defined - * in {@link MediaFormat}. - * @throws IllegalArgumentException if mime type is not valid. - */ - @NonNull - public Builder addSupportedVideoMimeType( - @NonNull String codecMime) { - mSupportedVideoMimeTypes.add(codecMime); - return this; - } - - private List<String> getSupportedVideoMimeTypes() { - return new ArrayList<>(mSupportedVideoMimeTypes); - } - - private boolean isValidVideoCodecMimeType(@NonNull String codecMime) { - if (!codecMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC) - && !codecMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9) - && !codecMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AV1)) { - return false; - } - return true; - } - - /** - * Adds an unsupported video codec mime type. - * - * @param codecMime Unsupported codec mime type. Must be one of the mime type defined - * in {@link MediaFormat}. - * @throws IllegalArgumentException if mime type is not valid. - */ - @NonNull - public Builder addUnsupportedVideoMimeType( - @NonNull String codecMime) { - if (!isValidVideoCodecMimeType(codecMime)) { - throw new IllegalArgumentException("Invalid codec mime type: " + codecMime); - } - mUnsupportedVideoMimeTypes.add(codecMime); - return this; - } - - private List<String> getUnsupportedVideoMimeTypes() { - return new ArrayList<>(mUnsupportedVideoMimeTypes); - } - - /** - * Adds a supported hdr type. - * - * @param hdrType Supported hdr type. Must be one of the String defined in - * {@link MediaFeature.HdrType}. - * @throws IllegalArgumentException if hdrType is not valid. - */ - @NonNull - public Builder addSupportedHdrType( - @NonNull @MediaFeature.MediaHdrType String hdrType) { - if (!isValidVideoCodecHdrType(hdrType)) { - throw new IllegalArgumentException("Invalid hdr type: " + hdrType); - } - mSupportedHdrTypes.add(hdrType); - return this; - } - - private List<String> getSupportedHdrTypes() { - return new ArrayList<>(mSupportedHdrTypes); - } - - private boolean isValidVideoCodecHdrType(@NonNull String hdrType) { - if (!hdrType.equals(MediaFeature.HdrType.DOLBY_VISION) - && !hdrType.equals(MediaFeature.HdrType.HDR10) - && !hdrType.equals(MediaFeature.HdrType.HDR10_PLUS) - && !hdrType.equals(MediaFeature.HdrType.HLG)) { - return false; - } - return true; - } - - /** - * Adds an unsupported hdr type. - * - * @param hdrType Unsupported hdr type. Must be one of the String defined in - * {@link MediaFeature.HdrType}. - * @throws IllegalArgumentException if hdrType is not valid. - */ - @NonNull - public Builder addUnsupportedHdrType( - @NonNull @MediaFeature.MediaHdrType String hdrType) { - if (!isValidVideoCodecHdrType(hdrType)) { - throw new IllegalArgumentException("Invalid hdr type: " + hdrType); - } - mUnsupportedHdrTypes.add(hdrType); - return this; - } - - private List<String> getUnsupportedHdrTypes() { - return new ArrayList<>(mUnsupportedHdrTypes); - } - - /** - * Sets whether slow-motion video is supported. - * If an application indicates support for slow-motion, it is application's responsibility - * to parse the slow-motion videos using their own parser or using support library. - * @see android.media.MediaFormat#KEY_SLOW_MOTION_MARKERS - * @hide - */ - @NonNull - public Builder setSlowMotionSupported(boolean slowMotionSupported) { - mIsSlowMotionSupported = slowMotionSupported; - return this; - } - } -} diff --git a/apex/media/framework/java/android/media/BaseMediaParceledListSlice.java b/apex/media/framework/java/android/media/BaseMediaParceledListSlice.java deleted file mode 100644 index fb666098301a..000000000000 --- a/apex/media/framework/java/android/media/BaseMediaParceledListSlice.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright 2020 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 android.media; - -import android.os.Binder; -import android.os.IBinder; -import android.os.Parcel; -import android.os.Parcelable; -import android.os.RemoteException; -import android.util.Log; - -import java.util.ArrayList; -import java.util.List; - -/** - * This is a copied version of BaseParceledListSlice in framework with hidden API usages - * removed. - * - * Transfer a large list of Parcelable objects across an IPC. Splits into - * multiple transactions if needed. - * - * Caveat: for efficiency and security, all elements must be the same concrete type. - * In order to avoid writing the class name of each object, we must ensure that - * each object is the same type, or else unparceling then reparceling the data may yield - * a different result if the class name encoded in the Parcelable is a Base type. - * See b/17671747. - * - * @hide - */ -abstract class BaseMediaParceledListSlice<T> implements Parcelable { - private static String TAG = "BaseMediaParceledListSlice"; - private static boolean DEBUG = false; - - /* - * TODO get this number from somewhere else. For now set it to a quarter of - * the 1MB limit. - */ - // private static final int MAX_IPC_SIZE = IBinder.getSuggestedMaxIpcSizeBytes(); - private static final int MAX_IPC_SIZE = 64 * 1024; - - private final List<T> mList; - - private int mInlineCountLimit = Integer.MAX_VALUE; - - public BaseMediaParceledListSlice(List<T> list) { - mList = list; - } - - @SuppressWarnings("unchecked") - BaseMediaParceledListSlice(Parcel p, ClassLoader loader) { - final int N = p.readInt(); - mList = new ArrayList<T>(N); - if (DEBUG) Log.d(TAG, "Retrieving " + N + " items"); - if (N <= 0) { - return; - } - - Parcelable.Creator<?> creator = readParcelableCreator(p, loader); - Class<?> listElementClass = null; - - int i = 0; - while (i < N) { - if (p.readInt() == 0) { - break; - } - - final T parcelable = readCreator(creator, p, loader); - if (listElementClass == null) { - listElementClass = parcelable.getClass(); - } else { - verifySameType(listElementClass, parcelable.getClass()); - } - - mList.add(parcelable); - - if (DEBUG) Log.d(TAG, "Read inline #" + i + ": " + mList.get(mList.size()-1)); - i++; - } - if (i >= N) { - return; - } - final IBinder retriever = p.readStrongBinder(); - while (i < N) { - if (DEBUG) Log.d(TAG, "Reading more @" + i + " of " + N + ": retriever=" + retriever); - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - data.writeInt(i); - try { - retriever.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0); - } catch (RemoteException e) { - Log.w(TAG, "Failure retrieving array; only received " + i + " of " + N, e); - return; - } - while (i < N && reply.readInt() != 0) { - final T parcelable = readCreator(creator, reply, loader); - verifySameType(listElementClass, parcelable.getClass()); - - mList.add(parcelable); - - if (DEBUG) Log.d(TAG, "Read extra #" + i + ": " + mList.get(mList.size()-1)); - i++; - } - reply.recycle(); - data.recycle(); - } - } - - private T readCreator(Parcelable.Creator<?> creator, Parcel p, ClassLoader loader) { - if (creator instanceof Parcelable.ClassLoaderCreator<?>) { - Parcelable.ClassLoaderCreator<?> classLoaderCreator = - (Parcelable.ClassLoaderCreator<?>) creator; - return (T) classLoaderCreator.createFromParcel(p, loader); - } - return (T) creator.createFromParcel(p); - } - - private static void verifySameType(final Class<?> expected, final Class<?> actual) { - if (!actual.equals(expected)) { - throw new IllegalArgumentException("Can't unparcel type " - + (actual == null ? null : actual.getName()) + " in list of type " - + (expected == null ? null : expected.getName())); - } - } - - public List<T> getList() { - return mList; - } - - /** - * Set a limit on the maximum number of entries in the array that will be included - * inline in the initial parcelling of this object. - */ - public void setInlineCountLimit(int maxCount) { - mInlineCountLimit = maxCount; - } - - /** - * Write this to another Parcel. Note that this discards the internal Parcel - * and should not be used anymore. This is so we can pass this to a Binder - * where we won't have a chance to call recycle on this. - */ - @Override - public void writeToParcel(Parcel dest, int flags) { - final int N = mList.size(); - final int callFlags = flags; - dest.writeInt(N); - if (DEBUG) Log.d(TAG, "Writing " + N + " items"); - if (N > 0) { - final Class<?> listElementClass = mList.get(0).getClass(); - writeParcelableCreator(mList.get(0), dest); - int i = 0; - while (i < N && i < mInlineCountLimit && dest.dataSize() < MAX_IPC_SIZE) { - dest.writeInt(1); - - final T parcelable = mList.get(i); - verifySameType(listElementClass, parcelable.getClass()); - writeElement(parcelable, dest, callFlags); - - if (DEBUG) Log.d(TAG, "Wrote inline #" + i + ": " + mList.get(i)); - i++; - } - if (i < N) { - dest.writeInt(0); - Binder retriever = new Binder() { - @Override - protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) - throws RemoteException { - if (code != FIRST_CALL_TRANSACTION) { - return super.onTransact(code, data, reply, flags); - } - int i = data.readInt(); - if (DEBUG) Log.d(TAG, "Writing more @" + i + " of " + N); - while (i < N && reply.dataSize() < MAX_IPC_SIZE) { - reply.writeInt(1); - - final T parcelable = mList.get(i); - verifySameType(listElementClass, parcelable.getClass()); - writeElement(parcelable, reply, callFlags); - - if (DEBUG) Log.d(TAG, "Wrote extra #" + i + ": " + mList.get(i)); - i++; - } - if (i < N) { - if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N); - reply.writeInt(0); - } - return true; - } - }; - if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N + ": retriever=" + retriever); - dest.writeStrongBinder(retriever); - } - } - } - - abstract void writeElement(T parcelable, Parcel reply, int callFlags); - - abstract void writeParcelableCreator(T parcelable, Parcel dest); - - abstract Parcelable.Creator<?> readParcelableCreator(Parcel from, ClassLoader loader); -} diff --git a/apex/media/framework/java/android/media/BufferingParams.java b/apex/media/framework/java/android/media/BufferingParams.java deleted file mode 100644 index 04af02874bbd..000000000000 --- a/apex/media/framework/java/android/media/BufferingParams.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright 2017 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 android.media; - -import android.os.Parcel; -import android.os.Parcelable; - -/** - * Structure for source buffering management params. - * - * Used by {@link MediaPlayer#getBufferingParams()} and - * {@link MediaPlayer#setBufferingParams(BufferingParams)} - * to control source buffering behavior. - * - * <p>There are two stages of source buffering in {@link MediaPlayer}: initial buffering - * (when {@link MediaPlayer} is being prepared) and rebuffering (when {@link MediaPlayer} - * is playing back source). {@link BufferingParams} includes corresponding marks for each - * stage of source buffering. The marks are time based (in milliseconds). - * - * <p>{@link MediaPlayer} source component has default marks which can be queried by - * calling {@link MediaPlayer#getBufferingParams()} before any change is made by - * {@link MediaPlayer#setBufferingParams()}. - * <ul> - * <li><strong>initial buffering:</strong> initialMarkMs is used when - * {@link MediaPlayer} is being prepared. When cached data amount exceeds this mark - * {@link MediaPlayer} is prepared. </li> - * <li><strong>rebuffering during playback:</strong> resumePlaybackMarkMs is used when - * {@link MediaPlayer} is playing back content. - * <ul> - * <li> {@link MediaPlayer} has internal mark, namely pausePlaybackMarkMs, to decide when - * to pause playback if cached data amount runs low. This internal mark varies based on - * type of data source. </li> - * <li> When cached data amount exceeds resumePlaybackMarkMs, {@link MediaPlayer} will - * resume playback if it has been paused due to low cached data amount. The internal mark - * pausePlaybackMarkMs shall be less than resumePlaybackMarkMs. </li> - * <li> {@link MediaPlayer} has internal mark, namely pauseRebufferingMarkMs, to decide - * when to pause rebuffering. Apparently, this internal mark shall be no less than - * resumePlaybackMarkMs. </li> - * <li> {@link MediaPlayer} has internal mark, namely resumeRebufferingMarkMs, to decide - * when to resume buffering. This internal mark varies based on type of data source. This - * mark shall be larger than pausePlaybackMarkMs, and less than pauseRebufferingMarkMs. - * </li> - * </ul> </li> - * </ul> - * <p>Users should use {@link Builder} to change {@link BufferingParams}. - * @hide - */ -public final class BufferingParams implements Parcelable { - private static final int BUFFERING_NO_MARK = -1; - - // params - private int mInitialMarkMs = BUFFERING_NO_MARK; - - private int mResumePlaybackMarkMs = BUFFERING_NO_MARK; - - private BufferingParams() { - } - - /** - * Return initial buffering mark in milliseconds. - * @return initial buffering mark in milliseconds - */ - public int getInitialMarkMs() { - return mInitialMarkMs; - } - - /** - * Return the mark in milliseconds for resuming playback. - * @return the mark for resuming playback in milliseconds - */ - public int getResumePlaybackMarkMs() { - return mResumePlaybackMarkMs; - } - - /** - * Builder class for {@link BufferingParams} objects. - * <p> Here is an example where <code>Builder</code> is used to define the - * {@link BufferingParams} to be used by a {@link MediaPlayer} instance: - * - * <pre class="prettyprint"> - * BufferingParams myParams = mediaplayer.getDefaultBufferingParams(); - * myParams = new BufferingParams.Builder(myParams) - * .setInitialMarkMs(10000) - * .setResumePlaybackMarkMs(15000) - * .build(); - * mediaplayer.setBufferingParams(myParams); - * </pre> - */ - public static class Builder { - private int mInitialMarkMs = BUFFERING_NO_MARK; - private int mResumePlaybackMarkMs = BUFFERING_NO_MARK; - - /** - * Constructs a new Builder with the defaults. - * By default, all marks are -1. - */ - public Builder() { - } - - /** - * Constructs a new Builder from a given {@link BufferingParams} instance - * @param bp the {@link BufferingParams} object whose data will be reused - * in the new Builder. - */ - public Builder(BufferingParams bp) { - mInitialMarkMs = bp.mInitialMarkMs; - mResumePlaybackMarkMs = bp.mResumePlaybackMarkMs; - } - - /** - * Combines all of the fields that have been set and return a new - * {@link BufferingParams} object. <code>IllegalStateException</code> will be - * thrown if there is conflict between fields. - * @return a new {@link BufferingParams} object - */ - public BufferingParams build() { - BufferingParams bp = new BufferingParams(); - bp.mInitialMarkMs = mInitialMarkMs; - bp.mResumePlaybackMarkMs = mResumePlaybackMarkMs; - - return bp; - } - - /** - * Sets the time based mark in milliseconds for initial buffering. - * @param markMs time based mark in milliseconds - * @return the same Builder instance. - */ - public Builder setInitialMarkMs(int markMs) { - mInitialMarkMs = markMs; - return this; - } - - /** - * Sets the time based mark in milliseconds for resuming playback. - * @param markMs time based mark in milliseconds for resuming playback - * @return the same Builder instance. - */ - public Builder setResumePlaybackMarkMs(int markMs) { - mResumePlaybackMarkMs = markMs; - return this; - } - } - - private BufferingParams(Parcel in) { - mInitialMarkMs = in.readInt(); - mResumePlaybackMarkMs = in.readInt(); - } - - public static final @android.annotation.NonNull Parcelable.Creator<BufferingParams> CREATOR = - new Parcelable.Creator<BufferingParams>() { - @Override - public BufferingParams createFromParcel(Parcel in) { - return new BufferingParams(in); - } - - @Override - public BufferingParams[] newArray(int size) { - return new BufferingParams[size]; - } - }; - - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mInitialMarkMs); - dest.writeInt(mResumePlaybackMarkMs); - } -} diff --git a/apex/media/framework/java/android/media/Controller2Link.java b/apex/media/framework/java/android/media/Controller2Link.java deleted file mode 100644 index 8eefec73194c..000000000000 --- a/apex/media/framework/java/android/media/Controller2Link.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright 2018 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 android.media; - -import android.os.Binder; -import android.os.Bundle; -import android.os.Parcel; -import android.os.Parcelable; -import android.os.RemoteException; -import android.os.ResultReceiver; - -import java.util.Objects; - -/** - * Handles incoming commands from {@link MediaSession2} to {@link MediaController2}. - * @hide - */ -// @SystemApi -public final class Controller2Link implements Parcelable { - private static final String TAG = "Controller2Link"; - private static final boolean DEBUG = MediaController2.DEBUG; - - public static final @android.annotation.NonNull Parcelable.Creator<Controller2Link> CREATOR = - new Parcelable.Creator<Controller2Link>() { - @Override - public Controller2Link createFromParcel(Parcel in) { - return new Controller2Link(in); - } - - @Override - public Controller2Link[] newArray(int size) { - return new Controller2Link[size]; - } - }; - - - private final MediaController2 mController; - private final IMediaController2 mIController; - - public Controller2Link(MediaController2 controller) { - mController = controller; - mIController = new Controller2Stub(); - } - - Controller2Link(Parcel in) { - mController = null; - mIController = IMediaController2.Stub.asInterface(in.readStrongBinder()); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeStrongBinder(mIController.asBinder()); - } - - @Override - public int hashCode() { - return mIController.asBinder().hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof Controller2Link)) { - return false; - } - Controller2Link other = (Controller2Link) obj; - return Objects.equals(mIController.asBinder(), other.mIController.asBinder()); - } - - /** Interface method for IMediaController2.notifyConnected */ - public void notifyConnected(int seq, Bundle connectionResult) { - try { - mIController.notifyConnected(seq, connectionResult); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** Interface method for IMediaController2.notifyDisonnected */ - public void notifyDisconnected(int seq) { - try { - mIController.notifyDisconnected(seq); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** Interface method for IMediaController2.notifyPlaybackActiveChanged */ - public void notifyPlaybackActiveChanged(int seq, boolean playbackActive) { - try { - mIController.notifyPlaybackActiveChanged(seq, playbackActive); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** Interface method for IMediaController2.sendSessionCommand */ - public void sendSessionCommand(int seq, Session2Command command, Bundle args, - ResultReceiver resultReceiver) { - try { - mIController.sendSessionCommand(seq, command, args, resultReceiver); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** Interface method for IMediaController2.cancelSessionCommand */ - public void cancelSessionCommand(int seq) { - try { - mIController.cancelSessionCommand(seq); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** Stub implementation for IMediaController2.notifyConnected */ - public void onConnected(int seq, Bundle connectionResult) { - if (connectionResult == null) { - onDisconnected(seq); - return; - } - mController.onConnected(seq, connectionResult); - } - - /** Stub implementation for IMediaController2.notifyDisonnected */ - public void onDisconnected(int seq) { - mController.onDisconnected(seq); - } - - /** Stub implementation for IMediaController2.notifyPlaybackActiveChanged */ - public void onPlaybackActiveChanged(int seq, boolean playbackActive) { - mController.onPlaybackActiveChanged(seq, playbackActive); - } - - /** Stub implementation for IMediaController2.sendSessionCommand */ - public void onSessionCommand(int seq, Session2Command command, Bundle args, - ResultReceiver resultReceiver) { - mController.onSessionCommand(seq, command, args, resultReceiver); - } - - /** Stub implementation for IMediaController2.cancelSessionCommand */ - public void onCancelCommand(int seq) { - mController.onCancelCommand(seq); - } - - private class Controller2Stub extends IMediaController2.Stub { - @Override - public void notifyConnected(int seq, Bundle connectionResult) { - final long token = Binder.clearCallingIdentity(); - try { - Controller2Link.this.onConnected(seq, connectionResult); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public void notifyDisconnected(int seq) { - final long token = Binder.clearCallingIdentity(); - try { - Controller2Link.this.onDisconnected(seq); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public void notifyPlaybackActiveChanged(int seq, boolean playbackActive) { - final long token = Binder.clearCallingIdentity(); - try { - Controller2Link.this.onPlaybackActiveChanged(seq, playbackActive); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public void sendSessionCommand(int seq, Session2Command command, Bundle args, - ResultReceiver resultReceiver) { - final long token = Binder.clearCallingIdentity(); - try { - Controller2Link.this.onSessionCommand(seq, command, args, resultReceiver); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public void cancelSessionCommand(int seq) { - final long token = Binder.clearCallingIdentity(); - try { - Controller2Link.this.onCancelCommand(seq); - } finally { - Binder.restoreCallingIdentity(token); - } - } - } -} diff --git a/apex/media/framework/java/android/media/DataSourceCallback.java b/apex/media/framework/java/android/media/DataSourceCallback.java deleted file mode 100644 index c297ecda249c..000000000000 --- a/apex/media/framework/java/android/media/DataSourceCallback.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2017 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 android.media; - -import android.annotation.NonNull; - -import java.io.Closeable; -import java.io.IOException; - -/** - * For supplying media data to the framework. Implement this if your app has - * special requirements for the way media data is obtained. - * - * <p class="note">Methods of this interface may be called on multiple different - * threads. There will be a thread synchronization point between each call to ensure that - * modifications to the state of your DataSourceCallback are visible to future calls. This means - * you don't need to do your own synchronization unless you're modifying the - * DataSourceCallback from another thread while it's being used by the framework.</p> - * - * @hide - */ -public abstract class DataSourceCallback implements Closeable { - - public static final int END_OF_STREAM = -1; - - /** - * Called to request data from the given position. - * - * Implementations should should write up to {@code size} bytes into - * {@code buffer}, and return the number of bytes written. - * - * Return {@code 0} if size is zero (thus no bytes are read). - * - * Return {@code -1} to indicate that end of stream is reached. - * - * @param position the position in the data source to read from. - * @param buffer the buffer to read the data into. - * @param offset the offset within buffer to read the data into. - * @param size the number of bytes to read. - * @throws IOException on fatal errors. - * @return the number of bytes read, or {@link #END_OF_STREAM} if end of stream is reached. - */ - public abstract int readAt(long position, @NonNull byte[] buffer, int offset, int size) - throws IOException; - - /** - * Called to get the size of the data source. - * - * @throws IOException on fatal errors - * @return the size of data source in bytes, or -1 if the size is unknown. - */ - public abstract long getSize() throws IOException; -} diff --git a/apex/media/framework/java/android/media/MediaCommunicationManager.java b/apex/media/framework/java/android/media/MediaCommunicationManager.java deleted file mode 100644 index f39bcfb267bf..000000000000 --- a/apex/media/framework/java/android/media/MediaCommunicationManager.java +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright 2020 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 android.media; - -import static android.Manifest.permission.MEDIA_CONTENT_CONTROL; -import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; - -import android.annotation.CallbackExecutor; -import android.annotation.IntRange; -import android.annotation.NonNull; -import android.annotation.RequiresPermission; -import android.annotation.SystemApi; -import android.annotation.SystemService; -import android.content.Context; -import android.media.session.MediaSession; -import android.media.session.MediaSessionManager; -import android.os.Build; -import android.os.RemoteException; -import android.os.UserHandle; -import android.service.media.MediaBrowserService; -import android.util.Log; - -import com.android.internal.annotations.GuardedBy; -import com.android.modules.annotation.MinSdk; -import com.android.modules.utils.build.SdkLevel; - -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.Executor; - -/** - * Provides support for interacting with {@link android.media.MediaSession2 MediaSession2s} - * that applications have published to express their ongoing media playback state. - */ -@MinSdk(Build.VERSION_CODES.S) -@SystemService(Context.MEDIA_COMMUNICATION_SERVICE) -public class MediaCommunicationManager { - private static final String TAG = "MediaCommunicationManager"; - - /** - * The manager version used from beginning. - */ - private static final int VERSION_1 = 1; - - /** - * Current manager version. - */ - private static final int CURRENT_VERSION = VERSION_1; - - private final Context mContext; - private final IMediaCommunicationService mService; - - private final Object mLock = new Object(); - private final CopyOnWriteArrayList<SessionCallbackRecord> mTokenCallbackRecords = - new CopyOnWriteArrayList<>(); - - @GuardedBy("mLock") - private MediaCommunicationServiceCallbackStub mCallbackStub; - - /** - * @hide - */ - public MediaCommunicationManager(@NonNull Context context) { - if (!SdkLevel.isAtLeastS()) { - throw new UnsupportedOperationException("Android version must be S or greater."); - } - mContext = context; - mService = IMediaCommunicationService.Stub.asInterface( - MediaFrameworkInitializer.getMediaServiceManager() - .getMediaCommunicationServiceRegisterer() - .get()); - } - - /** - * Gets the version of this {@link MediaCommunicationManager}. - */ - public @IntRange(from = 1) int getVersion() { - return CURRENT_VERSION; - } - - /** - * Notifies that a new {@link MediaSession2} with type {@link Session2Token#TYPE_SESSION} is - * created. - * @param token newly created session2 token - * @hide - */ - public void notifySession2Created(@NonNull Session2Token token) { - Objects.requireNonNull(token, "token shouldn't be null"); - if (token.getType() != Session2Token.TYPE_SESSION) { - throw new IllegalArgumentException("token's type should be TYPE_SESSION"); - } - try { - mService.notifySession2Created(token); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - } - - /** - * Checks whether the remote user is a trusted app. - * <p> - * An app is trusted if the app holds the - * {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission or has an enabled - * notification listener. - * - * @param userInfo The remote user info from either - * {@link MediaSession#getCurrentControllerInfo()} or - * {@link MediaBrowserService#getCurrentBrowserInfo()}. - * @return {@code true} if the remote user is trusted or {@code false} otherwise. - * @hide - */ - public boolean isTrustedForMediaControl(@NonNull MediaSessionManager.RemoteUserInfo userInfo) { - Objects.requireNonNull(userInfo, "userInfo shouldn't be null"); - if (userInfo.getPackageName() == null) { - return false; - } - try { - return mService.isTrusted( - userInfo.getPackageName(), userInfo.getPid(), userInfo.getUid()); - } catch (RemoteException e) { - Log.w(TAG, "Cannot communicate with the service.", e); - } - return false; - } - - /** - * This API is not generally intended for third party application developers. - * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a> - * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session - * Library</a> for consistent behavior across all devices. - * <p> - * Gets a list of {@link Session2Token} with type {@link Session2Token#TYPE_SESSION} for the - * current user. - * <p> - * Although this API can be used without any restriction, each session owners can accept or - * reject your uses of {@link MediaSession2}. - * - * @return A list of {@link Session2Token}. - */ - @NonNull - public List<Session2Token> getSession2Tokens() { - return getSession2Tokens(UserHandle.myUserId()); - } - - /** - * Adds a callback to be notified when the list of active sessions changes. - * <p> - * This requires the {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be - * held by the calling app. - * </p> - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - @RequiresPermission(MEDIA_CONTENT_CONTROL) - public void registerSessionCallback(@CallbackExecutor @NonNull Executor executor, - @NonNull SessionCallback callback) { - Objects.requireNonNull(executor, "executor must not be null"); - Objects.requireNonNull(callback, "callback must not be null"); - - if (!mTokenCallbackRecords.addIfAbsent( - new SessionCallbackRecord(executor, callback))) { - Log.w(TAG, "registerSession2TokenCallback: Ignoring the same callback"); - return; - } - synchronized (mLock) { - if (mCallbackStub == null) { - MediaCommunicationServiceCallbackStub callbackStub = - new MediaCommunicationServiceCallbackStub(); - try { - mService.registerCallback(callbackStub, mContext.getPackageName()); - mCallbackStub = callbackStub; - } catch (RemoteException ex) { - Log.e(TAG, "Failed to register callback.", ex); - } - } - } - } - - /** - * Stops receiving active sessions updates on the specified callback. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public void unregisterSessionCallback(@NonNull SessionCallback callback) { - if (!mTokenCallbackRecords.remove( - new SessionCallbackRecord(null, callback))) { - Log.w(TAG, "unregisterSession2TokenCallback: Ignoring an unknown callback."); - return; - } - synchronized (mLock) { - if (mCallbackStub != null && mTokenCallbackRecords.isEmpty()) { - try { - mService.unregisterCallback(mCallbackStub); - } catch (RemoteException ex) { - Log.e(TAG, "Failed to unregister callback.", ex); - } - mCallbackStub = null; - } - } - } - - private List<Session2Token> getSession2Tokens(int userId) { - try { - MediaParceledListSlice slice = mService.getSession2Tokens(userId); - return slice == null ? Collections.emptyList() : slice.getList(); - } catch (RemoteException e) { - Log.e(TAG, "Failed to get session tokens", e); - } - return Collections.emptyList(); - } - - /** - * Callback for listening to changes to the sessions. - * @see #registerSessionCallback(Executor, SessionCallback) - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public interface SessionCallback { - /** - * Called when a new {@link MediaSession2 media session2} is created. - * @param token the newly created token - */ - default void onSession2TokenCreated(@NonNull Session2Token token) {} - - /** - * Called when {@link #getSession2Tokens() session tokens} are changed. - */ - default void onSession2TokensChanged(@NonNull List<Session2Token> tokens) {} - } - - private static final class SessionCallbackRecord { - public final Executor executor; - public final SessionCallback callback; - - SessionCallbackRecord(Executor executor, SessionCallback callback) { - this.executor = executor; - this.callback = callback; - } - - @Override - public int hashCode() { - return Objects.hash(callback); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof SessionCallbackRecord)) { - return false; - } - return Objects.equals(this.callback, ((SessionCallbackRecord) obj).callback); - } - } - - class MediaCommunicationServiceCallbackStub extends IMediaCommunicationServiceCallback.Stub { - @Override - public void onSession2Created(Session2Token token) throws RemoteException { - for (SessionCallbackRecord record : mTokenCallbackRecords) { - record.executor.execute(() -> record.callback.onSession2TokenCreated(token)); - } - } - - @Override - public void onSession2Changed(MediaParceledListSlice tokens) throws RemoteException { - List<Session2Token> tokenList = tokens.getList(); - for (SessionCallbackRecord record : mTokenCallbackRecords) { - record.executor.execute(() -> record.callback.onSession2TokensChanged(tokenList)); - } - } - } -} diff --git a/apex/media/framework/java/android/media/MediaConstants.java b/apex/media/framework/java/android/media/MediaConstants.java deleted file mode 100644 index ce108894b9a5..000000000000 --- a/apex/media/framework/java/android/media/MediaConstants.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2018 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 android.media; - -class MediaConstants { - // Bundle key for int - static final String KEY_PID = "android.media.key.PID"; - - // Bundle key for String - static final String KEY_PACKAGE_NAME = "android.media.key.PACKAGE_NAME"; - - // Bundle key for Parcelable - static final String KEY_SESSION2LINK = "android.media.key.SESSION2LINK"; - static final String KEY_ALLOWED_COMMANDS = "android.media.key.ALLOWED_COMMANDS"; - static final String KEY_PLAYBACK_ACTIVE = "android.media.key.PLAYBACK_ACTIVE"; - static final String KEY_TOKEN_EXTRAS = "android.media.key.TOKEN_EXTRAS"; - static final String KEY_CONNECTION_HINTS = "android.media.key.CONNECTION_HINTS"; - - private MediaConstants() { - } -} diff --git a/apex/media/framework/java/android/media/MediaController2.java b/apex/media/framework/java/android/media/MediaController2.java deleted file mode 100644 index 159e8e551d11..000000000000 --- a/apex/media/framework/java/android/media/MediaController2.java +++ /dev/null @@ -1,637 +0,0 @@ -/* - * Copyright 2018 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 android.media; - -import static android.media.MediaConstants.KEY_ALLOWED_COMMANDS; -import static android.media.MediaConstants.KEY_CONNECTION_HINTS; -import static android.media.MediaConstants.KEY_PACKAGE_NAME; -import static android.media.MediaConstants.KEY_PID; -import static android.media.MediaConstants.KEY_PLAYBACK_ACTIVE; -import static android.media.MediaConstants.KEY_SESSION2LINK; -import static android.media.MediaConstants.KEY_TOKEN_EXTRAS; -import static android.media.Session2Command.Result.RESULT_ERROR_UNKNOWN_ERROR; -import static android.media.Session2Command.Result.RESULT_INFO_SKIPPED; -import static android.media.Session2Token.TYPE_SESSION; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.os.Bundle; -import android.os.Handler; -import android.os.IBinder; -import android.os.Process; -import android.os.RemoteException; -import android.os.ResultReceiver; -import android.util.ArrayMap; -import android.util.ArraySet; -import android.util.Log; - -import java.util.concurrent.Executor; - -/** - * This API is not generally intended for third party application developers. - * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a> - * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session - * Library</a> for consistent behavior across all devices. - * - * Allows an app to interact with an active {@link MediaSession2} or a - * {@link MediaSession2Service} which would provide {@link MediaSession2}. Media buttons and other - * commands can be sent to the session. - */ -public class MediaController2 implements AutoCloseable { - static final String TAG = "MediaController2"; - static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - - @SuppressWarnings("WeakerAccess") /* synthetic access */ - final ControllerCallback mCallback; - - private final IBinder.DeathRecipient mDeathRecipient = () -> close(); - private final Context mContext; - private final Session2Token mSessionToken; - private final Executor mCallbackExecutor; - private final Controller2Link mControllerStub; - private final Handler mResultHandler; - private final SessionServiceConnection mServiceConnection; - - private final Object mLock = new Object(); - //@GuardedBy("mLock") - private boolean mClosed; - //@GuardedBy("mLock") - private int mNextSeqNumber; - //@GuardedBy("mLock") - private Session2Link mSessionBinder; - //@GuardedBy("mLock") - private Session2CommandGroup mAllowedCommands; - //@GuardedBy("mLock") - private Session2Token mConnectedToken; - //@GuardedBy("mLock") - private ArrayMap<ResultReceiver, Integer> mPendingCommands; - //@GuardedBy("mLock") - private ArraySet<Integer> mRequestedCommandSeqNumbers; - //@GuardedBy("mLock") - private boolean mPlaybackActive; - - /** - * Create a {@link MediaController2} from the {@link Session2Token}. - * This connects to the session and may wake up the service if it's not available. - * - * @param context context - * @param token token to connect to - * @param connectionHints a session-specific argument to send to the session when connecting. - * The contents of this bundle may affect the connection result. - * @param executor executor to run callbacks on. - * @param callback controller callback to receive changes in. - */ - MediaController2(@NonNull Context context, @NonNull Session2Token token, - @NonNull Bundle connectionHints, @NonNull Executor executor, - @NonNull ControllerCallback callback) { - if (context == null) { - throw new IllegalArgumentException("context shouldn't be null"); - } - if (token == null) { - throw new IllegalArgumentException("token shouldn't be null"); - } - mContext = context; - mSessionToken = token; - mCallbackExecutor = (executor == null) ? context.getMainExecutor() : executor; - mCallback = (callback == null) ? new ControllerCallback() {} : callback; - mControllerStub = new Controller2Link(this); - // NOTE: mResultHandler uses main looper, so this MUST NOT be blocked. - mResultHandler = new Handler(context.getMainLooper()); - - mNextSeqNumber = 0; - mPendingCommands = new ArrayMap<>(); - mRequestedCommandSeqNumbers = new ArraySet<>(); - - boolean connectRequested; - if (token.getType() == TYPE_SESSION) { - mServiceConnection = null; - connectRequested = requestConnectToSession(connectionHints); - } else { - mServiceConnection = new SessionServiceConnection(connectionHints); - connectRequested = requestConnectToService(); - } - if (!connectRequested) { - close(); - } - } - - @Override - public void close() { - synchronized (mLock) { - if (mClosed) { - // Already closed. Ignore rest of clean up code. - // Note: unbindService() throws IllegalArgumentException when it's called twice. - return; - } - if (DEBUG) { - Log.d(TAG, "closing " + this); - } - mClosed = true; - if (mServiceConnection != null) { - // Note: This should be called even when the bindService() has returned false. - mContext.unbindService(mServiceConnection); - } - if (mSessionBinder != null) { - try { - mSessionBinder.disconnect(mControllerStub, getNextSeqNumber()); - mSessionBinder.unlinkToDeath(mDeathRecipient, 0); - } catch (RuntimeException e) { - // No-op - } - } - mConnectedToken = null; - mPendingCommands.clear(); - mRequestedCommandSeqNumbers.clear(); - mCallbackExecutor.execute(() -> { - mCallback.onDisconnected(MediaController2.this); - }); - mSessionBinder = null; - } - } - - /** - * Returns {@link Session2Token} of the connected session. - * If it is not connected yet, it returns {@code null}. - * <p> - * This may differ with the {@link Session2Token} from the constructor. For example, if the - * controller is created with the token for {@link MediaSession2Service}, this would return - * token for the {@link MediaSession2} in the service. - * - * @return Session2Token of the connected session, or {@code null} if not connected - */ - @Nullable - public Session2Token getConnectedToken() { - synchronized (mLock) { - return mConnectedToken; - } - } - - /** - * Returns whether the session's playback is active. - * - * @return {@code true} if playback active. {@code false} otherwise. - * @see ControllerCallback#onPlaybackActiveChanged(MediaController2, boolean) - */ - public boolean isPlaybackActive() { - synchronized (mLock) { - return mPlaybackActive; - } - } - - /** - * Sends a session command to the session - * <p> - * @param command the session command - * @param args optional arguments - * @return a token which will be sent together in {@link ControllerCallback#onCommandResult} - * when its result is received. - */ - @NonNull - public Object sendSessionCommand(@NonNull Session2Command command, @Nullable Bundle args) { - if (command == null) { - throw new IllegalArgumentException("command shouldn't be null"); - } - - ResultReceiver resultReceiver = new ResultReceiver(mResultHandler) { - protected void onReceiveResult(int resultCode, Bundle resultData) { - synchronized (mLock) { - mPendingCommands.remove(this); - } - mCallbackExecutor.execute(() -> { - mCallback.onCommandResult(MediaController2.this, this, - command, new Session2Command.Result(resultCode, resultData)); - }); - } - }; - - synchronized (mLock) { - if (mSessionBinder != null) { - int seq = getNextSeqNumber(); - mPendingCommands.put(resultReceiver, seq); - try { - mSessionBinder.sendSessionCommand(mControllerStub, seq, command, args, - resultReceiver); - } catch (RuntimeException e) { - mPendingCommands.remove(resultReceiver); - resultReceiver.send(RESULT_ERROR_UNKNOWN_ERROR, null); - } - } - } - return resultReceiver; - } - - /** - * Cancels the session command previously sent. - * - * @param token the token which is returned from {@link #sendSessionCommand}. - */ - public void cancelSessionCommand(@NonNull Object token) { - if (token == null) { - throw new IllegalArgumentException("token shouldn't be null"); - } - synchronized (mLock) { - if (mSessionBinder == null) return; - Integer seq = mPendingCommands.remove(token); - if (seq != null) { - mSessionBinder.cancelSessionCommand(mControllerStub, seq); - } - } - } - - // Called by Controller2Link.onConnected - void onConnected(int seq, Bundle connectionResult) { - Session2Link sessionBinder = connectionResult.getParcelable(KEY_SESSION2LINK); - Session2CommandGroup allowedCommands = - connectionResult.getParcelable(KEY_ALLOWED_COMMANDS); - boolean playbackActive = connectionResult.getBoolean(KEY_PLAYBACK_ACTIVE); - - Bundle tokenExtras = connectionResult.getBundle(KEY_TOKEN_EXTRAS); - if (tokenExtras == null) { - Log.w(TAG, "extras shouldn't be null."); - tokenExtras = Bundle.EMPTY; - } else if (MediaSession2.hasCustomParcelable(tokenExtras)) { - Log.w(TAG, "extras contain custom parcelable. Ignoring."); - tokenExtras = Bundle.EMPTY; - } - - if (DEBUG) { - Log.d(TAG, "notifyConnected sessionBinder=" + sessionBinder - + ", allowedCommands=" + allowedCommands); - } - if (sessionBinder == null || allowedCommands == null) { - // Connection rejected. - close(); - return; - } - synchronized (mLock) { - mSessionBinder = sessionBinder; - mAllowedCommands = allowedCommands; - mPlaybackActive = playbackActive; - - // Implementation for the local binder is no-op, - // so can be used without worrying about deadlock. - sessionBinder.linkToDeath(mDeathRecipient, 0); - mConnectedToken = new Session2Token(mSessionToken.getUid(), TYPE_SESSION, - mSessionToken.getPackageName(), sessionBinder, tokenExtras); - } - mCallbackExecutor.execute(() -> { - mCallback.onConnected(MediaController2.this, allowedCommands); - }); - } - - // Called by Controller2Link.onDisconnected - void onDisconnected(int seq) { - // close() will call mCallback.onDisconnected - close(); - } - - // Called by Controller2Link.onPlaybackActiveChanged - void onPlaybackActiveChanged(int seq, boolean playbackActive) { - synchronized (mLock) { - mPlaybackActive = playbackActive; - } - mCallbackExecutor.execute(() -> { - mCallback.onPlaybackActiveChanged(MediaController2.this, playbackActive); - }); - } - - // Called by Controller2Link.onSessionCommand - void onSessionCommand(int seq, Session2Command command, Bundle args, - @Nullable ResultReceiver resultReceiver) { - synchronized (mLock) { - mRequestedCommandSeqNumbers.add(seq); - } - mCallbackExecutor.execute(() -> { - boolean isCanceled; - synchronized (mLock) { - isCanceled = !mRequestedCommandSeqNumbers.remove(seq); - } - if (isCanceled) { - if (resultReceiver != null) { - resultReceiver.send(RESULT_INFO_SKIPPED, null); - } - return; - } - Session2Command.Result result = mCallback.onSessionCommand( - MediaController2.this, command, args); - if (resultReceiver != null) { - if (result == null) { - resultReceiver.send(RESULT_INFO_SKIPPED, null); - } else { - resultReceiver.send(result.getResultCode(), result.getResultData()); - } - } - }); - } - - // Called by Controller2Link.onSessionCommand - void onCancelCommand(int seq) { - synchronized (mLock) { - mRequestedCommandSeqNumbers.remove(seq); - } - } - - private int getNextSeqNumber() { - synchronized (mLock) { - return mNextSeqNumber++; - } - } - - private Bundle createConnectionRequest(@NonNull Bundle connectionHints) { - Bundle connectionRequest = new Bundle(); - connectionRequest.putString(KEY_PACKAGE_NAME, mContext.getPackageName()); - connectionRequest.putInt(KEY_PID, Process.myPid()); - connectionRequest.putBundle(KEY_CONNECTION_HINTS, connectionHints); - return connectionRequest; - } - - private boolean requestConnectToSession(@NonNull Bundle connectionHints) { - Session2Link sessionBinder = mSessionToken.getSessionLink(); - Bundle connectionRequest = createConnectionRequest(connectionHints); - try { - sessionBinder.connect(mControllerStub, getNextSeqNumber(), connectionRequest); - } catch (RuntimeException e) { - Log.w(TAG, "Failed to call connection request", e); - return false; - } - return true; - } - - private boolean requestConnectToService() { - // Service. Needs to get fresh binder whenever connection is needed. - final Intent intent = new Intent(MediaSession2Service.SERVICE_INTERFACE); - intent.setClassName(mSessionToken.getPackageName(), mSessionToken.getServiceName()); - - // Use bindService() instead of startForegroundService() to start session service for three - // reasons. - // 1. Prevent session service owner's stopSelf() from destroying service. - // With the startForegroundService(), service's call of stopSelf() will trigger immediate - // onDestroy() calls on the main thread even when onConnect() is running in another - // thread. - // 2. Minimize APIs for developers to take care about. - // With bindService(), developers only need to take care about Service.onBind() - // but Service.onStartCommand() should be also taken care about with the - // startForegroundService(). - // 3. Future support for UI-less playback - // If a service wants to keep running, it should be either foreground service or - // bound service. But there had been request for the feature for system apps - // and using bindService() will be better fit with it. - synchronized (mLock) { - boolean result = mContext.bindService( - intent, mServiceConnection, Context.BIND_AUTO_CREATE); - if (!result) { - Log.w(TAG, "bind to " + mSessionToken + " failed"); - return false; - } else if (DEBUG) { - Log.d(TAG, "bind to " + mSessionToken + " succeeded"); - } - } - return true; - } - - /** - * This API is not generally intended for third party application developers. - * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a> - * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session - * Library</a> for consistent behavior across all devices. - * <p> - * Builder for {@link MediaController2}. - * <p> - * Any incoming event from the {@link MediaSession2} will be handled on the callback - * executor. If it's not set, {@link Context#getMainExecutor()} will be used by default. - */ - public static final class Builder { - private Context mContext; - private Session2Token mToken; - private Bundle mConnectionHints; - private Executor mCallbackExecutor; - private ControllerCallback mCallback; - - /** - * Creates a builder for {@link MediaController2}. - * - * @param context context - * @param token token of the session to connect to - */ - public Builder(@NonNull Context context, @NonNull Session2Token token) { - if (context == null) { - throw new IllegalArgumentException("context shouldn't be null"); - } - if (token == null) { - throw new IllegalArgumentException("token shouldn't be null"); - } - mContext = context; - mToken = token; - } - - /** - * Set the connection hints for the controller. - * <p> - * {@code connectionHints} is a session-specific argument to send to the session when - * connecting. The contents of this bundle may affect the connection result. - * <p> - * An {@link IllegalArgumentException} will be thrown if the bundle contains any - * non-framework Parcelable objects. - * - * @param connectionHints a bundle which contains the connection hints - * @return The Builder to allow chaining - */ - @NonNull - public Builder setConnectionHints(@NonNull Bundle connectionHints) { - if (connectionHints == null) { - throw new IllegalArgumentException("connectionHints shouldn't be null"); - } - if (MediaSession2.hasCustomParcelable(connectionHints)) { - throw new IllegalArgumentException("connectionHints shouldn't contain any custom " - + "parcelables"); - } - mConnectionHints = new Bundle(connectionHints); - return this; - } - - /** - * Set callback for the controller and its executor. - * - * @param executor callback executor - * @param callback session callback. - * @return The Builder to allow chaining - */ - @NonNull - public Builder setControllerCallback(@NonNull Executor executor, - @NonNull ControllerCallback callback) { - if (executor == null) { - throw new IllegalArgumentException("executor shouldn't be null"); - } - if (callback == null) { - throw new IllegalArgumentException("callback shouldn't be null"); - } - mCallbackExecutor = executor; - mCallback = callback; - return this; - } - - /** - * Build {@link MediaController2}. - * - * @return a new controller - */ - @NonNull - public MediaController2 build() { - if (mCallbackExecutor == null) { - mCallbackExecutor = mContext.getMainExecutor(); - } - if (mCallback == null) { - mCallback = new ControllerCallback() {}; - } - if (mConnectionHints == null) { - mConnectionHints = Bundle.EMPTY; - } - return new MediaController2( - mContext, mToken, mConnectionHints, mCallbackExecutor, mCallback); - } - } - - /** - * This API is not generally intended for third party application developers. - * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a> - * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session - * Library</a> for consistent behavior across all devices. - * <p> - * Interface for listening to change in activeness of the {@link MediaSession2}. - */ - public abstract static class ControllerCallback { - /** - * Called when the controller is successfully connected to the session. The controller - * becomes available afterwards. - * - * @param controller the controller for this event - * @param allowedCommands commands that's allowed by the session. - */ - public void onConnected(@NonNull MediaController2 controller, - @NonNull Session2CommandGroup allowedCommands) {} - - /** - * Called when the session refuses the controller or the controller is disconnected from - * the session. The controller becomes unavailable afterwards and the callback wouldn't - * be called. - * <p> - * It will be also called after the {@link #close()}, so you can put clean up code here. - * You don't need to call {@link #close()} after this. - * - * @param controller the controller for this event - */ - public void onDisconnected(@NonNull MediaController2 controller) {} - - /** - * Called when the session's playback activeness is changed. - * - * @param controller the controller for this event - * @param playbackActive {@code true} if the session's playback is active. - * {@code false} otherwise. - * @see MediaController2#isPlaybackActive() - */ - public void onPlaybackActiveChanged(@NonNull MediaController2 controller, - boolean playbackActive) {} - - /** - * Called when the connected session sent a session command. - * - * @param controller the controller for this event - * @param command the session command - * @param args optional arguments - * @return the result for the session command. If {@code null}, RESULT_INFO_SKIPPED - * will be sent to the session. - */ - @Nullable - public Session2Command.Result onSessionCommand(@NonNull MediaController2 controller, - @NonNull Session2Command command, @Nullable Bundle args) { - return null; - } - - /** - * Called when the command sent to the connected session is finished. - * - * @param controller the controller for this event - * @param token the token got from {@link MediaController2#sendSessionCommand} - * @param command the session command - * @param result the result of the session command - */ - public void onCommandResult(@NonNull MediaController2 controller, @NonNull Object token, - @NonNull Session2Command command, @NonNull Session2Command.Result result) {} - } - - // This will be called on the main thread. - private class SessionServiceConnection implements ServiceConnection { - private final Bundle mConnectionHints; - - SessionServiceConnection(@Nullable Bundle connectionHints) { - mConnectionHints = connectionHints; - } - - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - // Note that it's always main-thread. - boolean connectRequested = false; - try { - if (DEBUG) { - Log.d(TAG, "onServiceConnected " + name + " " + this); - } - if (!mSessionToken.getPackageName().equals(name.getPackageName())) { - Log.wtf(TAG, "Expected connection to " + mSessionToken.getPackageName() - + " but is connected to " + name); - return; - } - IMediaSession2Service iService = IMediaSession2Service.Stub.asInterface(service); - if (iService == null) { - Log.wtf(TAG, "Service interface is missing."); - return; - } - Bundle connectionRequest = createConnectionRequest(mConnectionHints); - iService.connect(mControllerStub, getNextSeqNumber(), connectionRequest); - connectRequested = true; - } catch (RemoteException e) { - Log.w(TAG, "Service " + name + " has died prematurely", e); - } finally { - if (!connectRequested) { - close(); - } - } - } - - @Override - public void onServiceDisconnected(ComponentName name) { - // Temporal lose of the binding because of the service crash. System will automatically - // rebind, so just no-op. - if (DEBUG) { - Log.w(TAG, "Session service " + name + " is disconnected."); - } - close(); - } - - @Override - public void onBindingDied(ComponentName name) { - // Permanent lose of the binding because of the service package update or removed. - // This SessionServiceRecord will be removed accordingly, but forget session binder here - // for sure. - close(); - } - } -} diff --git a/apex/media/framework/java/android/media/MediaFeature.java b/apex/media/framework/java/android/media/MediaFeature.java deleted file mode 100644 index 8d1b159cd70b..000000000000 --- a/apex/media/framework/java/android/media/MediaFeature.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2020 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 android.media; - -import android.annotation.StringDef; -import android.os.Build; - -import com.android.modules.annotation.MinSdk; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * MediaFeature defines various media features, e.g. hdr type. - */ -@MinSdk(Build.VERSION_CODES.S) -public final class MediaFeature { - /** - * Defines tye type of HDR(high dynamic range) video. - */ - public static final class HdrType { - private HdrType() { - } - - /** - * HDR type for dolby-vision. - */ - public static final String DOLBY_VISION = "android.media.feature.hdr.dolby_vision"; - /** - * HDR type for hdr10. - */ - public static final String HDR10 = "android.media.feature.hdr.hdr10"; - /** - * HDR type for hdr10+. - */ - public static final String HDR10_PLUS = "android.media.feature.hdr.hdr10_plus"; - /** - * HDR type for hlg. - */ - public static final String HLG = "android.media.feature.hdr.hlg"; - } - - /** @hide */ - @StringDef({ - HdrType.DOLBY_VISION, - HdrType.HDR10, - HdrType.HDR10_PLUS, - HdrType.HLG, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface MediaHdrType { - } -} diff --git a/apex/media/framework/java/android/media/MediaFrameworkInitializer.java b/apex/media/framework/java/android/media/MediaFrameworkInitializer.java deleted file mode 100644 index 75a56b7231d9..000000000000 --- a/apex/media/framework/java/android/media/MediaFrameworkInitializer.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2020 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 android.media; - -import android.annotation.NonNull; -import android.annotation.SystemApi; -import android.annotation.SystemApi.Client; -import android.app.SystemServiceRegistry; -import android.content.Context; -import android.os.Build; - -import com.android.modules.annotation.MinSdk; -import com.android.modules.utils.build.SdkLevel; - -/** - * Class for performing registration for all media services on com.android.media apex. - * - * @hide - */ -@MinSdk(Build.VERSION_CODES.S) -@SystemApi(client = Client.MODULE_LIBRARIES) -public class MediaFrameworkInitializer { - private MediaFrameworkInitializer() { - } - - private static volatile MediaServiceManager sMediaServiceManager; - - /** - * Sets an instance of {@link MediaServiceManager} that allows - * the media mainline module to register/obtain media binder services. This is called - * by the platform during the system initialization. - * - * @param mediaServiceManager instance of {@link MediaServiceManager} that allows - * the media mainline module to register/obtain media binder services. - */ - public static void setMediaServiceManager( - @NonNull MediaServiceManager mediaServiceManager) { - if (sMediaServiceManager != null) { - throw new IllegalStateException("setMediaServiceManager called twice!"); - } - - if (mediaServiceManager == null) { - throw new NullPointerException("mediaServiceManager is null!"); - } - - sMediaServiceManager = mediaServiceManager; - } - - /** @hide */ - public static MediaServiceManager getMediaServiceManager() { - return sMediaServiceManager; - } - - /** - * Called by {@link SystemServiceRegistry}'s static initializer and registers all media - * services to {@link Context}, so that {@link Context#getSystemService} can return them. - * - * @throws IllegalStateException if this is called from anywhere besides - * {@link SystemServiceRegistry} - */ - public static void registerServiceWrappers() { - SystemServiceRegistry.registerContextAwareService( - Context.MEDIA_TRANSCODING_SERVICE, - MediaTranscodingManager.class, - context -> new MediaTranscodingManager(context) - ); - if (SdkLevel.isAtLeastS()) { - SystemServiceRegistry.registerContextAwareService( - Context.MEDIA_COMMUNICATION_SERVICE, - MediaCommunicationManager.class, - context -> new MediaCommunicationManager(context) - ); - } - } -} diff --git a/apex/media/framework/java/android/media/MediaParceledListSlice.java b/apex/media/framework/java/android/media/MediaParceledListSlice.java deleted file mode 100644 index 47ac193231a0..000000000000 --- a/apex/media/framework/java/android/media/MediaParceledListSlice.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2020 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 android.media; - -import android.annotation.NonNull; -import android.annotation.SystemApi; -import android.os.Parcel; -import android.os.Parcelable; - -import java.util.Collections; -import java.util.List; - -/** - * This is a copied version of MediaParceledListSlice in framework with hidden API usages removed, - * and also with some lint error fixed. - * - * Transfer a large list of Parcelable objects across an IPC. Splits into - * multiple transactions if needed. - * - * TODO: Remove this from @SystemApi once all the MediaSession related classes are moved - * to apex (or ParceledListSlice moved to apex). This class is temporaily added to system API - * for moving classes step by step. - * - * @param <T> The type of the elements in the list. - * @see BaseMediaParceledListSlice - * @deprecated This is temporary marked as @SystemApi. Should be removed from the API surface. - * @hide - */ -@Deprecated -@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) -public final class MediaParceledListSlice<T extends Parcelable> - extends BaseMediaParceledListSlice<T> { - public MediaParceledListSlice(@NonNull List<T> list) { - super(list); - } - - private MediaParceledListSlice(Parcel in, ClassLoader loader) { - super(in, loader); - } - - @NonNull - public static <T extends Parcelable> MediaParceledListSlice<T> emptyList() { - return new MediaParceledListSlice<T>(Collections.<T> emptyList()); - } - - @Override - public int describeContents() { - int contents = 0; - final List<T> list = getList(); - for (int i=0; i<list.size(); i++) { - contents |= list.get(i).describeContents(); - } - return contents; - } - - @Override - void writeElement(T parcelable, Parcel dest, int callFlags) { - parcelable.writeToParcel(dest, callFlags); - } - - @Override - void writeParcelableCreator(T parcelable, Parcel dest) { - dest.writeParcelableCreator((Parcelable) parcelable); - } - - @Override - Parcelable.Creator<?> readParcelableCreator(Parcel from, ClassLoader loader) { - return from.readParcelableCreator(loader); - } - - @NonNull - @SuppressWarnings("unchecked") - public static final Parcelable.ClassLoaderCreator<MediaParceledListSlice> CREATOR = - new Parcelable.ClassLoaderCreator<MediaParceledListSlice>() { - public MediaParceledListSlice createFromParcel(Parcel in) { - return new MediaParceledListSlice(in, null); - } - - @Override - public MediaParceledListSlice createFromParcel(Parcel in, ClassLoader loader) { - return new MediaParceledListSlice(in, loader); - } - - @Override - public MediaParceledListSlice[] newArray(int size) { - return new MediaParceledListSlice[size]; - } - }; -} diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java deleted file mode 100644 index 8cc3bc08dfb5..000000000000 --- a/apex/media/framework/java/android/media/MediaParser.java +++ /dev/null @@ -1,2292 +0,0 @@ -/* - * Copyright (C) 2019 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 android.media; - -import android.annotation.CheckResult; -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.StringDef; -import android.media.MediaCodec.CryptoInfo; -import android.media.metrics.LogSessionId; -import android.os.Build; -import android.text.TextUtils; -import android.util.Log; -import android.util.Pair; -import android.util.SparseArray; - -import androidx.annotation.RequiresApi; - -import com.android.modules.utils.build.SdkLevel; - -import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.Format; -import com.google.android.exoplayer2.ParserException; -import com.google.android.exoplayer2.drm.DrmInitData.SchemeData; -import com.google.android.exoplayer2.extractor.ChunkIndex; -import com.google.android.exoplayer2.extractor.DefaultExtractorInput; -import com.google.android.exoplayer2.extractor.Extractor; -import com.google.android.exoplayer2.extractor.ExtractorInput; -import com.google.android.exoplayer2.extractor.ExtractorOutput; -import com.google.android.exoplayer2.extractor.PositionHolder; -import com.google.android.exoplayer2.extractor.SeekMap.SeekPoints; -import com.google.android.exoplayer2.extractor.TrackOutput; -import com.google.android.exoplayer2.extractor.amr.AmrExtractor; -import com.google.android.exoplayer2.extractor.flac.FlacExtractor; -import com.google.android.exoplayer2.extractor.flv.FlvExtractor; -import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor; -import com.google.android.exoplayer2.extractor.mp3.Mp3Extractor; -import com.google.android.exoplayer2.extractor.mp4.FragmentedMp4Extractor; -import com.google.android.exoplayer2.extractor.mp4.Mp4Extractor; -import com.google.android.exoplayer2.extractor.ogg.OggExtractor; -import com.google.android.exoplayer2.extractor.ts.Ac3Extractor; -import com.google.android.exoplayer2.extractor.ts.Ac4Extractor; -import com.google.android.exoplayer2.extractor.ts.AdtsExtractor; -import com.google.android.exoplayer2.extractor.ts.DefaultTsPayloadReaderFactory; -import com.google.android.exoplayer2.extractor.ts.PsExtractor; -import com.google.android.exoplayer2.extractor.ts.TsExtractor; -import com.google.android.exoplayer2.extractor.wav.WavExtractor; -import com.google.android.exoplayer2.upstream.DataReader; -import com.google.android.exoplayer2.util.ParsableByteArray; -import com.google.android.exoplayer2.util.TimestampAdjuster; -import com.google.android.exoplayer2.util.Util; -import com.google.android.exoplayer2.video.ColorInfo; - -import java.io.EOFException; -import java.io.IOException; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.UUID; -import java.util.concurrent.ThreadLocalRandom; -import java.util.function.Function; - -/** - * Parses media container formats and extracts contained media samples and metadata. - * - * <p>This class provides access to a battery of low-level media container parsers. Each instance of - * this class is associated to a specific media parser implementation which is suitable for - * extraction from a specific media container format. The media parser implementation assignment - * depends on the factory method (see {@link #create} and {@link #createByName}) used to create the - * instance. - * - * <p>Users must implement the following to use this class. - * - * <ul> - * <li>{@link InputReader}: Provides the media container's bytes to parse. - * <li>{@link OutputConsumer}: Provides a sink for all extracted data and metadata. - * </ul> - * - * <p>The following code snippet includes a usage example: - * - * <pre> - * MyOutputConsumer myOutputConsumer = new MyOutputConsumer(); - * MyInputReader myInputReader = new MyInputReader("www.example.com"); - * MediaParser mediaParser = MediaParser.create(myOutputConsumer); - * - * while (mediaParser.advance(myInputReader)) {} - * - * mediaParser.release(); - * mediaParser = null; - * </pre> - * - * <p>The following code snippet provides a rudimentary {@link OutputConsumer} sample implementation - * which extracts and publishes all video samples: - * - * <pre> - * class VideoOutputConsumer implements MediaParser.OutputConsumer { - * - * private byte[] sampleDataBuffer = new byte[4096]; - * private byte[] discardedDataBuffer = new byte[4096]; - * private int videoTrackIndex = -1; - * private int bytesWrittenCount = 0; - * - * @Override - * public void onSeekMapFound(int i, @NonNull MediaFormat mediaFormat) { - * // Do nothing. - * } - * - * @Override - * public void onTrackDataFound(int i, @NonNull TrackData trackData) { - * MediaFormat mediaFormat = trackData.mediaFormat; - * if (videoTrackIndex == -1 && - * mediaFormat - * .getString(MediaFormat.KEY_MIME, /* defaultValue= */ "") - * .startsWith("video/")) { - * videoTrackIndex = i; - * } - * } - * - * @Override - * public void onSampleDataFound(int trackIndex, @NonNull InputReader inputReader) - * throws IOException { - * int numberOfBytesToRead = (int) inputReader.getLength(); - * if (videoTrackIndex != trackIndex) { - * // Discard contents. - * inputReader.read( - * discardedDataBuffer, - * /* offset= */ 0, - * Math.min(discardDataBuffer.length, numberOfBytesToRead)); - * } else { - * ensureSpaceInBuffer(numberOfBytesToRead); - * int bytesRead = inputReader.read( - * sampleDataBuffer, bytesWrittenCount, numberOfBytesToRead); - * bytesWrittenCount += bytesRead; - * } - * } - * - * @Override - * public void onSampleCompleted( - * int trackIndex, - * long timeMicros, - * int flags, - * int size, - * int offset, - * @Nullable CryptoInfo cryptoData) { - * if (videoTrackIndex != trackIndex) { - * return; // It's not the video track. Ignore. - * } - * byte[] sampleData = new byte[size]; - * int sampleStartOffset = bytesWrittenCount - size - offset; - * System.arraycopy( - * sampleDataBuffer, - * sampleStartOffset, - * sampleData, - * /* destPos= */ 0, - * size); - * // Place trailing bytes at the start of the buffer. - * System.arraycopy( - * sampleDataBuffer, - * bytesWrittenCount - offset, - * sampleDataBuffer, - * /* destPos= */ 0, - * /* size= */ offset); - * bytesWrittenCount = bytesWrittenCount - offset; - * publishSample(sampleData, timeMicros, flags); - * } - * - * private void ensureSpaceInBuffer(int numberOfBytesToRead) { - * int requiredLength = bytesWrittenCount + numberOfBytesToRead; - * if (requiredLength > sampleDataBuffer.length) { - * sampleDataBuffer = Arrays.copyOf(sampleDataBuffer, requiredLength); - * } - * } - * - * } - * - * </pre> - */ -public final class MediaParser { - - /** - * Maps seek positions to {@link SeekPoint SeekPoints} in the stream. - * - * <p>A {@link SeekPoint} is a position in the stream from which a player may successfully start - * playing media samples. - */ - public static final class SeekMap { - - /** Returned by {@link #getDurationMicros()} when the duration is unknown. */ - public static final int UNKNOWN_DURATION = Integer.MIN_VALUE; - - /** - * For each {@link #getSeekPoints} call, returns a single {@link SeekPoint} whose {@link - * SeekPoint#timeMicros} matches the requested timestamp, and whose {@link - * SeekPoint#position} is 0. - * - * @hide - */ - public static final SeekMap DUMMY = new SeekMap(new DummyExoPlayerSeekMap()); - - private final com.google.android.exoplayer2.extractor.SeekMap mExoPlayerSeekMap; - - private SeekMap(com.google.android.exoplayer2.extractor.SeekMap exoplayerSeekMap) { - mExoPlayerSeekMap = exoplayerSeekMap; - } - - /** Returns whether seeking is supported. */ - public boolean isSeekable() { - return mExoPlayerSeekMap.isSeekable(); - } - - /** - * Returns the duration of the stream in microseconds or {@link #UNKNOWN_DURATION} if the - * duration is unknown. - */ - public long getDurationMicros() { - long durationUs = mExoPlayerSeekMap.getDurationUs(); - return durationUs != C.TIME_UNSET ? durationUs : UNKNOWN_DURATION; - } - - /** - * Obtains {@link SeekPoint SeekPoints} for the specified seek time in microseconds. - * - * <p>{@code getSeekPoints(timeMicros).first} contains the latest seek point for samples - * with timestamp equal to or smaller than {@code timeMicros}. - * - * <p>{@code getSeekPoints(timeMicros).second} contains the earliest seek point for samples - * with timestamp equal to or greater than {@code timeMicros}. If a seek point exists for - * {@code timeMicros}, the returned pair will contain the same {@link SeekPoint} twice. - * - * @param timeMicros A seek time in microseconds. - * @return The corresponding {@link SeekPoint SeekPoints}. - */ - @NonNull - public Pair<SeekPoint, SeekPoint> getSeekPoints(long timeMicros) { - SeekPoints seekPoints = mExoPlayerSeekMap.getSeekPoints(timeMicros); - return new Pair<>(toSeekPoint(seekPoints.first), toSeekPoint(seekPoints.second)); - } - } - - /** Holds information associated with a track. */ - public static final class TrackData { - - /** Holds {@link MediaFormat} information for the track. */ - @NonNull public final MediaFormat mediaFormat; - - /** - * Holds {@link DrmInitData} necessary to acquire keys associated with the track, or null if - * the track has no encryption data. - */ - @Nullable public final DrmInitData drmInitData; - - private TrackData(MediaFormat mediaFormat, DrmInitData drmInitData) { - this.mediaFormat = mediaFormat; - this.drmInitData = drmInitData; - } - } - - /** Defines a seek point in a media stream. */ - public static final class SeekPoint { - - /** A {@link SeekPoint} whose time and byte offset are both set to 0. */ - @NonNull public static final SeekPoint START = new SeekPoint(0, 0); - - /** The time of the seek point, in microseconds. */ - public final long timeMicros; - - /** The byte offset of the seek point. */ - public final long position; - - /** - * @param timeMicros The time of the seek point, in microseconds. - * @param position The byte offset of the seek point. - */ - private SeekPoint(long timeMicros, long position) { - this.timeMicros = timeMicros; - this.position = position; - } - - @Override - @NonNull - public String toString() { - return "[timeMicros=" + timeMicros + ", position=" + position + "]"; - } - - @Override - public boolean equals(@Nullable Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - SeekPoint other = (SeekPoint) obj; - return timeMicros == other.timeMicros && position == other.position; - } - - @Override - public int hashCode() { - int result = (int) timeMicros; - result = 31 * result + (int) position; - return result; - } - } - - /** Provides input data to {@link MediaParser}. */ - public interface InputReader { - - /** - * Reads up to {@code readLength} bytes of data and stores them into {@code buffer}, - * starting at index {@code offset}. - * - * <p>This method blocks until at least one byte is read, the end of input is detected, or - * an exception is thrown. The read position advances to the first unread byte. - * - * @param buffer The buffer into which the read data should be stored. - * @param offset The start offset into {@code buffer} at which data should be written. - * @param readLength The maximum number of bytes to read. - * @return The non-zero number of bytes read, or -1 if no data is available because the end - * of the input has been reached. - * @throws java.io.IOException If an error occurs reading from the source. - */ - int read(@NonNull byte[] buffer, int offset, int readLength) throws IOException; - - /** Returns the current read position (byte offset) in the stream. */ - long getPosition(); - - /** Returns the length of the input in bytes, or -1 if the length is unknown. */ - long getLength(); - } - - /** {@link InputReader} that allows setting the read position. */ - public interface SeekableInputReader extends InputReader { - - /** - * Sets the read position at the given {@code position}. - * - * <p>{@link #advance} will immediately return after calling this method. - * - * @param position The position to seek to, in bytes. - */ - void seekToPosition(long position); - } - - /** Receives extracted media sample data and metadata from {@link MediaParser}. */ - public interface OutputConsumer { - - /** - * Called when a {@link SeekMap} has been extracted from the stream. - * - * <p>This method is called at least once before any samples are {@link #onSampleCompleted - * complete}. May be called multiple times after that in order to add {@link SeekPoint - * SeekPoints}. - * - * @param seekMap The extracted {@link SeekMap}. - */ - void onSeekMapFound(@NonNull SeekMap seekMap); - - /** - * Called when the number of tracks is found. - * - * @param numberOfTracks The number of tracks in the stream. - */ - void onTrackCountFound(int numberOfTracks); - - /** - * Called when new {@link TrackData} is found in the stream. - * - * @param trackIndex The index of the track for which the {@link TrackData} was extracted. - * @param trackData The extracted {@link TrackData}. - */ - void onTrackDataFound(int trackIndex, @NonNull TrackData trackData); - - /** - * Called when sample data is found in the stream. - * - * <p>If the invocation of this method returns before the entire {@code inputReader} {@link - * InputReader#getLength() length} is consumed, the method will be called again for the - * implementer to read the remaining data. Implementers should surface any thrown {@link - * IOException} caused by reading from {@code input}. - * - * @param trackIndex The index of the track to which the sample data corresponds. - * @param inputReader The {@link InputReader} from which to read the data. - * @throws IOException If an exception occurs while reading from {@code inputReader}. - */ - void onSampleDataFound(int trackIndex, @NonNull InputReader inputReader) throws IOException; - - /** - * Called once all the data of a sample has been passed to {@link #onSampleDataFound}. - * - * <p>Includes sample metadata, like presentation timestamp and flags. - * - * @param trackIndex The index of the track to which the sample corresponds. - * @param timeMicros The media timestamp associated with the sample, in microseconds. - * @param flags Flags associated with the sample. See the {@code SAMPLE_FLAG_*} constants. - * @param size The size of the sample data, in bytes. - * @param offset The number of bytes that have been consumed by {@code - * onSampleDataFound(int, MediaParser.InputReader)} for the specified track, since the - * last byte belonging to the sample whose metadata is being passed. - * @param cryptoInfo Encryption data required to decrypt the sample. May be null for - * unencrypted samples. Implementors should treat any output {@link CryptoInfo} - * instances as immutable. MediaParser will not modify any output {@code cryptoInfos} - * and implementors should not modify them either. - */ - void onSampleCompleted( - int trackIndex, - long timeMicros, - @SampleFlags int flags, - int size, - int offset, - @Nullable CryptoInfo cryptoInfo); - } - - /** - * Thrown if all parser implementations provided to {@link #create} failed to sniff the input - * content. - */ - public static final class UnrecognizedInputFormatException extends IOException { - - /** - * Creates a new instance which signals that the parsers with the given names failed to - * parse the input. - */ - @NonNull - @CheckResult - private static UnrecognizedInputFormatException createForExtractors( - @NonNull String... extractorNames) { - StringBuilder builder = new StringBuilder(); - builder.append("None of the available parsers ( "); - builder.append(extractorNames[0]); - for (int i = 1; i < extractorNames.length; i++) { - builder.append(", "); - builder.append(extractorNames[i]); - } - builder.append(") could read the stream."); - return new UnrecognizedInputFormatException(builder.toString()); - } - - private UnrecognizedInputFormatException(String extractorNames) { - super(extractorNames); - } - } - - /** Thrown when an error occurs while parsing a media stream. */ - public static final class ParsingException extends IOException { - - private ParsingException(ParserException cause) { - super(cause); - } - } - - // Sample flags. - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef( - flag = true, - value = { - SAMPLE_FLAG_KEY_FRAME, - SAMPLE_FLAG_HAS_SUPPLEMENTAL_DATA, - SAMPLE_FLAG_LAST_SAMPLE, - SAMPLE_FLAG_ENCRYPTED, - SAMPLE_FLAG_DECODE_ONLY - }) - public @interface SampleFlags {} - /** Indicates that the sample holds a synchronization sample. */ - public static final int SAMPLE_FLAG_KEY_FRAME = MediaCodec.BUFFER_FLAG_KEY_FRAME; - /** - * Indicates that the sample has supplemental data. - * - * <p>Samples will not have this flag set unless the {@code - * "android.media.mediaparser.includeSupplementalData"} parameter is set to {@code true} via - * {@link #setParameter}. - * - * <p>Samples with supplemental data have the following sample data format: - * - * <ul> - * <li>If the {@code "android.media.mediaparser.inBandCryptoInfo"} parameter is set, all - * encryption information. - * <li>(4 bytes) {@code sample_data_size}: The size of the actual sample data, not including - * supplemental data or encryption information. - * <li>({@code sample_data_size} bytes): The media sample data. - * <li>(remaining bytes) The supplemental data. - * </ul> - */ - public static final int SAMPLE_FLAG_HAS_SUPPLEMENTAL_DATA = 1 << 28; - /** Indicates that the sample is known to contain the last media sample of the stream. */ - public static final int SAMPLE_FLAG_LAST_SAMPLE = 1 << 29; - /** Indicates that the sample is (at least partially) encrypted. */ - public static final int SAMPLE_FLAG_ENCRYPTED = 1 << 30; - /** Indicates that the sample should be decoded but not rendered. */ - public static final int SAMPLE_FLAG_DECODE_ONLY = 1 << 31; - - // Parser implementation names. - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @StringDef( - prefix = {"PARSER_NAME_"}, - value = { - PARSER_NAME_UNKNOWN, - PARSER_NAME_MATROSKA, - PARSER_NAME_FMP4, - PARSER_NAME_MP4, - PARSER_NAME_MP3, - PARSER_NAME_ADTS, - PARSER_NAME_AC3, - PARSER_NAME_TS, - PARSER_NAME_FLV, - PARSER_NAME_OGG, - PARSER_NAME_PS, - PARSER_NAME_WAV, - PARSER_NAME_AMR, - PARSER_NAME_AC4, - PARSER_NAME_FLAC - }) - public @interface ParserName {} - - /** Parser name returned by {@link #getParserName()} when no parser has been selected yet. */ - public static final String PARSER_NAME_UNKNOWN = "android.media.mediaparser.UNKNOWN"; - /** - * Parser for the Matroska container format, as defined in the <a - * href="https://matroska.org/technical/specs/">spec</a>. - */ - public static final String PARSER_NAME_MATROSKA = "android.media.mediaparser.MatroskaParser"; - /** - * Parser for fragmented files using the MP4 container format, as defined in ISO/IEC 14496-12. - */ - public static final String PARSER_NAME_FMP4 = "android.media.mediaparser.FragmentedMp4Parser"; - /** - * Parser for non-fragmented files using the MP4 container format, as defined in ISO/IEC - * 14496-12. - */ - public static final String PARSER_NAME_MP4 = "android.media.mediaparser.Mp4Parser"; - /** Parser for the MP3 container format, as defined in ISO/IEC 11172-3. */ - public static final String PARSER_NAME_MP3 = "android.media.mediaparser.Mp3Parser"; - /** Parser for the ADTS container format, as defined in ISO/IEC 13818-7. */ - public static final String PARSER_NAME_ADTS = "android.media.mediaparser.AdtsParser"; - /** - * Parser for the AC-3 container format, as defined in Digital Audio Compression Standard - * (AC-3). - */ - public static final String PARSER_NAME_AC3 = "android.media.mediaparser.Ac3Parser"; - /** Parser for the TS container format, as defined in ISO/IEC 13818-1. */ - public static final String PARSER_NAME_TS = "android.media.mediaparser.TsParser"; - /** - * Parser for the FLV container format, as defined in Adobe Flash Video File Format - * Specification. - */ - public static final String PARSER_NAME_FLV = "android.media.mediaparser.FlvParser"; - /** Parser for the OGG container format, as defined in RFC 3533. */ - public static final String PARSER_NAME_OGG = "android.media.mediaparser.OggParser"; - /** Parser for the PS container format, as defined in ISO/IEC 11172-1. */ - public static final String PARSER_NAME_PS = "android.media.mediaparser.PsParser"; - /** - * Parser for the WAV container format, as defined in Multimedia Programming Interface and Data - * Specifications. - */ - public static final String PARSER_NAME_WAV = "android.media.mediaparser.WavParser"; - /** Parser for the AMR container format, as defined in RFC 4867. */ - public static final String PARSER_NAME_AMR = "android.media.mediaparser.AmrParser"; - /** - * Parser for the AC-4 container format, as defined by Dolby AC-4: Audio delivery for - * Next-Generation Entertainment Services. - */ - public static final String PARSER_NAME_AC4 = "android.media.mediaparser.Ac4Parser"; - /** - * Parser for the FLAC container format, as defined in the <a - * href="https://xiph.org/flac/">spec</a>. - */ - public static final String PARSER_NAME_FLAC = "android.media.mediaparser.FlacParser"; - - // MediaParser parameters. - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @StringDef( - prefix = {"PARAMETER_"}, - value = { - PARAMETER_ADTS_ENABLE_CBR_SEEKING, - PARAMETER_AMR_ENABLE_CBR_SEEKING, - PARAMETER_FLAC_DISABLE_ID3, - PARAMETER_MP4_IGNORE_EDIT_LISTS, - PARAMETER_MP4_IGNORE_TFDT_BOX, - PARAMETER_MP4_TREAT_VIDEO_FRAMES_AS_KEYFRAMES, - PARAMETER_MATROSKA_DISABLE_CUES_SEEKING, - PARAMETER_MP3_DISABLE_ID3, - PARAMETER_MP3_ENABLE_CBR_SEEKING, - PARAMETER_MP3_ENABLE_INDEX_SEEKING, - PARAMETER_TS_MODE, - PARAMETER_TS_ALLOW_NON_IDR_AVC_KEYFRAMES, - PARAMETER_TS_IGNORE_AAC_STREAM, - PARAMETER_TS_IGNORE_AVC_STREAM, - PARAMETER_TS_IGNORE_SPLICE_INFO_STREAM, - PARAMETER_TS_DETECT_ACCESS_UNITS, - PARAMETER_TS_ENABLE_HDMV_DTS_AUDIO_STREAMS, - PARAMETER_IN_BAND_CRYPTO_INFO, - PARAMETER_INCLUDE_SUPPLEMENTAL_DATA - }) - public @interface ParameterName {} - - /** - * Sets whether constant bitrate seeking should be enabled for ADTS parsing. {@code boolean} - * expected. Default value is {@code false}. - */ - public static final String PARAMETER_ADTS_ENABLE_CBR_SEEKING = - "android.media.mediaparser.adts.enableCbrSeeking"; - /** - * Sets whether constant bitrate seeking should be enabled for AMR. {@code boolean} expected. - * Default value is {@code false}. - */ - public static final String PARAMETER_AMR_ENABLE_CBR_SEEKING = - "android.media.mediaparser.amr.enableCbrSeeking"; - /** - * Sets whether the ID3 track should be disabled for FLAC. {@code boolean} expected. Default - * value is {@code false}. - */ - public static final String PARAMETER_FLAC_DISABLE_ID3 = - "android.media.mediaparser.flac.disableId3"; - /** - * Sets whether MP4 parsing should ignore edit lists. {@code boolean} expected. Default value is - * {@code false}. - */ - public static final String PARAMETER_MP4_IGNORE_EDIT_LISTS = - "android.media.mediaparser.mp4.ignoreEditLists"; - /** - * Sets whether MP4 parsing should ignore the tfdt box. {@code boolean} expected. Default value - * is {@code false}. - */ - public static final String PARAMETER_MP4_IGNORE_TFDT_BOX = - "android.media.mediaparser.mp4.ignoreTfdtBox"; - /** - * Sets whether MP4 parsing should treat all video frames as key frames. {@code boolean} - * expected. Default value is {@code false}. - */ - public static final String PARAMETER_MP4_TREAT_VIDEO_FRAMES_AS_KEYFRAMES = - "android.media.mediaparser.mp4.treatVideoFramesAsKeyframes"; - /** - * Sets whether Matroska parsing should avoid seeking to the cues element. {@code boolean} - * expected. Default value is {@code false}. - * - * <p>If this flag is enabled and the cues element occurs after the first cluster, then the - * media is treated as unseekable. - */ - public static final String PARAMETER_MATROSKA_DISABLE_CUES_SEEKING = - "android.media.mediaparser.matroska.disableCuesSeeking"; - /** - * Sets whether the ID3 track should be disabled for MP3. {@code boolean} expected. Default - * value is {@code false}. - */ - public static final String PARAMETER_MP3_DISABLE_ID3 = - "android.media.mediaparser.mp3.disableId3"; - /** - * Sets whether constant bitrate seeking should be enabled for MP3. {@code boolean} expected. - * Default value is {@code false}. - */ - public static final String PARAMETER_MP3_ENABLE_CBR_SEEKING = - "android.media.mediaparser.mp3.enableCbrSeeking"; - /** - * Sets whether MP3 parsing should generate a time-to-byte mapping. {@code boolean} expected. - * Default value is {@code false}. - * - * <p>Enabling this flag may require to scan a significant portion of the file to compute a seek - * point. Therefore, it should only be used if: - * - * <ul> - * <li>the file is small, or - * <li>the bitrate is variable (or the type of bitrate is unknown) and the seeking metadata - * provided in the file is not precise enough (or is not present). - * </ul> - */ - public static final String PARAMETER_MP3_ENABLE_INDEX_SEEKING = - "android.media.mediaparser.mp3.enableIndexSeeking"; - /** - * Sets the operation mode for TS parsing. {@code String} expected. Valid values are {@code - * "single_pmt"}, {@code "multi_pmt"}, and {@code "hls"}. Default value is {@code "single_pmt"}. - * - * <p>The operation modes alter the way TS behaves so that it can handle certain kinds of - * commonly-occurring malformed media. - * - * <ul> - * <li>{@code "single_pmt"}: Only the first found PMT is parsed. Others are ignored, even if - * more PMTs are declared in the PAT. - * <li>{@code "multi_pmt"}: Behave as described in ISO/IEC 13818-1. - * <li>{@code "hls"}: Enable {@code "single_pmt"} mode, and ignore continuity counters. - * </ul> - */ - public static final String PARAMETER_TS_MODE = "android.media.mediaparser.ts.mode"; - /** - * Sets whether TS should treat samples consisting of non-IDR I slices as synchronization - * samples (key-frames). {@code boolean} expected. Default value is {@code false}. - */ - public static final String PARAMETER_TS_ALLOW_NON_IDR_AVC_KEYFRAMES = - "android.media.mediaparser.ts.allowNonIdrAvcKeyframes"; - /** - * Sets whether TS parsing should ignore AAC elementary streams. {@code boolean} expected. - * Default value is {@code false}. - */ - public static final String PARAMETER_TS_IGNORE_AAC_STREAM = - "android.media.mediaparser.ts.ignoreAacStream"; - /** - * Sets whether TS parsing should ignore AVC elementary streams. {@code boolean} expected. - * Default value is {@code false}. - */ - public static final String PARAMETER_TS_IGNORE_AVC_STREAM = - "android.media.mediaparser.ts.ignoreAvcStream"; - /** - * Sets whether TS parsing should ignore splice information streams. {@code boolean} expected. - * Default value is {@code false}. - */ - public static final String PARAMETER_TS_IGNORE_SPLICE_INFO_STREAM = - "android.media.mediaparser.ts.ignoreSpliceInfoStream"; - /** - * Sets whether TS parsing should split AVC stream into access units based on slice headers. - * {@code boolean} expected. Default value is {@code false}. - * - * <p>This flag should be left disabled if the stream contains access units delimiters in order - * to avoid unnecessary computational costs. - */ - public static final String PARAMETER_TS_DETECT_ACCESS_UNITS = - "android.media.mediaparser.ts.ignoreDetectAccessUnits"; - /** - * Sets whether TS parsing should handle HDMV DTS audio streams. {@code boolean} expected. - * Default value is {@code false}. - * - * <p>Enabling this flag will disable the detection of SCTE subtitles. - */ - public static final String PARAMETER_TS_ENABLE_HDMV_DTS_AUDIO_STREAMS = - "android.media.mediaparser.ts.enableHdmvDtsAudioStreams"; - /** - * Sets whether encryption data should be sent in-band with the sample data, as per {@link - * OutputConsumer#onSampleDataFound}. {@code boolean} expected. Default value is {@code false}. - * - * <p>If this parameter is set, encrypted samples' data will be prefixed with the encryption - * information bytes. The format for in-band encryption information is: - * - * <ul> - * <li>(1 byte) {@code encryption_signal_byte}: Most significant bit signals whether the - * encryption data contains subsample encryption data. The remaining bits contain {@code - * initialization_vector_size}. - * <li>({@code initialization_vector_size} bytes) Initialization vector. - * <li>If subsample encryption data is present, as per {@code encryption_signal_byte}, the - * encryption data also contains: - * <ul> - * <li>(2 bytes) {@code subsample_encryption_data_length}. - * <li>({@code subsample_encryption_data_length * 6} bytes) Subsample encryption data - * (repeated {@code subsample_encryption_data_length} times): - * <ul> - * <li>(2 bytes) Size of a clear section in sample. - * <li>(4 bytes) Size of an encryption section in sample. - * </ul> - * </ul> - * </ul> - * - * @hide - */ - public static final String PARAMETER_IN_BAND_CRYPTO_INFO = - "android.media.mediaparser.inBandCryptoInfo"; - /** - * Sets whether supplemental data should be included as part of the sample data. {@code boolean} - * expected. Default value is {@code false}. See {@link #SAMPLE_FLAG_HAS_SUPPLEMENTAL_DATA} for - * information about the sample data format. - * - * @hide - */ - public static final String PARAMETER_INCLUDE_SUPPLEMENTAL_DATA = - "android.media.mediaparser.includeSupplementalData"; - /** - * Sets whether sample timestamps may start from non-zero offsets. {@code boolean} expected. - * Default value is {@code false}. - * - * <p>When set to true, sample timestamps will not be offset to start from zero, and the media - * provided timestamps will be used instead. For example, transport stream sample timestamps - * will not be converted to a zero-based timebase. - * - * @hide - */ - public static final String PARAMETER_IGNORE_TIMESTAMP_OFFSET = - "android.media.mediaparser.ignoreTimestampOffset"; - /** - * Sets whether each track type should be eagerly exposed. {@code boolean} expected. Default - * value is {@code false}. - * - * <p>When set to true, each track type will be eagerly exposed through a call to {@link - * OutputConsumer#onTrackDataFound} containing a single-value {@link MediaFormat}. The key for - * the track type is {@code "track-type-string"}, and the possible values are {@code "video"}, - * {@code "audio"}, {@code "text"}, {@code "metadata"}, and {@code "unknown"}. - * - * @hide - */ - public static final String PARAMETER_EAGERLY_EXPOSE_TRACKTYPE = - "android.media.mediaparser.eagerlyExposeTrackType"; - /** - * Sets whether a dummy {@link SeekMap} should be exposed before starting extraction. {@code - * boolean} expected. Default value is {@code false}. - * - * <p>For each {@link SeekMap#getSeekPoints} call, the dummy {@link SeekMap} returns a single - * {@link SeekPoint} whose {@link SeekPoint#timeMicros} matches the requested timestamp, and - * whose {@link SeekPoint#position} is 0. - * - * @hide - */ - public static final String PARAMETER_EXPOSE_DUMMY_SEEKMAP = - "android.media.mediaparser.exposeDummySeekMap"; - - /** - * Sets whether chunk indices available in the extracted media should be exposed as {@link - * MediaFormat MediaFormats}. {@code boolean} expected. Default value is {@link false}. - * - * <p>When set to true, any information about media segmentation will be exposed as a {@link - * MediaFormat} (with track index 0) containing four {@link ByteBuffer} elements under the - * following keys: - * - * <ul> - * <li>"chunk-index-int-sizes": Contains {@code ints} representing the sizes in bytes of each - * of the media segments. - * <li>"chunk-index-long-offsets": Contains {@code longs} representing the byte offsets of - * each segment in the stream. - * <li>"chunk-index-long-us-durations": Contains {@code longs} representing the media duration - * of each segment, in microseconds. - * <li>"chunk-index-long-us-times": Contains {@code longs} representing the start time of each - * segment, in microseconds. - * </ul> - * - * @hide - */ - public static final String PARAMETER_EXPOSE_CHUNK_INDEX_AS_MEDIA_FORMAT = - "android.media.mediaParser.exposeChunkIndexAsMediaFormat"; - /** - * Sets a list of closed-caption {@link MediaFormat MediaFormats} that should be exposed as part - * of the extracted media. {@code List<MediaFormat>} expected. Default value is an empty list. - * - * <p>Expected keys in the {@link MediaFormat} are: - * - * <ul> - * <p>{@link MediaFormat#KEY_MIME}: Determine the type of captions (for example, - * application/cea-608). Mandatory. - * <p>{@link MediaFormat#KEY_CAPTION_SERVICE_NUMBER}: Determine the channel on which the - * captions are transmitted. Optional. - * </ul> - * - * @hide - */ - public static final String PARAMETER_EXPOSE_CAPTION_FORMATS = - "android.media.mediaParser.exposeCaptionFormats"; - /** - * Sets whether the value associated with {@link #PARAMETER_EXPOSE_CAPTION_FORMATS} should - * override any in-band caption service declarations. {@code boolean} expected. Default value is - * {@link false}. - * - * <p>When {@code false}, any present in-band caption services information will override the - * values associated with {@link #PARAMETER_EXPOSE_CAPTION_FORMATS}. - * - * @hide - */ - public static final String PARAMETER_OVERRIDE_IN_BAND_CAPTION_DECLARATIONS = - "android.media.mediaParser.overrideInBandCaptionDeclarations"; - /** - * Sets whether a track for EMSG events should be exposed in case of parsing a container that - * supports them. {@code boolean} expected. Default value is {@link false}. - * - * @hide - */ - public static final String PARAMETER_EXPOSE_EMSG_TRACK = - "android.media.mediaParser.exposeEmsgTrack"; - - // Private constants. - - private static final String TAG = "MediaParser"; - private static final String JNI_LIBRARY_NAME = "mediaparser-jni"; - private static final Map<String, ExtractorFactory> EXTRACTOR_FACTORIES_BY_NAME; - private static final Map<String, Class> EXPECTED_TYPE_BY_PARAMETER_NAME; - private static final String TS_MODE_SINGLE_PMT = "single_pmt"; - private static final String TS_MODE_MULTI_PMT = "multi_pmt"; - private static final String TS_MODE_HLS = "hls"; - private static final int BYTES_PER_SUBSAMPLE_ENCRYPTION_ENTRY = 6; - private static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; - private static final String MEDIAMETRICS_ELEMENT_SEPARATOR = "|"; - private static final int MEDIAMETRICS_MAX_STRING_SIZE = 200; - private static final int MEDIAMETRICS_PARAMETER_LIST_MAX_LENGTH; - /** - * Intentional error introduced to reported metrics to prevent identification of the parsed - * media. Note: Increasing this value may cause older hostside CTS tests to fail. - */ - private static final float MEDIAMETRICS_DITHER = .02f; - - @IntDef( - value = { - STATE_READING_SIGNAL_BYTE, - STATE_READING_INIT_VECTOR, - STATE_READING_SUBSAMPLE_ENCRYPTION_SIZE, - STATE_READING_SUBSAMPLE_ENCRYPTION_DATA - }) - private @interface EncryptionDataReadState {} - - private static final int STATE_READING_SIGNAL_BYTE = 0; - private static final int STATE_READING_INIT_VECTOR = 1; - private static final int STATE_READING_SUBSAMPLE_ENCRYPTION_SIZE = 2; - private static final int STATE_READING_SUBSAMPLE_ENCRYPTION_DATA = 3; - - // Instance creation methods. - - /** - * Creates an instance backed by the parser with the given {@code name}. The returned instance - * will attempt parsing without sniffing the content. - * - * @param name The name of the parser that will be associated with the created instance. - * @param outputConsumer The {@link OutputConsumer} to which track data and samples are pushed. - * @return A new instance. - * @throws IllegalArgumentException If an invalid name is provided. - */ - @NonNull - public static MediaParser createByName( - @NonNull @ParserName String name, @NonNull OutputConsumer outputConsumer) { - String[] nameAsArray = new String[] {name}; - assertValidNames(nameAsArray); - return new MediaParser(outputConsumer, /* createdByName= */ true, name); - } - - /** - * Creates an instance whose backing parser will be selected by sniffing the content during the - * first {@link #advance} call. Parser implementations will sniff the content in order of - * appearance in {@code parserNames}. - * - * @param outputConsumer The {@link OutputConsumer} to which extracted data is output. - * @param parserNames The names of the parsers to sniff the content with. If empty, a default - * array of names is used. - * @return A new instance. - */ - @NonNull - public static MediaParser create( - @NonNull OutputConsumer outputConsumer, @NonNull @ParserName String... parserNames) { - assertValidNames(parserNames); - if (parserNames.length == 0) { - parserNames = EXTRACTOR_FACTORIES_BY_NAME.keySet().toArray(new String[0]); - } - return new MediaParser(outputConsumer, /* createdByName= */ false, parserNames); - } - - // Misc static methods. - - /** - * Returns an immutable list with the names of the parsers that are suitable for container - * formats with the given {@link MediaFormat}. - * - * <p>A parser supports a {@link MediaFormat} if the mime type associated with {@link - * MediaFormat#KEY_MIME} corresponds to the supported container format. - * - * @param mediaFormat The {@link MediaFormat} to check support for. - * @return The parser names that support the given {@code mediaFormat}, or the list of all - * parsers available if no container specific format information is provided. - */ - @NonNull - @ParserName - public static List<String> getParserNames(@NonNull MediaFormat mediaFormat) { - String mimeType = mediaFormat.getString(MediaFormat.KEY_MIME); - mimeType = mimeType == null ? null : Util.toLowerInvariant(mimeType.trim()); - if (TextUtils.isEmpty(mimeType)) { - // No MIME type provided. Return all. - return Collections.unmodifiableList( - new ArrayList<>(EXTRACTOR_FACTORIES_BY_NAME.keySet())); - } - ArrayList<String> result = new ArrayList<>(); - switch (mimeType) { - case "video/x-matroska": - case "audio/x-matroska": - case "video/x-webm": - case "audio/x-webm": - result.add(PARSER_NAME_MATROSKA); - break; - case "video/mp4": - case "audio/mp4": - case "application/mp4": - result.add(PARSER_NAME_MP4); - result.add(PARSER_NAME_FMP4); - break; - case "audio/mpeg": - result.add(PARSER_NAME_MP3); - break; - case "audio/aac": - result.add(PARSER_NAME_ADTS); - break; - case "audio/ac3": - result.add(PARSER_NAME_AC3); - break; - case "video/mp2t": - case "audio/mp2t": - result.add(PARSER_NAME_TS); - break; - case "video/x-flv": - result.add(PARSER_NAME_FLV); - break; - case "video/ogg": - case "audio/ogg": - case "application/ogg": - result.add(PARSER_NAME_OGG); - break; - case "video/mp2p": - case "video/mp1s": - result.add(PARSER_NAME_PS); - break; - case "audio/vnd.wave": - case "audio/wav": - case "audio/wave": - case "audio/x-wav": - result.add(PARSER_NAME_WAV); - break; - case "audio/amr": - result.add(PARSER_NAME_AMR); - break; - case "audio/ac4": - result.add(PARSER_NAME_AC4); - break; - case "audio/flac": - case "audio/x-flac": - result.add(PARSER_NAME_FLAC); - break; - default: - // No parsers support the given mime type. Do nothing. - break; - } - return Collections.unmodifiableList(result); - } - - // Private fields. - - private final Map<String, Object> mParserParameters; - private final OutputConsumer mOutputConsumer; - private final String[] mParserNamesPool; - private final PositionHolder mPositionHolder; - private final InputReadingDataReader mExoDataReader; - private final DataReaderAdapter mScratchDataReaderAdapter; - private final ParsableByteArrayAdapter mScratchParsableByteArrayAdapter; - @Nullable private final Constructor<DrmInitData.SchemeInitData> mSchemeInitDataConstructor; - private final ArrayList<Format> mMuxedCaptionFormats; - private boolean mInBandCryptoInfo; - private boolean mIncludeSupplementalData; - private boolean mIgnoreTimestampOffset; - private boolean mEagerlyExposeTrackType; - private boolean mExposeDummySeekMap; - private boolean mExposeChunkIndexAsMediaFormat; - private String mParserName; - private Extractor mExtractor; - private ExtractorInput mExtractorInput; - private boolean mPendingExtractorInit; - private long mPendingSeekPosition; - private long mPendingSeekTimeMicros; - private boolean mLoggedSchemeInitDataCreationException; - private boolean mReleased; - - // MediaMetrics fields. - @Nullable private LogSessionId mLogSessionId; - private final boolean mCreatedByName; - private final SparseArray<Format> mTrackFormats; - private String mLastObservedExceptionName; - private long mDurationMillis; - private long mResourceByteCount; - - // Public methods. - - /** - * Sets parser-specific parameters which allow customizing behavior. - * - * <p>Must be called before the first call to {@link #advance}. - * - * @param parameterName The name of the parameter to set. See {@code PARAMETER_*} constants for - * documentation on possible values. - * @param value The value to set for the given {@code parameterName}. See {@code PARAMETER_*} - * constants for documentation on the expected types. - * @return This instance, for convenience. - * @throws IllegalStateException If called after calling {@link #advance} on the same instance. - */ - @NonNull - public MediaParser setParameter( - @NonNull @ParameterName String parameterName, @NonNull Object value) { - if (mExtractor != null) { - throw new IllegalStateException( - "setParameters() must be called before the first advance() call."); - } - Class expectedType = EXPECTED_TYPE_BY_PARAMETER_NAME.get(parameterName); - // Ignore parameter names that are not contained in the map, in case the client is passing - // a parameter that is being added in a future version of this library. - if (expectedType != null && !expectedType.isInstance(value)) { - throw new IllegalArgumentException( - parameterName - + " expects a " - + expectedType.getSimpleName() - + " but a " - + value.getClass().getSimpleName() - + " was passed."); - } - if (PARAMETER_TS_MODE.equals(parameterName) - && !TS_MODE_SINGLE_PMT.equals(value) - && !TS_MODE_HLS.equals(value) - && !TS_MODE_MULTI_PMT.equals(value)) { - throw new IllegalArgumentException(PARAMETER_TS_MODE + " does not accept: " + value); - } - if (PARAMETER_IN_BAND_CRYPTO_INFO.equals(parameterName)) { - mInBandCryptoInfo = (boolean) value; - } - if (PARAMETER_INCLUDE_SUPPLEMENTAL_DATA.equals(parameterName)) { - mIncludeSupplementalData = (boolean) value; - } - if (PARAMETER_IGNORE_TIMESTAMP_OFFSET.equals(parameterName)) { - mIgnoreTimestampOffset = (boolean) value; - } - if (PARAMETER_EAGERLY_EXPOSE_TRACKTYPE.equals(parameterName)) { - mEagerlyExposeTrackType = (boolean) value; - } - if (PARAMETER_EXPOSE_DUMMY_SEEKMAP.equals(parameterName)) { - mExposeDummySeekMap = (boolean) value; - } - if (PARAMETER_EXPOSE_CHUNK_INDEX_AS_MEDIA_FORMAT.equals(parameterName)) { - mExposeChunkIndexAsMediaFormat = (boolean) value; - } - if (PARAMETER_EXPOSE_CAPTION_FORMATS.equals(parameterName)) { - setMuxedCaptionFormats((List<MediaFormat>) value); - } - mParserParameters.put(parameterName, value); - return this; - } - - /** - * Returns whether the given {@code parameterName} is supported by this parser. - * - * @param parameterName The parameter name to check support for. One of the {@code PARAMETER_*} - * constants. - * @return Whether the given {@code parameterName} is supported. - */ - public boolean supportsParameter(@NonNull @ParameterName String parameterName) { - return EXPECTED_TYPE_BY_PARAMETER_NAME.containsKey(parameterName); - } - - /** - * Returns the name of the backing parser implementation. - * - * <p>If this instance was creating using {@link #createByName}, the provided name is returned. - * If this instance was created using {@link #create}, this method will return {@link - * #PARSER_NAME_UNKNOWN} until the first call to {@link #advance}, after which the name of the - * backing parser implementation is returned. - * - * @return The name of the backing parser implementation, or null if the backing parser - * implementation has not yet been selected. - */ - @NonNull - @ParserName - public String getParserName() { - return mParserName; - } - - /** - * Makes progress in the extraction of the input media stream, unless the end of the input has - * been reached. - * - * <p>This method will block until some progress has been made. - * - * <p>If this instance was created using {@link #create}, the first call to this method will - * sniff the content using the selected parser implementations. - * - * @param seekableInputReader The {@link SeekableInputReader} from which to obtain the media - * container data. - * @return Whether there is any data left to extract. Returns false if the end of input has been - * reached. - * @throws IOException If an error occurs while reading from the {@link SeekableInputReader}. - * @throws UnrecognizedInputFormatException If the format cannot be recognized by any of the - * underlying parser implementations. - */ - public boolean advance(@NonNull SeekableInputReader seekableInputReader) throws IOException { - if (mExtractorInput == null) { - // TODO: For efficiency, the same implementation should be used, by providing a - // clearBuffers() method, or similar. - long resourceLength = seekableInputReader.getLength(); - if (mResourceByteCount == 0) { - // For resource byte count metric collection, we only take into account the length - // of the first provided input reader. - mResourceByteCount = resourceLength; - } - mExtractorInput = - new DefaultExtractorInput( - mExoDataReader, seekableInputReader.getPosition(), resourceLength); - } - mExoDataReader.mInputReader = seekableInputReader; - - if (mExtractor == null) { - mPendingExtractorInit = true; - if (!mParserName.equals(PARSER_NAME_UNKNOWN)) { - mExtractor = createExtractor(mParserName); - } else { - for (String parserName : mParserNamesPool) { - Extractor extractor = createExtractor(parserName); - try { - if (extractor.sniff(mExtractorInput)) { - mParserName = parserName; - mExtractor = extractor; - mPendingExtractorInit = true; - break; - } - } catch (EOFException e) { - // Do nothing. - } finally { - mExtractorInput.resetPeekPosition(); - } - } - if (mExtractor == null) { - UnrecognizedInputFormatException exception = - UnrecognizedInputFormatException.createForExtractors(mParserNamesPool); - mLastObservedExceptionName = exception.getClass().getName(); - throw exception; - } - return true; - } - } - - if (mPendingExtractorInit) { - if (mExposeDummySeekMap) { - // We propagate the dummy seek map before initializing the extractor, in case the - // extractor initialization outputs a seek map. - mOutputConsumer.onSeekMapFound(SeekMap.DUMMY); - } - mExtractor.init(new ExtractorOutputAdapter()); - mPendingExtractorInit = false; - // We return after initialization to allow clients use any output information before - // starting actual extraction. - return true; - } - - if (isPendingSeek()) { - mExtractor.seek(mPendingSeekPosition, mPendingSeekTimeMicros); - removePendingSeek(); - } - - mPositionHolder.position = seekableInputReader.getPosition(); - int result; - try { - result = mExtractor.read(mExtractorInput, mPositionHolder); - } catch (Exception e) { - mLastObservedExceptionName = e.getClass().getName(); - if (e instanceof ParserException) { - throw new ParsingException((ParserException) e); - } else { - throw e; - } - } - if (result == Extractor.RESULT_END_OF_INPUT) { - mExtractorInput = null; - return false; - } - if (result == Extractor.RESULT_SEEK) { - mExtractorInput = null; - seekableInputReader.seekToPosition(mPositionHolder.position); - } - return true; - } - - /** - * Seeks within the media container being extracted. - * - * <p>{@link SeekPoint SeekPoints} can be obtained from the {@link SeekMap} passed to {@link - * OutputConsumer#onSeekMapFound(SeekMap)}. - * - * <p>Following a call to this method, the {@link InputReader} passed to the next invocation of - * {@link #advance} must provide data starting from {@link SeekPoint#position} in the stream. - * - * @param seekPoint The {@link SeekPoint} to seek to. - */ - public void seek(@NonNull SeekPoint seekPoint) { - if (mExtractor == null) { - mPendingSeekPosition = seekPoint.position; - mPendingSeekTimeMicros = seekPoint.timeMicros; - } else { - mExtractor.seek(seekPoint.position, seekPoint.timeMicros); - } - } - - /** - * Releases any acquired resources. - * - * <p>After calling this method, this instance becomes unusable and no other methods should be - * invoked. - */ - public void release() { - mExtractorInput = null; - mExtractor = null; - if (mReleased) { - // Nothing to do. - return; - } - mReleased = true; - - String trackMimeTypes = buildMediaMetricsString(format -> format.sampleMimeType); - String trackCodecs = buildMediaMetricsString(format -> format.codecs); - int videoWidth = -1; - int videoHeight = -1; - for (int i = 0; i < mTrackFormats.size(); i++) { - Format format = mTrackFormats.valueAt(i); - if (format.width != Format.NO_VALUE && format.height != Format.NO_VALUE) { - videoWidth = format.width; - videoHeight = format.height; - break; - } - } - - String alteredParameters = - String.join( - MEDIAMETRICS_ELEMENT_SEPARATOR, - mParserParameters.keySet().toArray(new String[0])); - alteredParameters = - alteredParameters.substring( - 0, - Math.min( - alteredParameters.length(), - MEDIAMETRICS_PARAMETER_LIST_MAX_LENGTH)); - - nativeSubmitMetrics( - SdkLevel.isAtLeastS() ? getLogSessionIdStringV31() : "", - mParserName, - mCreatedByName, - String.join(MEDIAMETRICS_ELEMENT_SEPARATOR, mParserNamesPool), - mLastObservedExceptionName, - addDither(mResourceByteCount), - addDither(mDurationMillis), - trackMimeTypes, - trackCodecs, - alteredParameters, - videoWidth, - videoHeight); - } - - @RequiresApi(31) - public void setLogSessionId(@NonNull LogSessionId logSessionId) { - this.mLogSessionId = Objects.requireNonNull(logSessionId); - } - - @RequiresApi(31) - @NonNull - public LogSessionId getLogSessionId() { - return mLogSessionId != null ? mLogSessionId : LogSessionId.LOG_SESSION_ID_NONE; - } - - // Private methods. - - private MediaParser( - OutputConsumer outputConsumer, boolean createdByName, String... parserNamesPool) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { - throw new UnsupportedOperationException("Android version must be R or greater."); - } - mParserParameters = new HashMap<>(); - mOutputConsumer = outputConsumer; - mParserNamesPool = parserNamesPool; - mCreatedByName = createdByName; - mParserName = createdByName ? parserNamesPool[0] : PARSER_NAME_UNKNOWN; - mPositionHolder = new PositionHolder(); - mExoDataReader = new InputReadingDataReader(); - removePendingSeek(); - mScratchDataReaderAdapter = new DataReaderAdapter(); - mScratchParsableByteArrayAdapter = new ParsableByteArrayAdapter(); - mSchemeInitDataConstructor = getSchemeInitDataConstructor(); - mMuxedCaptionFormats = new ArrayList<>(); - - // MediaMetrics. - mTrackFormats = new SparseArray<>(); - mLastObservedExceptionName = ""; - mDurationMillis = -1; - } - - private String buildMediaMetricsString(Function<Format, String> formatFieldGetter) { - StringBuilder stringBuilder = new StringBuilder(); - for (int i = 0; i < mTrackFormats.size(); i++) { - if (i > 0) { - stringBuilder.append(MEDIAMETRICS_ELEMENT_SEPARATOR); - } - String fieldValue = formatFieldGetter.apply(mTrackFormats.valueAt(i)); - stringBuilder.append(fieldValue != null ? fieldValue : ""); - } - return stringBuilder.substring( - 0, Math.min(stringBuilder.length(), MEDIAMETRICS_MAX_STRING_SIZE)); - } - - private void setMuxedCaptionFormats(List<MediaFormat> mediaFormats) { - mMuxedCaptionFormats.clear(); - for (MediaFormat mediaFormat : mediaFormats) { - mMuxedCaptionFormats.add(toExoPlayerCaptionFormat(mediaFormat)); - } - } - - private boolean isPendingSeek() { - return mPendingSeekPosition >= 0; - } - - private void removePendingSeek() { - mPendingSeekPosition = -1; - mPendingSeekTimeMicros = -1; - } - - private Extractor createExtractor(String parserName) { - int flags = 0; - TimestampAdjuster timestampAdjuster = null; - if (mIgnoreTimestampOffset) { - timestampAdjuster = new TimestampAdjuster(TimestampAdjuster.DO_NOT_OFFSET); - } - switch (parserName) { - case PARSER_NAME_MATROSKA: - flags = - getBooleanParameter(PARAMETER_MATROSKA_DISABLE_CUES_SEEKING) - ? MatroskaExtractor.FLAG_DISABLE_SEEK_FOR_CUES - : 0; - return new MatroskaExtractor(flags); - case PARSER_NAME_FMP4: - flags |= - getBooleanParameter(PARAMETER_EXPOSE_EMSG_TRACK) - ? FragmentedMp4Extractor.FLAG_ENABLE_EMSG_TRACK - : 0; - flags |= - getBooleanParameter(PARAMETER_MP4_IGNORE_EDIT_LISTS) - ? FragmentedMp4Extractor.FLAG_WORKAROUND_IGNORE_EDIT_LISTS - : 0; - flags |= - getBooleanParameter(PARAMETER_MP4_IGNORE_TFDT_BOX) - ? FragmentedMp4Extractor.FLAG_WORKAROUND_IGNORE_TFDT_BOX - : 0; - flags |= - getBooleanParameter(PARAMETER_MP4_TREAT_VIDEO_FRAMES_AS_KEYFRAMES) - ? FragmentedMp4Extractor - .FLAG_WORKAROUND_EVERY_VIDEO_FRAME_IS_SYNC_FRAME - : 0; - return new FragmentedMp4Extractor( - flags, - timestampAdjuster, - /* sideloadedTrack= */ null, - mMuxedCaptionFormats); - case PARSER_NAME_MP4: - flags |= - getBooleanParameter(PARAMETER_MP4_IGNORE_EDIT_LISTS) - ? Mp4Extractor.FLAG_WORKAROUND_IGNORE_EDIT_LISTS - : 0; - return new Mp4Extractor(flags); - case PARSER_NAME_MP3: - flags |= - getBooleanParameter(PARAMETER_MP3_DISABLE_ID3) - ? Mp3Extractor.FLAG_DISABLE_ID3_METADATA - : 0; - flags |= - getBooleanParameter(PARAMETER_MP3_ENABLE_CBR_SEEKING) - ? Mp3Extractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING - : 0; - // TODO: Add index seeking once we update the ExoPlayer version. - return new Mp3Extractor(flags); - case PARSER_NAME_ADTS: - flags |= - getBooleanParameter(PARAMETER_ADTS_ENABLE_CBR_SEEKING) - ? AdtsExtractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING - : 0; - return new AdtsExtractor(flags); - case PARSER_NAME_AC3: - return new Ac3Extractor(); - case PARSER_NAME_TS: - flags |= - getBooleanParameter(PARAMETER_TS_ALLOW_NON_IDR_AVC_KEYFRAMES) - ? DefaultTsPayloadReaderFactory.FLAG_ALLOW_NON_IDR_KEYFRAMES - : 0; - flags |= - getBooleanParameter(PARAMETER_TS_DETECT_ACCESS_UNITS) - ? DefaultTsPayloadReaderFactory.FLAG_DETECT_ACCESS_UNITS - : 0; - flags |= - getBooleanParameter(PARAMETER_TS_ENABLE_HDMV_DTS_AUDIO_STREAMS) - ? DefaultTsPayloadReaderFactory.FLAG_ENABLE_HDMV_DTS_AUDIO_STREAMS - : 0; - flags |= - getBooleanParameter(PARAMETER_TS_IGNORE_AAC_STREAM) - ? DefaultTsPayloadReaderFactory.FLAG_IGNORE_AAC_STREAM - : 0; - flags |= - getBooleanParameter(PARAMETER_TS_IGNORE_AVC_STREAM) - ? DefaultTsPayloadReaderFactory.FLAG_IGNORE_H264_STREAM - : 0; - flags |= - getBooleanParameter(PARAMETER_TS_IGNORE_SPLICE_INFO_STREAM) - ? DefaultTsPayloadReaderFactory.FLAG_IGNORE_SPLICE_INFO_STREAM - : 0; - flags |= - getBooleanParameter(PARAMETER_OVERRIDE_IN_BAND_CAPTION_DECLARATIONS) - ? DefaultTsPayloadReaderFactory.FLAG_OVERRIDE_CAPTION_DESCRIPTORS - : 0; - String tsMode = getStringParameter(PARAMETER_TS_MODE, TS_MODE_SINGLE_PMT); - int hlsMode = - TS_MODE_SINGLE_PMT.equals(tsMode) - ? TsExtractor.MODE_SINGLE_PMT - : TS_MODE_HLS.equals(tsMode) - ? TsExtractor.MODE_HLS - : TsExtractor.MODE_MULTI_PMT; - return new TsExtractor( - hlsMode, - timestampAdjuster != null - ? timestampAdjuster - : new TimestampAdjuster(/* firstSampleTimestampUs= */ 0), - new DefaultTsPayloadReaderFactory(flags, mMuxedCaptionFormats)); - case PARSER_NAME_FLV: - return new FlvExtractor(); - case PARSER_NAME_OGG: - return new OggExtractor(); - case PARSER_NAME_PS: - return new PsExtractor(); - case PARSER_NAME_WAV: - return new WavExtractor(); - case PARSER_NAME_AMR: - flags |= - getBooleanParameter(PARAMETER_AMR_ENABLE_CBR_SEEKING) - ? AmrExtractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING - : 0; - return new AmrExtractor(flags); - case PARSER_NAME_AC4: - return new Ac4Extractor(); - case PARSER_NAME_FLAC: - flags |= - getBooleanParameter(PARAMETER_FLAC_DISABLE_ID3) - ? FlacExtractor.FLAG_DISABLE_ID3_METADATA - : 0; - return new FlacExtractor(flags); - default: - // Should never happen. - throw new IllegalStateException("Unexpected attempt to create: " + parserName); - } - } - - private boolean getBooleanParameter(String name) { - return (boolean) mParserParameters.getOrDefault(name, false); - } - - private String getStringParameter(String name, String defaultValue) { - return (String) mParserParameters.getOrDefault(name, defaultValue); - } - - @RequiresApi(31) - private String getLogSessionIdStringV31() { - return mLogSessionId != null ? mLogSessionId.getStringId() : ""; - } - - // Private classes. - - private static final class InputReadingDataReader implements DataReader { - - public InputReader mInputReader; - - @Override - public int read(byte[] buffer, int offset, int readLength) throws IOException { - return mInputReader.read(buffer, offset, readLength); - } - } - - private final class MediaParserDrmInitData extends DrmInitData { - - private final SchemeInitData[] mSchemeDatas; - - private MediaParserDrmInitData(com.google.android.exoplayer2.drm.DrmInitData exoDrmInitData) - throws IllegalAccessException, InstantiationException, InvocationTargetException { - mSchemeDatas = new SchemeInitData[exoDrmInitData.schemeDataCount]; - for (int i = 0; i < mSchemeDatas.length; i++) { - mSchemeDatas[i] = toFrameworkSchemeInitData(exoDrmInitData.get(i)); - } - } - - @Override - @Nullable - public SchemeInitData get(UUID schemeUuid) { - for (SchemeInitData schemeInitData : mSchemeDatas) { - if (schemeInitData.uuid.equals(schemeUuid)) { - return schemeInitData; - } - } - return null; - } - - @Override - public SchemeInitData getSchemeInitDataAt(int index) { - return mSchemeDatas[index]; - } - - @Override - public int getSchemeInitDataCount() { - return mSchemeDatas.length; - } - - private DrmInitData.SchemeInitData toFrameworkSchemeInitData(SchemeData exoSchemeData) - throws IllegalAccessException, InvocationTargetException, InstantiationException { - return mSchemeInitDataConstructor.newInstance( - exoSchemeData.uuid, exoSchemeData.mimeType, exoSchemeData.data); - } - } - - private final class ExtractorOutputAdapter implements ExtractorOutput { - - private final SparseArray<TrackOutput> mTrackOutputAdapters; - private boolean mTracksEnded; - - private ExtractorOutputAdapter() { - mTrackOutputAdapters = new SparseArray<>(); - } - - @Override - public TrackOutput track(int id, int type) { - TrackOutput trackOutput = mTrackOutputAdapters.get(id); - if (trackOutput == null) { - int trackIndex = mTrackOutputAdapters.size(); - trackOutput = new TrackOutputAdapter(trackIndex); - mTrackOutputAdapters.put(id, trackOutput); - if (mEagerlyExposeTrackType) { - MediaFormat mediaFormat = new MediaFormat(); - mediaFormat.setString("track-type-string", toTypeString(type)); - mOutputConsumer.onTrackDataFound( - trackIndex, new TrackData(mediaFormat, /* drmInitData= */ null)); - } - } - return trackOutput; - } - - @Override - public void endTracks() { - mOutputConsumer.onTrackCountFound(mTrackOutputAdapters.size()); - } - - @Override - public void seekMap(com.google.android.exoplayer2.extractor.SeekMap exoplayerSeekMap) { - long durationUs = exoplayerSeekMap.getDurationUs(); - if (durationUs != C.TIME_UNSET) { - mDurationMillis = C.usToMs(durationUs); - } - if (mExposeChunkIndexAsMediaFormat && exoplayerSeekMap instanceof ChunkIndex) { - ChunkIndex chunkIndex = (ChunkIndex) exoplayerSeekMap; - MediaFormat mediaFormat = new MediaFormat(); - mediaFormat.setByteBuffer("chunk-index-int-sizes", toByteBuffer(chunkIndex.sizes)); - mediaFormat.setByteBuffer( - "chunk-index-long-offsets", toByteBuffer(chunkIndex.offsets)); - mediaFormat.setByteBuffer( - "chunk-index-long-us-durations", toByteBuffer(chunkIndex.durationsUs)); - mediaFormat.setByteBuffer( - "chunk-index-long-us-times", toByteBuffer(chunkIndex.timesUs)); - mOutputConsumer.onTrackDataFound( - /* trackIndex= */ 0, new TrackData(mediaFormat, /* drmInitData= */ null)); - } - mOutputConsumer.onSeekMapFound(new SeekMap(exoplayerSeekMap)); - } - } - - private class TrackOutputAdapter implements TrackOutput { - - private final int mTrackIndex; - - private CryptoInfo mLastOutputCryptoInfo; - private CryptoInfo.Pattern mLastOutputEncryptionPattern; - private CryptoData mLastReceivedCryptoData; - - @EncryptionDataReadState private int mEncryptionDataReadState; - private int mEncryptionDataSizeToSubtractFromSampleDataSize; - private int mEncryptionVectorSize; - private byte[] mScratchIvSpace; - private int mSubsampleEncryptionDataSize; - private int[] mScratchSubsampleEncryptedBytesCount; - private int[] mScratchSubsampleClearBytesCount; - private boolean mHasSubsampleEncryptionData; - private int mSkippedSupplementalDataBytes; - - private TrackOutputAdapter(int trackIndex) { - mTrackIndex = trackIndex; - mScratchIvSpace = new byte[16]; // Size documented in CryptoInfo. - mScratchSubsampleEncryptedBytesCount = new int[32]; - mScratchSubsampleClearBytesCount = new int[32]; - mEncryptionDataReadState = STATE_READING_SIGNAL_BYTE; - mLastOutputEncryptionPattern = - new CryptoInfo.Pattern(/* blocksToEncrypt= */ 0, /* blocksToSkip= */ 0); - } - - @Override - public void format(Format format) { - mTrackFormats.put(mTrackIndex, format); - mOutputConsumer.onTrackDataFound( - mTrackIndex, - new TrackData( - toMediaFormat(format), toFrameworkDrmInitData(format.drmInitData))); - } - - @Override - public int sampleData( - DataReader input, - int length, - boolean allowEndOfInput, - @SampleDataPart int sampleDataPart) - throws IOException { - mScratchDataReaderAdapter.setDataReader(input, length); - long positionBeforeReading = mScratchDataReaderAdapter.getPosition(); - mOutputConsumer.onSampleDataFound(mTrackIndex, mScratchDataReaderAdapter); - return (int) (mScratchDataReaderAdapter.getPosition() - positionBeforeReading); - } - - @Override - public void sampleData( - ParsableByteArray data, int length, @SampleDataPart int sampleDataPart) { - if (sampleDataPart == SAMPLE_DATA_PART_ENCRYPTION && !mInBandCryptoInfo) { - while (length > 0) { - switch (mEncryptionDataReadState) { - case STATE_READING_SIGNAL_BYTE: - int encryptionSignalByte = data.readUnsignedByte(); - length--; - mHasSubsampleEncryptionData = ((encryptionSignalByte >> 7) & 1) != 0; - mEncryptionVectorSize = encryptionSignalByte & 0x7F; - mEncryptionDataSizeToSubtractFromSampleDataSize = - mEncryptionVectorSize + 1; // Signal byte. - mEncryptionDataReadState = STATE_READING_INIT_VECTOR; - break; - case STATE_READING_INIT_VECTOR: - Arrays.fill(mScratchIvSpace, (byte) 0); // Ensure 0-padding. - data.readBytes(mScratchIvSpace, /* offset= */ 0, mEncryptionVectorSize); - length -= mEncryptionVectorSize; - if (mHasSubsampleEncryptionData) { - mEncryptionDataReadState = STATE_READING_SUBSAMPLE_ENCRYPTION_SIZE; - } else { - mSubsampleEncryptionDataSize = 0; - mEncryptionDataReadState = STATE_READING_SIGNAL_BYTE; - } - break; - case STATE_READING_SUBSAMPLE_ENCRYPTION_SIZE: - mSubsampleEncryptionDataSize = data.readUnsignedShort(); - if (mScratchSubsampleClearBytesCount.length - < mSubsampleEncryptionDataSize) { - mScratchSubsampleClearBytesCount = - new int[mSubsampleEncryptionDataSize]; - mScratchSubsampleEncryptedBytesCount = - new int[mSubsampleEncryptionDataSize]; - } - length -= 2; - mEncryptionDataSizeToSubtractFromSampleDataSize += - 2 - + mSubsampleEncryptionDataSize - * BYTES_PER_SUBSAMPLE_ENCRYPTION_ENTRY; - mEncryptionDataReadState = STATE_READING_SUBSAMPLE_ENCRYPTION_DATA; - break; - case STATE_READING_SUBSAMPLE_ENCRYPTION_DATA: - for (int i = 0; i < mSubsampleEncryptionDataSize; i++) { - mScratchSubsampleClearBytesCount[i] = data.readUnsignedShort(); - mScratchSubsampleEncryptedBytesCount[i] = data.readInt(); - } - length -= - mSubsampleEncryptionDataSize - * BYTES_PER_SUBSAMPLE_ENCRYPTION_ENTRY; - mEncryptionDataReadState = STATE_READING_SIGNAL_BYTE; - if (length != 0) { - throw new IllegalStateException(); - } - break; - default: - // Never happens. - throw new IllegalStateException(); - } - } - } else if (sampleDataPart == SAMPLE_DATA_PART_SUPPLEMENTAL - && !mIncludeSupplementalData) { - mSkippedSupplementalDataBytes += length; - data.skipBytes(length); - } else { - outputSampleData(data, length); - } - } - - @Override - public void sampleMetadata( - long timeUs, int flags, int size, int offset, @Nullable CryptoData cryptoData) { - size -= mSkippedSupplementalDataBytes; - mSkippedSupplementalDataBytes = 0; - mOutputConsumer.onSampleCompleted( - mTrackIndex, - timeUs, - getMediaParserFlags(flags), - size - mEncryptionDataSizeToSubtractFromSampleDataSize, - offset, - getPopulatedCryptoInfo(cryptoData)); - mEncryptionDataReadState = STATE_READING_SIGNAL_BYTE; - mEncryptionDataSizeToSubtractFromSampleDataSize = 0; - } - - @Nullable - private CryptoInfo getPopulatedCryptoInfo(@Nullable CryptoData cryptoData) { - if (cryptoData == null) { - // The sample is not encrypted. - return null; - } else if (mInBandCryptoInfo) { - if (cryptoData != mLastReceivedCryptoData) { - mLastOutputCryptoInfo = - createNewCryptoInfoAndPopulateWithCryptoData(cryptoData); - // We are using in-band crypto info, so the IV will be ignored. But we prevent - // it from being null because toString assumes it non-null. - mLastOutputCryptoInfo.iv = EMPTY_BYTE_ARRAY; - } - } else /* We must populate the full CryptoInfo. */ { - // CryptoInfo.pattern is not accessible to the user, so the user needs to feed - // this CryptoInfo directly to MediaCodec. We need to create a new CryptoInfo per - // sample because of per-sample initialization vector changes. - CryptoInfo newCryptoInfo = createNewCryptoInfoAndPopulateWithCryptoData(cryptoData); - newCryptoInfo.iv = Arrays.copyOf(mScratchIvSpace, mScratchIvSpace.length); - boolean canReuseSubsampleInfo = - mLastOutputCryptoInfo != null - && mLastOutputCryptoInfo.numSubSamples - == mSubsampleEncryptionDataSize; - for (int i = 0; i < mSubsampleEncryptionDataSize && canReuseSubsampleInfo; i++) { - canReuseSubsampleInfo = - mLastOutputCryptoInfo.numBytesOfClearData[i] - == mScratchSubsampleClearBytesCount[i] - && mLastOutputCryptoInfo.numBytesOfEncryptedData[i] - == mScratchSubsampleEncryptedBytesCount[i]; - } - newCryptoInfo.numSubSamples = mSubsampleEncryptionDataSize; - if (canReuseSubsampleInfo) { - newCryptoInfo.numBytesOfClearData = mLastOutputCryptoInfo.numBytesOfClearData; - newCryptoInfo.numBytesOfEncryptedData = - mLastOutputCryptoInfo.numBytesOfEncryptedData; - } else { - newCryptoInfo.numBytesOfClearData = - Arrays.copyOf( - mScratchSubsampleClearBytesCount, mSubsampleEncryptionDataSize); - newCryptoInfo.numBytesOfEncryptedData = - Arrays.copyOf( - mScratchSubsampleEncryptedBytesCount, - mSubsampleEncryptionDataSize); - } - mLastOutputCryptoInfo = newCryptoInfo; - } - mLastReceivedCryptoData = cryptoData; - return mLastOutputCryptoInfo; - } - - private CryptoInfo createNewCryptoInfoAndPopulateWithCryptoData(CryptoData cryptoData) { - CryptoInfo cryptoInfo = new CryptoInfo(); - cryptoInfo.key = cryptoData.encryptionKey; - cryptoInfo.mode = cryptoData.cryptoMode; - if (cryptoData.clearBlocks != mLastOutputEncryptionPattern.getSkipBlocks() - || cryptoData.encryptedBlocks - != mLastOutputEncryptionPattern.getEncryptBlocks()) { - mLastOutputEncryptionPattern = - new CryptoInfo.Pattern(cryptoData.encryptedBlocks, cryptoData.clearBlocks); - } - cryptoInfo.setPattern(mLastOutputEncryptionPattern); - return cryptoInfo; - } - - private void outputSampleData(ParsableByteArray data, int length) { - mScratchParsableByteArrayAdapter.resetWithByteArray(data, length); - try { - // Read all bytes from data. ExoPlayer extractors expect all sample data to be - // consumed by TrackOutput implementations when passing a ParsableByteArray. - while (mScratchParsableByteArrayAdapter.getLength() > 0) { - mOutputConsumer.onSampleDataFound( - mTrackIndex, mScratchParsableByteArrayAdapter); - } - } catch (IOException e) { - // Unexpected. - throw new RuntimeException(e); - } - } - } - - private static final class DataReaderAdapter implements InputReader { - - private DataReader mDataReader; - private int mCurrentPosition; - private long mLength; - - public void setDataReader(DataReader dataReader, long length) { - mDataReader = dataReader; - mCurrentPosition = 0; - mLength = length; - } - - // Input implementation. - - @Override - public int read(byte[] buffer, int offset, int readLength) throws IOException { - int readBytes = 0; - readBytes = mDataReader.read(buffer, offset, readLength); - mCurrentPosition += readBytes; - return readBytes; - } - - @Override - public long getPosition() { - return mCurrentPosition; - } - - @Override - public long getLength() { - return mLength - mCurrentPosition; - } - } - - private static final class ParsableByteArrayAdapter implements InputReader { - - private ParsableByteArray mByteArray; - private long mLength; - private int mCurrentPosition; - - public void resetWithByteArray(ParsableByteArray byteArray, long length) { - mByteArray = byteArray; - mCurrentPosition = 0; - mLength = length; - } - - // Input implementation. - - @Override - public int read(byte[] buffer, int offset, int readLength) { - mByteArray.readBytes(buffer, offset, readLength); - mCurrentPosition += readLength; - return readLength; - } - - @Override - public long getPosition() { - return mCurrentPosition; - } - - @Override - public long getLength() { - return mLength - mCurrentPosition; - } - } - - private static final class DummyExoPlayerSeekMap - implements com.google.android.exoplayer2.extractor.SeekMap { - - @Override - public boolean isSeekable() { - return true; - } - - @Override - public long getDurationUs() { - return C.TIME_UNSET; - } - - @Override - public SeekPoints getSeekPoints(long timeUs) { - com.google.android.exoplayer2.extractor.SeekPoint seekPoint = - new com.google.android.exoplayer2.extractor.SeekPoint( - timeUs, /* position= */ 0); - return new SeekPoints(seekPoint, seekPoint); - } - } - - /** Creates extractor instances. */ - private interface ExtractorFactory { - - /** Returns a new extractor instance. */ - Extractor createInstance(); - } - - // Private static methods. - - private static Format toExoPlayerCaptionFormat(MediaFormat mediaFormat) { - Format.Builder formatBuilder = - new Format.Builder().setSampleMimeType(mediaFormat.getString(MediaFormat.KEY_MIME)); - if (mediaFormat.containsKey(MediaFormat.KEY_CAPTION_SERVICE_NUMBER)) { - formatBuilder.setAccessibilityChannel( - mediaFormat.getInteger(MediaFormat.KEY_CAPTION_SERVICE_NUMBER)); - } - return formatBuilder.build(); - } - - private static MediaFormat toMediaFormat(Format format) { - MediaFormat result = new MediaFormat(); - setOptionalMediaFormatInt(result, MediaFormat.KEY_BIT_RATE, format.bitrate); - setOptionalMediaFormatInt(result, MediaFormat.KEY_CHANNEL_COUNT, format.channelCount); - - ColorInfo colorInfo = format.colorInfo; - if (colorInfo != null) { - setOptionalMediaFormatInt( - result, MediaFormat.KEY_COLOR_TRANSFER, colorInfo.colorTransfer); - setOptionalMediaFormatInt(result, MediaFormat.KEY_COLOR_RANGE, colorInfo.colorRange); - setOptionalMediaFormatInt(result, MediaFormat.KEY_COLOR_STANDARD, colorInfo.colorSpace); - - if (format.colorInfo.hdrStaticInfo != null) { - result.setByteBuffer( - MediaFormat.KEY_HDR_STATIC_INFO, - ByteBuffer.wrap(format.colorInfo.hdrStaticInfo)); - } - } - - setOptionalMediaFormatString(result, MediaFormat.KEY_MIME, format.sampleMimeType); - setOptionalMediaFormatString(result, MediaFormat.KEY_CODECS_STRING, format.codecs); - if (format.frameRate != Format.NO_VALUE) { - result.setFloat(MediaFormat.KEY_FRAME_RATE, format.frameRate); - } - setOptionalMediaFormatInt(result, MediaFormat.KEY_WIDTH, format.width); - setOptionalMediaFormatInt(result, MediaFormat.KEY_HEIGHT, format.height); - - List<byte[]> initData = format.initializationData; - for (int i = 0; i < initData.size(); i++) { - result.setByteBuffer("csd-" + i, ByteBuffer.wrap(initData.get(i))); - } - setPcmEncoding(format, result); - setOptionalMediaFormatString(result, MediaFormat.KEY_LANGUAGE, format.language); - setOptionalMediaFormatInt(result, MediaFormat.KEY_MAX_INPUT_SIZE, format.maxInputSize); - setOptionalMediaFormatInt(result, MediaFormat.KEY_ROTATION, format.rotationDegrees); - setOptionalMediaFormatInt(result, MediaFormat.KEY_SAMPLE_RATE, format.sampleRate); - setOptionalMediaFormatInt( - result, MediaFormat.KEY_CAPTION_SERVICE_NUMBER, format.accessibilityChannel); - - int selectionFlags = format.selectionFlags; - result.setInteger( - MediaFormat.KEY_IS_AUTOSELECT, selectionFlags & C.SELECTION_FLAG_AUTOSELECT); - result.setInteger(MediaFormat.KEY_IS_DEFAULT, selectionFlags & C.SELECTION_FLAG_DEFAULT); - result.setInteger( - MediaFormat.KEY_IS_FORCED_SUBTITLE, selectionFlags & C.SELECTION_FLAG_FORCED); - - setOptionalMediaFormatInt(result, MediaFormat.KEY_ENCODER_DELAY, format.encoderDelay); - setOptionalMediaFormatInt(result, MediaFormat.KEY_ENCODER_PADDING, format.encoderPadding); - - if (format.pixelWidthHeightRatio != Format.NO_VALUE && format.pixelWidthHeightRatio != 0) { - int parWidth = 1; - int parHeight = 1; - if (format.pixelWidthHeightRatio < 1.0f) { - parHeight = 1 << 30; - parWidth = (int) (format.pixelWidthHeightRatio * parHeight); - } else if (format.pixelWidthHeightRatio > 1.0f) { - parWidth = 1 << 30; - parHeight = (int) (parWidth / format.pixelWidthHeightRatio); - } - result.setInteger(MediaFormat.KEY_PIXEL_ASPECT_RATIO_WIDTH, parWidth); - result.setInteger(MediaFormat.KEY_PIXEL_ASPECT_RATIO_HEIGHT, parHeight); - result.setFloat("pixel-width-height-ratio-float", format.pixelWidthHeightRatio); - } - if (format.drmInitData != null) { - // The crypto mode is propagated along with sample metadata. We also include it in the - // format for convenient use from ExoPlayer. - result.setString("crypto-mode-fourcc", format.drmInitData.schemeType); - } - if (format.subsampleOffsetUs != Format.OFFSET_SAMPLE_RELATIVE) { - result.setLong("subsample-offset-us-long", format.subsampleOffsetUs); - } - // LACK OF SUPPORT FOR: - // format.id; - // format.metadata; - // format.stereoMode; - return result; - } - - private static ByteBuffer toByteBuffer(long[] longArray) { - ByteBuffer byteBuffer = ByteBuffer.allocateDirect(longArray.length * Long.BYTES); - for (long element : longArray) { - byteBuffer.putLong(element); - } - byteBuffer.flip(); - return byteBuffer; - } - - private static ByteBuffer toByteBuffer(int[] intArray) { - ByteBuffer byteBuffer = ByteBuffer.allocateDirect(intArray.length * Integer.BYTES); - for (int element : intArray) { - byteBuffer.putInt(element); - } - byteBuffer.flip(); - return byteBuffer; - } - - private static String toTypeString(int type) { - switch (type) { - case C.TRACK_TYPE_VIDEO: - return "video"; - case C.TRACK_TYPE_AUDIO: - return "audio"; - case C.TRACK_TYPE_TEXT: - return "text"; - case C.TRACK_TYPE_METADATA: - return "metadata"; - default: - return "unknown"; - } - } - - private static void setPcmEncoding(Format format, MediaFormat result) { - int exoPcmEncoding = format.pcmEncoding; - setOptionalMediaFormatInt(result, "exo-pcm-encoding", format.pcmEncoding); - int mediaFormatPcmEncoding; - switch (exoPcmEncoding) { - case C.ENCODING_PCM_8BIT: - mediaFormatPcmEncoding = AudioFormat.ENCODING_PCM_8BIT; - break; - case C.ENCODING_PCM_16BIT: - mediaFormatPcmEncoding = AudioFormat.ENCODING_PCM_16BIT; - break; - case C.ENCODING_PCM_FLOAT: - mediaFormatPcmEncoding = AudioFormat.ENCODING_PCM_FLOAT; - break; - default: - // No matching value. Do nothing. - return; - } - result.setInteger(MediaFormat.KEY_PCM_ENCODING, mediaFormatPcmEncoding); - } - - private static void setOptionalMediaFormatInt(MediaFormat mediaFormat, String key, int value) { - if (value != Format.NO_VALUE) { - mediaFormat.setInteger(key, value); - } - } - - private static void setOptionalMediaFormatString( - MediaFormat mediaFormat, String key, @Nullable String value) { - if (value != null) { - mediaFormat.setString(key, value); - } - } - - private DrmInitData toFrameworkDrmInitData( - com.google.android.exoplayer2.drm.DrmInitData exoDrmInitData) { - try { - return exoDrmInitData != null && mSchemeInitDataConstructor != null - ? new MediaParserDrmInitData(exoDrmInitData) - : null; - } catch (Throwable e) { - if (!mLoggedSchemeInitDataCreationException) { - mLoggedSchemeInitDataCreationException = true; - Log.e(TAG, "Unable to create SchemeInitData instance."); - } - return null; - } - } - - /** Returns a new {@link SeekPoint} equivalent to the given {@code exoPlayerSeekPoint}. */ - private static SeekPoint toSeekPoint( - com.google.android.exoplayer2.extractor.SeekPoint exoPlayerSeekPoint) { - return new SeekPoint(exoPlayerSeekPoint.timeUs, exoPlayerSeekPoint.position); - } - - /** - * Introduces random error to the given metric value in order to prevent the identification of - * the parsed media. - */ - private static long addDither(long value) { - // Generate a random in [0, 1]. - double randomDither = ThreadLocalRandom.current().nextFloat(); - // Clamp the random number to [0, 2 * MEDIAMETRICS_DITHER]. - randomDither *= 2 * MEDIAMETRICS_DITHER; - // Translate the random number to [1 - MEDIAMETRICS_DITHER, 1 + MEDIAMETRICS_DITHER]. - randomDither += 1 - MEDIAMETRICS_DITHER; - return value != -1 ? (long) (value * randomDither) : -1; - } - - private static void assertValidNames(@NonNull String[] names) { - for (String name : names) { - if (!EXTRACTOR_FACTORIES_BY_NAME.containsKey(name)) { - throw new IllegalArgumentException( - "Invalid extractor name: " - + name - + ". Supported parsers are: " - + TextUtils.join(", ", EXTRACTOR_FACTORIES_BY_NAME.keySet()) - + "."); - } - } - } - - private int getMediaParserFlags(int flags) { - @SampleFlags int result = 0; - result |= (flags & C.BUFFER_FLAG_ENCRYPTED) != 0 ? SAMPLE_FLAG_ENCRYPTED : 0; - result |= (flags & C.BUFFER_FLAG_KEY_FRAME) != 0 ? SAMPLE_FLAG_KEY_FRAME : 0; - result |= (flags & C.BUFFER_FLAG_DECODE_ONLY) != 0 ? SAMPLE_FLAG_DECODE_ONLY : 0; - result |= - (flags & C.BUFFER_FLAG_HAS_SUPPLEMENTAL_DATA) != 0 && mIncludeSupplementalData - ? SAMPLE_FLAG_HAS_SUPPLEMENTAL_DATA - : 0; - result |= (flags & C.BUFFER_FLAG_LAST_SAMPLE) != 0 ? SAMPLE_FLAG_LAST_SAMPLE : 0; - return result; - } - - @Nullable - private static Constructor<DrmInitData.SchemeInitData> getSchemeInitDataConstructor() { - // TODO: Use constructor statically when available. - Constructor<DrmInitData.SchemeInitData> constructor; - try { - return DrmInitData.SchemeInitData.class.getConstructor( - UUID.class, String.class, byte[].class); - } catch (Throwable e) { - Log.e(TAG, "Unable to get SchemeInitData constructor."); - return null; - } - } - - // Native methods. - - private native void nativeSubmitMetrics( - String logSessionId, - String parserName, - boolean createdByName, - String parserPool, - String lastObservedExceptionName, - long resourceByteCount, - long durationMillis, - String trackMimeTypes, - String trackCodecs, - String alteredParameters, - int videoWidth, - int videoHeight); - - // Static initialization. - - static { - System.loadLibrary(JNI_LIBRARY_NAME); - - // Using a LinkedHashMap to keep the insertion order when iterating over the keys. - LinkedHashMap<String, ExtractorFactory> extractorFactoriesByName = new LinkedHashMap<>(); - // Parsers are ordered to match ExoPlayer's DefaultExtractorsFactory extractor ordering, - // which in turn aims to minimize the chances of incorrect extractor selections. - extractorFactoriesByName.put(PARSER_NAME_MATROSKA, MatroskaExtractor::new); - extractorFactoriesByName.put(PARSER_NAME_FMP4, FragmentedMp4Extractor::new); - extractorFactoriesByName.put(PARSER_NAME_MP4, Mp4Extractor::new); - extractorFactoriesByName.put(PARSER_NAME_MP3, Mp3Extractor::new); - extractorFactoriesByName.put(PARSER_NAME_ADTS, AdtsExtractor::new); - extractorFactoriesByName.put(PARSER_NAME_AC3, Ac3Extractor::new); - extractorFactoriesByName.put(PARSER_NAME_TS, TsExtractor::new); - extractorFactoriesByName.put(PARSER_NAME_FLV, FlvExtractor::new); - extractorFactoriesByName.put(PARSER_NAME_OGG, OggExtractor::new); - extractorFactoriesByName.put(PARSER_NAME_PS, PsExtractor::new); - extractorFactoriesByName.put(PARSER_NAME_WAV, WavExtractor::new); - extractorFactoriesByName.put(PARSER_NAME_AMR, AmrExtractor::new); - extractorFactoriesByName.put(PARSER_NAME_AC4, Ac4Extractor::new); - extractorFactoriesByName.put(PARSER_NAME_FLAC, FlacExtractor::new); - EXTRACTOR_FACTORIES_BY_NAME = Collections.unmodifiableMap(extractorFactoriesByName); - - HashMap<String, Class> expectedTypeByParameterName = new HashMap<>(); - expectedTypeByParameterName.put(PARAMETER_ADTS_ENABLE_CBR_SEEKING, Boolean.class); - expectedTypeByParameterName.put(PARAMETER_AMR_ENABLE_CBR_SEEKING, Boolean.class); - expectedTypeByParameterName.put(PARAMETER_FLAC_DISABLE_ID3, Boolean.class); - expectedTypeByParameterName.put(PARAMETER_MP4_IGNORE_EDIT_LISTS, Boolean.class); - expectedTypeByParameterName.put(PARAMETER_MP4_IGNORE_TFDT_BOX, Boolean.class); - expectedTypeByParameterName.put( - PARAMETER_MP4_TREAT_VIDEO_FRAMES_AS_KEYFRAMES, Boolean.class); - expectedTypeByParameterName.put(PARAMETER_MATROSKA_DISABLE_CUES_SEEKING, Boolean.class); - expectedTypeByParameterName.put(PARAMETER_MP3_DISABLE_ID3, Boolean.class); - expectedTypeByParameterName.put(PARAMETER_MP3_ENABLE_CBR_SEEKING, Boolean.class); - expectedTypeByParameterName.put(PARAMETER_MP3_ENABLE_INDEX_SEEKING, Boolean.class); - expectedTypeByParameterName.put(PARAMETER_TS_MODE, String.class); - expectedTypeByParameterName.put(PARAMETER_TS_ALLOW_NON_IDR_AVC_KEYFRAMES, Boolean.class); - expectedTypeByParameterName.put(PARAMETER_TS_IGNORE_AAC_STREAM, Boolean.class); - expectedTypeByParameterName.put(PARAMETER_TS_IGNORE_AVC_STREAM, Boolean.class); - expectedTypeByParameterName.put(PARAMETER_TS_IGNORE_SPLICE_INFO_STREAM, Boolean.class); - expectedTypeByParameterName.put(PARAMETER_TS_DETECT_ACCESS_UNITS, Boolean.class); - expectedTypeByParameterName.put(PARAMETER_TS_ENABLE_HDMV_DTS_AUDIO_STREAMS, Boolean.class); - expectedTypeByParameterName.put(PARAMETER_IN_BAND_CRYPTO_INFO, Boolean.class); - expectedTypeByParameterName.put(PARAMETER_INCLUDE_SUPPLEMENTAL_DATA, Boolean.class); - expectedTypeByParameterName.put(PARAMETER_IGNORE_TIMESTAMP_OFFSET, Boolean.class); - expectedTypeByParameterName.put(PARAMETER_EAGERLY_EXPOSE_TRACKTYPE, Boolean.class); - expectedTypeByParameterName.put(PARAMETER_EXPOSE_DUMMY_SEEKMAP, Boolean.class); - expectedTypeByParameterName.put( - PARAMETER_EXPOSE_CHUNK_INDEX_AS_MEDIA_FORMAT, Boolean.class); - expectedTypeByParameterName.put( - PARAMETER_OVERRIDE_IN_BAND_CAPTION_DECLARATIONS, Boolean.class); - expectedTypeByParameterName.put(PARAMETER_EXPOSE_EMSG_TRACK, Boolean.class); - // We do not check PARAMETER_EXPOSE_CAPTION_FORMATS here, and we do it in setParameters - // instead. Checking that the value is a List is insufficient to catch wrong parameter - // value types. - int sumOfParameterNameLengths = - expectedTypeByParameterName.keySet().stream() - .map(String::length) - .reduce(0, Integer::sum); - sumOfParameterNameLengths += PARAMETER_EXPOSE_CAPTION_FORMATS.length(); - // Add space for any required separators. - MEDIAMETRICS_PARAMETER_LIST_MAX_LENGTH = - sumOfParameterNameLengths + expectedTypeByParameterName.size(); - - EXPECTED_TYPE_BY_PARAMETER_NAME = Collections.unmodifiableMap(expectedTypeByParameterName); - } -} diff --git a/apex/media/framework/java/android/media/MediaSession2.java b/apex/media/framework/java/android/media/MediaSession2.java deleted file mode 100644 index e76d61cf8965..000000000000 --- a/apex/media/framework/java/android/media/MediaSession2.java +++ /dev/null @@ -1,931 +0,0 @@ -/* - * Copyright 2018 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 android.media; - -import static android.media.MediaConstants.KEY_ALLOWED_COMMANDS; -import static android.media.MediaConstants.KEY_CONNECTION_HINTS; -import static android.media.MediaConstants.KEY_PACKAGE_NAME; -import static android.media.MediaConstants.KEY_PID; -import static android.media.MediaConstants.KEY_PLAYBACK_ACTIVE; -import static android.media.MediaConstants.KEY_SESSION2LINK; -import static android.media.MediaConstants.KEY_TOKEN_EXTRAS; -import static android.media.Session2Command.Result.RESULT_ERROR_UNKNOWN_ERROR; -import static android.media.Session2Command.Result.RESULT_INFO_SKIPPED; -import static android.media.Session2Token.TYPE_SESSION; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.media.session.MediaSessionManager; -import android.media.session.MediaSessionManager.RemoteUserInfo; -import android.os.BadParcelableException; -import android.os.Bundle; -import android.os.Handler; -import android.os.Parcel; -import android.os.Process; -import android.os.ResultReceiver; -import android.util.ArrayMap; -import android.util.ArraySet; -import android.util.Log; - -import com.android.modules.utils.build.SdkLevel; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.Executor; - -/** - * This API is not generally intended for third party application developers. - * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a> - * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session - * Library</a> for consistent behavior across all devices. - * <p> - * Allows a media app to expose its transport controls and playback information in a process to - * other processes including the Android framework and other apps. - */ -public class MediaSession2 implements AutoCloseable { - static final String TAG = "MediaSession2"; - static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - - // Note: This checks the uniqueness of a session ID only in a single process. - // When the framework becomes able to check the uniqueness, this logic should be removed. - //@GuardedBy("MediaSession.class") - private static final List<String> SESSION_ID_LIST = new ArrayList<>(); - - @SuppressWarnings("WeakerAccess") /* synthetic access */ - final Object mLock = new Object(); - //@GuardedBy("mLock") - @SuppressWarnings("WeakerAccess") /* synthetic access */ - final Map<Controller2Link, ControllerInfo> mConnectedControllers = new HashMap<>(); - - @SuppressWarnings("WeakerAccess") /* synthetic access */ - final Context mContext; - @SuppressWarnings("WeakerAccess") /* synthetic access */ - final Executor mCallbackExecutor; - @SuppressWarnings("WeakerAccess") /* synthetic access */ - final SessionCallback mCallback; - @SuppressWarnings("WeakerAccess") /* synthetic access */ - final Session2Link mSessionStub; - - private final String mSessionId; - private final PendingIntent mSessionActivity; - private final Session2Token mSessionToken; - private final MediaSessionManager mMediaSessionManager; - private final MediaCommunicationManager mCommunicationManager; - private final Handler mResultHandler; - - //@GuardedBy("mLock") - private boolean mClosed; - //@GuardedBy("mLock") - private boolean mPlaybackActive; - //@GuardedBy("mLock") - private ForegroundServiceEventCallback mForegroundServiceEventCallback; - - MediaSession2(@NonNull Context context, @NonNull String id, PendingIntent sessionActivity, - @NonNull Executor callbackExecutor, @NonNull SessionCallback callback, - @NonNull Bundle tokenExtras) { - synchronized (MediaSession2.class) { - if (SESSION_ID_LIST.contains(id)) { - throw new IllegalStateException("Session ID must be unique. ID=" + id); - } - SESSION_ID_LIST.add(id); - } - - mContext = context; - mSessionId = id; - mSessionActivity = sessionActivity; - mCallbackExecutor = callbackExecutor; - mCallback = callback; - mSessionStub = new Session2Link(this); - mSessionToken = new Session2Token(Process.myUid(), TYPE_SESSION, context.getPackageName(), - mSessionStub, tokenExtras); - if (SdkLevel.isAtLeastS()) { - mCommunicationManager = mContext.getSystemService(MediaCommunicationManager.class); - mMediaSessionManager = null; - } else { - mMediaSessionManager = mContext.getSystemService(MediaSessionManager.class); - mCommunicationManager = null; - } - // NOTE: mResultHandler uses main looper, so this MUST NOT be blocked. - mResultHandler = new Handler(context.getMainLooper()); - mClosed = false; - } - - @Override - public void close() { - try { - List<ControllerInfo> controllerInfos; - ForegroundServiceEventCallback callback; - synchronized (mLock) { - if (mClosed) { - return; - } - mClosed = true; - controllerInfos = getConnectedControllers(); - mConnectedControllers.clear(); - callback = mForegroundServiceEventCallback; - mForegroundServiceEventCallback = null; - } - synchronized (MediaSession2.class) { - SESSION_ID_LIST.remove(mSessionId); - } - if (callback != null) { - callback.onSessionClosed(this); - } - for (ControllerInfo info : controllerInfos) { - info.notifyDisconnected(); - } - } catch (Exception e) { - // Should not be here. - } - } - - /** - * Returns the session ID - */ - @NonNull - public String getId() { - return mSessionId; - } - - /** - * Returns the {@link Session2Token} for creating {@link MediaController2}. - */ - @NonNull - public Session2Token getToken() { - return mSessionToken; - } - - /** - * Broadcasts a session command to all the connected controllers - * <p> - * @param command the session command - * @param args optional arguments - */ - public void broadcastSessionCommand(@NonNull Session2Command command, @Nullable Bundle args) { - if (command == null) { - throw new IllegalArgumentException("command shouldn't be null"); - } - List<ControllerInfo> controllerInfos = getConnectedControllers(); - for (ControllerInfo controller : controllerInfos) { - controller.sendSessionCommand(command, args, null); - } - } - - /** - * Sends a session command to a specific controller - * <p> - * @param controller the controller to get the session command - * @param command the session command - * @param args optional arguments - * @return a token which will be sent together in {@link SessionCallback#onCommandResult} - * when its result is received. - */ - @NonNull - public Object sendSessionCommand(@NonNull ControllerInfo controller, - @NonNull Session2Command command, @Nullable Bundle args) { - if (controller == null) { - throw new IllegalArgumentException("controller shouldn't be null"); - } - if (command == null) { - throw new IllegalArgumentException("command shouldn't be null"); - } - ResultReceiver resultReceiver = new ResultReceiver(mResultHandler) { - protected void onReceiveResult(int resultCode, Bundle resultData) { - controller.receiveCommandResult(this); - mCallbackExecutor.execute(() -> { - mCallback.onCommandResult(MediaSession2.this, controller, this, - command, new Session2Command.Result(resultCode, resultData)); - }); - } - }; - controller.sendSessionCommand(command, args, resultReceiver); - return resultReceiver; - } - - /** - * Cancels the session command previously sent. - * - * @param controller the controller to get the session command - * @param token the token which is returned from {@link #sendSessionCommand}. - */ - public void cancelSessionCommand(@NonNull ControllerInfo controller, @NonNull Object token) { - if (controller == null) { - throw new IllegalArgumentException("controller shouldn't be null"); - } - if (token == null) { - throw new IllegalArgumentException("token shouldn't be null"); - } - controller.cancelSessionCommand(token); - } - - /** - * Sets whether the playback is active (i.e. playing something) - * - * @param playbackActive {@code true} if the playback active, {@code false} otherwise. - **/ - public void setPlaybackActive(boolean playbackActive) { - final ForegroundServiceEventCallback serviceCallback; - synchronized (mLock) { - if (mPlaybackActive == playbackActive) { - return; - } - mPlaybackActive = playbackActive; - serviceCallback = mForegroundServiceEventCallback; - } - if (serviceCallback != null) { - serviceCallback.onPlaybackActiveChanged(this, playbackActive); - } - List<ControllerInfo> controllerInfos = getConnectedControllers(); - for (ControllerInfo controller : controllerInfos) { - controller.notifyPlaybackActiveChanged(playbackActive); - } - } - - /** - * Returns whehther the playback is active (i.e. playing something) - * - * @return {@code true} if the playback active, {@code false} otherwise. - */ - public boolean isPlaybackActive() { - synchronized (mLock) { - return mPlaybackActive; - } - } - - /** - * Gets the list of the connected controllers - * - * @return list of the connected controllers. - */ - @NonNull - public List<ControllerInfo> getConnectedControllers() { - List<ControllerInfo> controllers = new ArrayList<>(); - synchronized (mLock) { - controllers.addAll(mConnectedControllers.values()); - } - return controllers; - } - - /** - * Returns whether the given bundle includes non-framework Parcelables. - */ - static boolean hasCustomParcelable(@Nullable Bundle bundle) { - if (bundle == null) { - return false; - } - - // Try writing the bundle to parcel, and read it with framework classloader. - Parcel parcel = null; - try { - parcel = Parcel.obtain(); - parcel.writeBundle(bundle); - parcel.setDataPosition(0); - Bundle out = parcel.readBundle(null); - - // Calling Bundle#size() will trigger Bundle#unparcel(). - out.size(); - } catch (BadParcelableException e) { - Log.d(TAG, "Custom parcelable in bundle.", e); - return true; - } finally { - if (parcel != null) { - parcel.recycle(); - } - } - return false; - } - - boolean isClosed() { - synchronized (mLock) { - return mClosed; - } - } - - SessionCallback getCallback() { - return mCallback; - } - - boolean isTrustedForMediaControl(RemoteUserInfo remoteUserInfo) { - if (SdkLevel.isAtLeastS()) { - return mCommunicationManager.isTrustedForMediaControl(remoteUserInfo); - } else { - return mMediaSessionManager.isTrustedForMediaControl(remoteUserInfo); - } - } - - void setForegroundServiceEventCallback(ForegroundServiceEventCallback callback) { - synchronized (mLock) { - if (mForegroundServiceEventCallback == callback) { - return; - } - if (mForegroundServiceEventCallback != null && callback != null) { - throw new IllegalStateException("A session cannot be added to multiple services"); - } - mForegroundServiceEventCallback = callback; - } - } - - // Called by Session2Link.onConnect and MediaSession2Service.MediaSession2ServiceStub.connect - void onConnect(final Controller2Link controller, int callingPid, int callingUid, int seq, - Bundle connectionRequest) { - if (callingPid == 0) { - // The pid here is from Binder.getCallingPid(), which can be 0 for an oneway call from - // the remote process. If it's the case, use PID from the connectionRequest. - callingPid = connectionRequest.getInt(KEY_PID); - } - String callingPkg = connectionRequest.getString(KEY_PACKAGE_NAME); - - RemoteUserInfo remoteUserInfo = new RemoteUserInfo(callingPkg, callingPid, callingUid); - - Bundle connectionHints = connectionRequest.getBundle(KEY_CONNECTION_HINTS); - if (connectionHints == null) { - Log.w(TAG, "connectionHints shouldn't be null."); - connectionHints = Bundle.EMPTY; - } else if (hasCustomParcelable(connectionHints)) { - Log.w(TAG, "connectionHints contain custom parcelable. Ignoring."); - connectionHints = Bundle.EMPTY; - } - - final ControllerInfo controllerInfo = new ControllerInfo( - remoteUserInfo, - isTrustedForMediaControl(remoteUserInfo), - controller, - connectionHints); - mCallbackExecutor.execute(() -> { - boolean connected = false; - try { - if (isClosed()) { - return; - } - controllerInfo.mAllowedCommands = - mCallback.onConnect(MediaSession2.this, controllerInfo); - // Don't reject connection for the request from trusted app. - // Otherwise server will fail to retrieve session's information to dispatch - // media keys to. - if (controllerInfo.mAllowedCommands == null && !controllerInfo.isTrusted()) { - return; - } - if (controllerInfo.mAllowedCommands == null) { - // For trusted apps, send non-null allowed commands to keep - // connection. - controllerInfo.mAllowedCommands = - new Session2CommandGroup.Builder().build(); - } - if (DEBUG) { - Log.d(TAG, "Accepting connection: " + controllerInfo); - } - // If connection is accepted, notify the current state to the controller. - // It's needed because we cannot call synchronous calls between - // session/controller. - Bundle connectionResult = new Bundle(); - connectionResult.putParcelable(KEY_SESSION2LINK, mSessionStub); - connectionResult.putParcelable(KEY_ALLOWED_COMMANDS, - controllerInfo.mAllowedCommands); - connectionResult.putBoolean(KEY_PLAYBACK_ACTIVE, isPlaybackActive()); - connectionResult.putBundle(KEY_TOKEN_EXTRAS, mSessionToken.getExtras()); - - // Double check if session is still there, because close() can be called in - // another thread. - if (isClosed()) { - return; - } - controllerInfo.notifyConnected(connectionResult); - synchronized (mLock) { - if (mConnectedControllers.containsKey(controller)) { - Log.w(TAG, "Controller " + controllerInfo + " has sent connection" - + " request multiple times"); - } - mConnectedControllers.put(controller, controllerInfo); - } - mCallback.onPostConnect(MediaSession2.this, controllerInfo); - connected = true; - } finally { - if (!connected || isClosed()) { - if (DEBUG) { - Log.d(TAG, "Rejecting connection or notifying that session is closed" - + ", controllerInfo=" + controllerInfo); - } - synchronized (mLock) { - mConnectedControllers.remove(controller); - } - controllerInfo.notifyDisconnected(); - } - } - }); - } - - // Called by Session2Link.onDisconnect - void onDisconnect(@NonNull final Controller2Link controller, int seq) { - final ControllerInfo controllerInfo; - synchronized (mLock) { - controllerInfo = mConnectedControllers.remove(controller); - } - if (controllerInfo == null) { - return; - } - mCallbackExecutor.execute(() -> { - mCallback.onDisconnected(MediaSession2.this, controllerInfo); - }); - } - - // Called by Session2Link.onSessionCommand - void onSessionCommand(@NonNull final Controller2Link controller, final int seq, - final Session2Command command, final Bundle args, - @Nullable ResultReceiver resultReceiver) { - if (controller == null) { - return; - } - final ControllerInfo controllerInfo; - synchronized (mLock) { - controllerInfo = mConnectedControllers.get(controller); - } - if (controllerInfo == null) { - return; - } - - // TODO: check allowed commands. - synchronized (mLock) { - controllerInfo.addRequestedCommandSeqNumber(seq); - } - mCallbackExecutor.execute(() -> { - if (!controllerInfo.removeRequestedCommandSeqNumber(seq)) { - if (resultReceiver != null) { - resultReceiver.send(RESULT_INFO_SKIPPED, null); - } - return; - } - Session2Command.Result result = mCallback.onSessionCommand( - MediaSession2.this, controllerInfo, command, args); - if (resultReceiver != null) { - if (result == null) { - resultReceiver.send(RESULT_INFO_SKIPPED, null); - } else { - resultReceiver.send(result.getResultCode(), result.getResultData()); - } - } - }); - } - - // Called by Session2Link.onCancelCommand - void onCancelCommand(@NonNull final Controller2Link controller, final int seq) { - final ControllerInfo controllerInfo; - synchronized (mLock) { - controllerInfo = mConnectedControllers.get(controller); - } - if (controllerInfo == null) { - return; - } - controllerInfo.removeRequestedCommandSeqNumber(seq); - } - - /** - * This API is not generally intended for third party application developers. - * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a> - * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session - * Library</a> for consistent behavior across all devices. - * <p> - * Builder for {@link MediaSession2}. - * <p> - * Any incoming event from the {@link MediaController2} will be handled on the callback - * executor. If it's not set, {@link Context#getMainExecutor()} will be used by default. - */ - public static final class Builder { - private Context mContext; - private String mId; - private PendingIntent mSessionActivity; - private Executor mCallbackExecutor; - private SessionCallback mCallback; - private Bundle mExtras; - - /** - * Creates a builder for {@link MediaSession2}. - * - * @param context Context - * @throws IllegalArgumentException if context is {@code null}. - */ - public Builder(@NonNull Context context) { - if (context == null) { - throw new IllegalArgumentException("context shouldn't be null"); - } - mContext = context; - } - - /** - * Set an intent for launching UI for this Session. This can be used as a - * quick link to an ongoing media screen. The intent should be for an - * activity that may be started using {@link Context#startActivity(Intent)}. - * - * @param pi The intent to launch to show UI for this session. - * @return The Builder to allow chaining - */ - @NonNull - public Builder setSessionActivity(@Nullable PendingIntent pi) { - mSessionActivity = pi; - return this; - } - - /** - * Set ID of the session. If it's not set, an empty string will be used to create a session. - * <p> - * Use this if and only if your app supports multiple playback at the same time and also - * wants to provide external apps to have finer controls of them. - * - * @param id id of the session. Must be unique per package. - * @throws IllegalArgumentException if id is {@code null}. - * @return The Builder to allow chaining - */ - @NonNull - public Builder setId(@NonNull String id) { - if (id == null) { - throw new IllegalArgumentException("id shouldn't be null"); - } - mId = id; - return this; - } - - /** - * Set callback for the session and its executor. - * - * @param executor callback executor - * @param callback session callback. - * @return The Builder to allow chaining - */ - @NonNull - public Builder setSessionCallback(@NonNull Executor executor, - @NonNull SessionCallback callback) { - mCallbackExecutor = executor; - mCallback = callback; - return this; - } - - /** - * Set extras for the session token. If null or not set, {@link Session2Token#getExtras()} - * will return an empty {@link Bundle}. An {@link IllegalArgumentException} will be thrown - * if the bundle contains any non-framework Parcelable objects. - * - * @return The Builder to allow chaining - * @see Session2Token#getExtras() - */ - @NonNull - public Builder setExtras(@NonNull Bundle extras) { - if (extras == null) { - throw new NullPointerException("extras shouldn't be null"); - } - if (hasCustomParcelable(extras)) { - throw new IllegalArgumentException( - "extras shouldn't contain any custom parcelables"); - } - mExtras = new Bundle(extras); - return this; - } - - /** - * Build {@link MediaSession2}. - * - * @return a new session - * @throws IllegalStateException if the session with the same id is already exists for the - * package. - */ - @NonNull - public MediaSession2 build() { - if (mCallbackExecutor == null) { - mCallbackExecutor = mContext.getMainExecutor(); - } - if (mCallback == null) { - mCallback = new SessionCallback() {}; - } - if (mId == null) { - mId = ""; - } - if (mExtras == null) { - mExtras = Bundle.EMPTY; - } - MediaSession2 session2 = new MediaSession2(mContext, mId, mSessionActivity, - mCallbackExecutor, mCallback, mExtras); - - // Notify framework about the newly create session after the constructor is finished. - // Otherwise, framework may access the session before the initialization is finished. - try { - if (SdkLevel.isAtLeastS()) { - MediaCommunicationManager manager = - mContext.getSystemService(MediaCommunicationManager.class); - manager.notifySession2Created(session2.getToken()); - } else { - MediaSessionManager manager = - mContext.getSystemService(MediaSessionManager.class); - manager.notifySession2Created(session2.getToken()); - } - } catch (Exception e) { - session2.close(); - throw e; - } - - return session2; - } - } - - /** - * This API is not generally intended for third party application developers. - * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a> - * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session - * Library</a> for consistent behavior across all devices. - * <p> - * Information of a controller. - */ - public static final class ControllerInfo { - private final RemoteUserInfo mRemoteUserInfo; - private final boolean mIsTrusted; - private final Controller2Link mControllerBinder; - private final Bundle mConnectionHints; - private final Object mLock = new Object(); - //@GuardedBy("mLock") - private int mNextSeqNumber; - //@GuardedBy("mLock") - private ArrayMap<ResultReceiver, Integer> mPendingCommands; - //@GuardedBy("mLock") - private ArraySet<Integer> mRequestedCommandSeqNumbers; - - @SuppressWarnings("WeakerAccess") /* synthetic access */ - Session2CommandGroup mAllowedCommands; - - /** - * @param remoteUserInfo remote user info - * @param trusted {@code true} if trusted, {@code false} otherwise - * @param controllerBinder Controller2Link for the connected controller. - * @param connectionHints a session-specific argument sent from the controller for the - * connection. The contents of this bundle may affect the - * connection result. - */ - ControllerInfo(@NonNull RemoteUserInfo remoteUserInfo, boolean trusted, - @Nullable Controller2Link controllerBinder, @NonNull Bundle connectionHints) { - mRemoteUserInfo = remoteUserInfo; - mIsTrusted = trusted; - mControllerBinder = controllerBinder; - mConnectionHints = connectionHints; - mPendingCommands = new ArrayMap<>(); - mRequestedCommandSeqNumbers = new ArraySet<>(); - } - - /** - * @return remote user info of the controller. - */ - @NonNull - public RemoteUserInfo getRemoteUserInfo() { - return mRemoteUserInfo; - } - - /** - * @return package name of the controller. - */ - @NonNull - public String getPackageName() { - return mRemoteUserInfo.getPackageName(); - } - - /** - * @return uid of the controller. Can be a negative value if the uid cannot be obtained. - */ - public int getUid() { - return mRemoteUserInfo.getUid(); - } - - /** - * @return connection hints sent from controller. - */ - @NonNull - public Bundle getConnectionHints() { - return new Bundle(mConnectionHints); - } - - /** - * Return if the controller has granted {@code android.permission.MEDIA_CONTENT_CONTROL} or - * has a enabled notification listener so can be trusted to accept connection and incoming - * command request. - * - * @return {@code true} if the controller is trusted. - * @hide - */ - public boolean isTrusted() { - return mIsTrusted; - } - - @Override - public int hashCode() { - return Objects.hash(mControllerBinder, mRemoteUserInfo); - } - - @Override - public boolean equals(@Nullable Object obj) { - if (!(obj instanceof ControllerInfo)) return false; - if (this == obj) return true; - - ControllerInfo other = (ControllerInfo) obj; - if (mControllerBinder != null || other.mControllerBinder != null) { - return Objects.equals(mControllerBinder, other.mControllerBinder); - } - return mRemoteUserInfo.equals(other.mRemoteUserInfo); - } - - @Override - @NonNull - public String toString() { - return "ControllerInfo {pkg=" + mRemoteUserInfo.getPackageName() + ", uid=" - + mRemoteUserInfo.getUid() + ", allowedCommands=" + mAllowedCommands + "})"; - } - - void notifyConnected(Bundle connectionResult) { - if (mControllerBinder == null) return; - - try { - mControllerBinder.notifyConnected(getNextSeqNumber(), connectionResult); - } catch (RuntimeException e) { - // Controller may be died prematurely. - } - } - - void notifyDisconnected() { - if (mControllerBinder == null) return; - - try { - mControllerBinder.notifyDisconnected(getNextSeqNumber()); - } catch (RuntimeException e) { - // Controller may be died prematurely. - } - } - - void notifyPlaybackActiveChanged(boolean playbackActive) { - if (mControllerBinder == null) return; - - try { - mControllerBinder.notifyPlaybackActiveChanged(getNextSeqNumber(), playbackActive); - } catch (RuntimeException e) { - // Controller may be died prematurely. - } - } - - void sendSessionCommand(Session2Command command, Bundle args, - ResultReceiver resultReceiver) { - if (mControllerBinder == null) return; - - try { - int seq = getNextSeqNumber(); - synchronized (mLock) { - mPendingCommands.put(resultReceiver, seq); - } - mControllerBinder.sendSessionCommand(seq, command, args, resultReceiver); - } catch (RuntimeException e) { - // Controller may be died prematurely. - synchronized (mLock) { - mPendingCommands.remove(resultReceiver); - } - resultReceiver.send(RESULT_ERROR_UNKNOWN_ERROR, null); - } - } - - void cancelSessionCommand(@NonNull Object token) { - if (mControllerBinder == null) return; - Integer seq; - synchronized (mLock) { - seq = mPendingCommands.remove(token); - } - if (seq != null) { - mControllerBinder.cancelSessionCommand(seq); - } - } - - void receiveCommandResult(ResultReceiver resultReceiver) { - synchronized (mLock) { - mPendingCommands.remove(resultReceiver); - } - } - - void addRequestedCommandSeqNumber(int seq) { - synchronized (mLock) { - mRequestedCommandSeqNumbers.add(seq); - } - } - - boolean removeRequestedCommandSeqNumber(int seq) { - synchronized (mLock) { - return mRequestedCommandSeqNumbers.remove(seq); - } - } - - private int getNextSeqNumber() { - synchronized (mLock) { - return mNextSeqNumber++; - } - } - } - - /** - * This API is not generally intended for third party application developers. - * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a> - * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session - * Library</a> for consistent behavior across all devices. - * <p> - * Callback to be called for all incoming commands from {@link MediaController2}s. - */ - public abstract static class SessionCallback { - /** - * Called when a controller is created for this session. Return allowed commands for - * controller. By default it returns {@code null}. - * <p> - * You can reject the connection by returning {@code null}. In that case, controller - * receives {@link MediaController2.ControllerCallback#onDisconnected(MediaController2)} - * and cannot be used. - * <p> - * The controller hasn't connected yet in this method, so calls to the controller - * (e.g. {@link #sendSessionCommand}) would be ignored. Override {@link #onPostConnect} for - * the custom initialization for the controller instead. - * - * @param session the session for this event - * @param controller controller information. - * @return allowed commands. Can be {@code null} to reject connection. - */ - @Nullable - public Session2CommandGroup onConnect(@NonNull MediaSession2 session, - @NonNull ControllerInfo controller) { - return null; - } - - /** - * Called immediately after a controller is connected. This is a convenient method to add - * custom initialization between the session and a controller. - * <p> - * Note that calls to the controller (e.g. {@link #sendSessionCommand}) work here but don't - * work in {@link #onConnect} because the controller hasn't connected yet in - * {@link #onConnect}. - * - * @param session the session for this event - * @param controller controller information. - */ - public void onPostConnect(@NonNull MediaSession2 session, - @NonNull ControllerInfo controller) { - } - - /** - * Called when a controller is disconnected - * - * @param session the session for this event - * @param controller controller information - */ - public void onDisconnected(@NonNull MediaSession2 session, - @NonNull ControllerInfo controller) {} - - /** - * Called when a controller sent a session command. - * - * @param session the session for this event - * @param controller controller information - * @param command the session command - * @param args optional arguments - * @return the result for the session command. If {@code null}, RESULT_INFO_SKIPPED - * will be sent to the session. - */ - @Nullable - public Session2Command.Result onSessionCommand(@NonNull MediaSession2 session, - @NonNull ControllerInfo controller, @NonNull Session2Command command, - @Nullable Bundle args) { - return null; - } - - /** - * Called when the command sent to the controller is finished. - * - * @param session the session for this event - * @param controller controller information - * @param token the token got from {@link MediaSession2#sendSessionCommand} - * @param command the session command - * @param result the result of the session command - */ - public void onCommandResult(@NonNull MediaSession2 session, - @NonNull ControllerInfo controller, @NonNull Object token, - @NonNull Session2Command command, @NonNull Session2Command.Result result) {} - } - - abstract static class ForegroundServiceEventCallback { - public void onPlaybackActiveChanged(MediaSession2 session, boolean playbackActive) {} - public void onSessionClosed(MediaSession2 session) {} - } -} diff --git a/apex/media/framework/java/android/media/MediaSession2Service.java b/apex/media/framework/java/android/media/MediaSession2Service.java deleted file mode 100644 index f6fd509fd245..000000000000 --- a/apex/media/framework/java/android/media/MediaSession2Service.java +++ /dev/null @@ -1,452 +0,0 @@ -/* - * Copyright 2019 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 android.media; - -import static android.media.MediaConstants.KEY_CONNECTION_HINTS; -import static android.media.MediaConstants.KEY_PACKAGE_NAME; -import static android.media.MediaConstants.KEY_PID; - -import android.annotation.CallSuper; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.media.MediaSession2.ControllerInfo; -import android.media.session.MediaSessionManager; -import android.media.session.MediaSessionManager.RemoteUserInfo; -import android.os.Binder; -import android.os.Bundle; -import android.os.Handler; -import android.os.IBinder; -import android.util.ArrayMap; -import android.util.Log; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/** - * This API is not generally intended for third party application developers. - * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a> - * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session - * Library</a> for consistent behavior across all devices. - * <p> - * Service containing {@link MediaSession2}. - */ -public abstract class MediaSession2Service extends Service { - /** - * The {@link Intent} that must be declared as handled by the service. - */ - public static final String SERVICE_INTERFACE = "android.media.MediaSession2Service"; - - private static final String TAG = "MediaSession2Service"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - - private final MediaSession2.ForegroundServiceEventCallback mForegroundServiceEventCallback = - new MediaSession2.ForegroundServiceEventCallback() { - @Override - public void onPlaybackActiveChanged(MediaSession2 session, boolean playbackActive) { - MediaSession2Service.this.onPlaybackActiveChanged(session, playbackActive); - } - - @Override - public void onSessionClosed(MediaSession2 session) { - removeSession(session); - } - }; - - private final Object mLock = new Object(); - //@GuardedBy("mLock") - private NotificationManager mNotificationManager; - //@GuardedBy("mLock") - private MediaSessionManager mMediaSessionManager; - //@GuardedBy("mLock") - private Intent mStartSelfIntent; - //@GuardedBy("mLock") - private Map<String, MediaSession2> mSessions = new ArrayMap<>(); - //@GuardedBy("mLock") - private Map<MediaSession2, MediaNotification> mNotifications = new ArrayMap<>(); - //@GuardedBy("mLock") - private MediaSession2ServiceStub mStub; - - /** - * Called by the system when the service is first created. Do not call this method directly. - * <p> - * Override this method if you need your own initialization. Derived classes MUST call through - * to the super class's implementation of this method. - */ - @CallSuper - @Override - public void onCreate() { - super.onCreate(); - synchronized (mLock) { - mStub = new MediaSession2ServiceStub(this); - mStartSelfIntent = new Intent(this, this.getClass()); - mNotificationManager = - (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - mMediaSessionManager = - (MediaSessionManager) getSystemService(Context.MEDIA_SESSION_SERVICE); - } - } - - @CallSuper - @Override - @Nullable - public IBinder onBind(@NonNull Intent intent) { - if (SERVICE_INTERFACE.equals(intent.getAction())) { - synchronized (mLock) { - return mStub; - } - } - return null; - } - - /** - * Called by the system to notify that it is no longer used and is being removed. Do not call - * this method directly. - * <p> - * Override this method if you need your own clean up. Derived classes MUST call through - * to the super class's implementation of this method. - */ - @CallSuper - @Override - public void onDestroy() { - super.onDestroy(); - synchronized (mLock) { - List<MediaSession2> sessions = getSessions(); - for (MediaSession2 session : sessions) { - removeSession(session); - } - mSessions.clear(); - mNotifications.clear(); - } - mStub.close(); - } - - /** - * Called when a {@link MediaController2} is created with the this service's - * {@link Session2Token}. Return the session for telling the controller which session to - * connect. Return {@code null} to reject the connection from this controller. - * <p> - * Session returned here will be added to this service automatically. You don't need to call - * {@link #addSession(MediaSession2)} for that. - * <p> - * This method is always called on the main thread. - * - * @param controllerInfo information of the controller which is trying to connect. - * @return a {@link MediaSession2} instance for the controller to connect to, or {@code null} - * to reject connection - * @see MediaSession2.Builder - * @see #getSessions() - */ - @Nullable - public abstract MediaSession2 onGetSession(@NonNull ControllerInfo controllerInfo); - - /** - * Called when notification UI needs update. Override this method to show or cancel your own - * notification UI. - * <p> - * This would be called on {@link MediaSession2}'s callback executor when playback state is - * changed. - * <p> - * With the notification returned here, the service becomes foreground service when the playback - * is started. Apps must request the permission - * {@link android.Manifest.permission#FOREGROUND_SERVICE} in order to use this API. It becomes - * background service after the playback is stopped. - * - * @param session a session that needs notification update. - * @return a {@link MediaNotification}. Can be {@code null}. - */ - @Nullable - public abstract MediaNotification onUpdateNotification(@NonNull MediaSession2 session); - - /** - * Adds a session to this service. - * <p> - * Added session will be removed automatically when it's closed, or removed when - * {@link #removeSession} is called. - * - * @param session a session to be added. - * @see #removeSession(MediaSession2) - */ - public final void addSession(@NonNull MediaSession2 session) { - if (session == null) { - throw new IllegalArgumentException("session shouldn't be null"); - } - if (session.isClosed()) { - throw new IllegalArgumentException("session is already closed"); - } - synchronized (mLock) { - MediaSession2 previousSession = mSessions.get(session.getId()); - if (previousSession != null) { - if (previousSession != session) { - Log.w(TAG, "Session ID should be unique, ID=" + session.getId() - + ", previous=" + previousSession + ", session=" + session); - } - return; - } - mSessions.put(session.getId(), session); - session.setForegroundServiceEventCallback(mForegroundServiceEventCallback); - } - } - - /** - * Removes a session from this service. - * - * @param session a session to be removed. - * @see #addSession(MediaSession2) - */ - public final void removeSession(@NonNull MediaSession2 session) { - if (session == null) { - throw new IllegalArgumentException("session shouldn't be null"); - } - MediaNotification notification; - synchronized (mLock) { - if (mSessions.get(session.getId()) != session) { - // Session isn't added or removed already. - return; - } - mSessions.remove(session.getId()); - notification = mNotifications.remove(session); - } - session.setForegroundServiceEventCallback(null); - if (notification != null) { - mNotificationManager.cancel(notification.getNotificationId()); - } - if (getSessions().isEmpty()) { - stopForeground(false); - } - } - - /** - * Gets the list of {@link MediaSession2}s that you've added to this service. - * - * @return sessions - */ - public final @NonNull List<MediaSession2> getSessions() { - List<MediaSession2> list = new ArrayList<>(); - synchronized (mLock) { - list.addAll(mSessions.values()); - } - return list; - } - - /** - * Returns the {@link MediaSessionManager}. - */ - @NonNull - MediaSessionManager getMediaSessionManager() { - synchronized (mLock) { - return mMediaSessionManager; - } - } - - /** - * Called by registered {@link MediaSession2.ForegroundServiceEventCallback} - * - * @param session session with change - * @param playbackActive {@code true} if playback is active. - */ - void onPlaybackActiveChanged(MediaSession2 session, boolean playbackActive) { - MediaNotification mediaNotification = onUpdateNotification(session); - if (mediaNotification == null) { - // The service implementation doesn't want to use the automatic start/stopForeground - // feature. - return; - } - synchronized (mLock) { - mNotifications.put(session, mediaNotification); - } - int id = mediaNotification.getNotificationId(); - Notification notification = mediaNotification.getNotification(); - if (!playbackActive) { - mNotificationManager.notify(id, notification); - return; - } - // playbackActive == true - startForegroundService(mStartSelfIntent); - startForeground(id, notification); - } - - /** - * This API is not generally intended for third party application developers. - * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a> - * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session - * Library</a> for consistent behavior across all devices. - * <p> - * Returned by {@link #onUpdateNotification(MediaSession2)} for making session service - * foreground service to keep playback running in the background. It's highly recommended to - * show media style notification here. - */ - public static class MediaNotification { - private final int mNotificationId; - private final Notification mNotification; - - /** - * Default constructor - * - * @param notificationId notification id to be used for - * {@link NotificationManager#notify(int, Notification)}. - * @param notification a notification to make session service run in the foreground. Media - * style notification is recommended here. - */ - public MediaNotification(int notificationId, @NonNull Notification notification) { - if (notification == null) { - throw new IllegalArgumentException("notification shouldn't be null"); - } - mNotificationId = notificationId; - mNotification = notification; - } - - /** - * Gets the id of the notification. - * - * @return the notification id - */ - public int getNotificationId() { - return mNotificationId; - } - - /** - * Gets the notification. - * - * @return the notification - */ - @NonNull - public Notification getNotification() { - return mNotification; - } - } - - private static final class MediaSession2ServiceStub extends IMediaSession2Service.Stub - implements AutoCloseable { - final WeakReference<MediaSession2Service> mService; - final Handler mHandler; - - MediaSession2ServiceStub(MediaSession2Service service) { - mService = new WeakReference<>(service); - mHandler = new Handler(service.getMainLooper()); - } - - @Override - public void connect(Controller2Link caller, int seq, Bundle connectionRequest) { - if (mService.get() == null) { - if (DEBUG) { - Log.d(TAG, "Service is already destroyed"); - } - return; - } - if (caller == null || connectionRequest == null) { - if (DEBUG) { - Log.d(TAG, "Ignoring calls with illegal arguments, caller=" + caller - + ", connectionRequest=" + connectionRequest); - } - return; - } - final int pid = Binder.getCallingPid(); - final int uid = Binder.getCallingUid(); - final long token = Binder.clearCallingIdentity(); - try { - mHandler.post(() -> { - boolean shouldNotifyDisconnected = true; - try { - final MediaSession2Service service = mService.get(); - if (service == null) { - if (DEBUG) { - Log.d(TAG, "Service isn't available"); - } - return; - } - - String callingPkg = connectionRequest.getString(KEY_PACKAGE_NAME); - // The Binder.getCallingPid() can be 0 for an oneway call from the - // remote process. If it's the case, use PID from the connectionRequest. - RemoteUserInfo remoteUserInfo = new RemoteUserInfo( - callingPkg, - pid == 0 ? connectionRequest.getInt(KEY_PID) : pid, - uid); - - Bundle connectionHints = connectionRequest.getBundle(KEY_CONNECTION_HINTS); - if (connectionHints == null) { - Log.w(TAG, "connectionHints shouldn't be null."); - connectionHints = Bundle.EMPTY; - } else if (MediaSession2.hasCustomParcelable(connectionHints)) { - Log.w(TAG, "connectionHints contain custom parcelable. Ignoring."); - connectionHints = Bundle.EMPTY; - } - - final ControllerInfo controllerInfo = new ControllerInfo( - remoteUserInfo, - service.getMediaSessionManager() - .isTrustedForMediaControl(remoteUserInfo), - caller, - connectionHints); - - if (DEBUG) { - Log.d(TAG, "Handling incoming connection request from the" - + " controller=" + controllerInfo); - } - - final MediaSession2 session; - session = service.onGetSession(controllerInfo); - - if (session == null) { - if (DEBUG) { - Log.d(TAG, "Rejecting incoming connection request from the" - + " controller=" + controllerInfo); - } - // Note: Trusted controllers also can be rejected according to the - // service implementation. - return; - } - service.addSession(session); - shouldNotifyDisconnected = false; - session.onConnect(caller, pid, uid, seq, connectionRequest); - } catch (Exception e) { - // Don't propagate exception in service to the controller. - Log.w(TAG, "Failed to add a session to session service", e); - } finally { - // Trick to call onDisconnected() in one place. - if (shouldNotifyDisconnected) { - if (DEBUG) { - Log.d(TAG, "Notifying the controller of its disconnection"); - } - try { - caller.notifyDisconnected(0); - } catch (RuntimeException e) { - // Controller may be died prematurely. - // Not an issue because we'll ignore it anyway. - } - } - } - }); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public void close() { - mHandler.removeCallbacksAndMessages(null); - mService.clear(); - } - } -} diff --git a/apex/media/framework/java/android/media/MediaTranscodingManager.java b/apex/media/framework/java/android/media/MediaTranscodingManager.java deleted file mode 100644 index 1a84929c678f..000000000000 --- a/apex/media/framework/java/android/media/MediaTranscodingManager.java +++ /dev/null @@ -1,1752 +0,0 @@ -/* - * Copyright (C) 2019 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 android.media; - -import android.annotation.CallbackExecutor; -import android.annotation.IntDef; -import android.annotation.IntRange; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.app.ActivityManager; -import android.content.ContentResolver; -import android.content.Context; -import android.content.res.AssetFileDescriptor; -import android.net.Uri; -import android.os.Build; -import android.os.ParcelFileDescriptor; -import android.os.RemoteException; -import android.os.ServiceSpecificException; -import android.system.Os; -import android.util.Log; - -import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; -import com.android.modules.annotation.MinSdk; -import com.android.modules.utils.build.SdkLevel; - -import java.io.FileNotFoundException; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -/** - Android 12 introduces Compatible media transcoding feature. See - <a href="https://developer.android.com/about/versions/12/features#compatible_media_transcoding"> - Compatible media transcoding</a>. MediaTranscodingManager provides an interface to the system's media - transcoding service and can be used to transcode media files, e.g. transcoding a video from HEVC to - AVC. - - <h3>Transcoding Types</h3> - <h4>Video Transcoding</h4> - When transcoding a video file, the video track will be transcoded based on the desired track format - and the audio track will be pass through without any modification. - <p class=note> - Note that currently only support transcoding video file in mp4 format and with single video track. - - <h3>Transcoding Request</h3> - <p> - To transcode a media file, first create a {@link TranscodingRequest} through its builder class - {@link VideoTranscodingRequest.Builder}. Transcode requests are then enqueue to the manager through - {@link MediaTranscodingManager#enqueueRequest( - TranscodingRequest, Executor, OnTranscodingFinishedListener)} - TranscodeRequest are processed based on client process's priority and request priority. When a - transcode operation is completed the caller is notified via its - {@link OnTranscodingFinishedListener}. - In the meantime the caller may use the returned TranscodingSession object to cancel or check the - status of a specific transcode operation. - <p> - Here is an example where <code>Builder</code> is used to specify all parameters - - <pre class=prettyprint> - VideoTranscodingRequest request = - new VideoTranscodingRequest.Builder(srcUri, dstUri, videoFormat).build(); - }</pre> - @hide - */ -@MinSdk(Build.VERSION_CODES.S) -@SystemApi -public final class MediaTranscodingManager { - private static final String TAG = "MediaTranscodingManager"; - - /** Maximum number of retry to connect to the service. */ - private static final int CONNECT_SERVICE_RETRY_COUNT = 100; - - /** Interval between trying to reconnect to the service. */ - private static final int INTERVAL_CONNECT_SERVICE_RETRY_MS = 40; - - /** Default bpp(bits-per-pixel) to use for calculating default bitrate. */ - private static final float BPP = 0.25f; - - /** - * Listener that gets notified when a transcoding operation has finished. - * This listener gets notified regardless of how the operation finished. It is up to the - * listener implementation to check the result and take appropriate action. - */ - @FunctionalInterface - public interface OnTranscodingFinishedListener { - /** - * Called when the transcoding operation has finished. The receiver may use the - * TranscodingSession to check the result, i.e. whether the operation succeeded, was - * canceled or if an error occurred. - * - * @param session The TranscodingSession instance for the finished transcoding operation. - */ - void onTranscodingFinished(@NonNull TranscodingSession session); - } - - private final Context mContext; - private ContentResolver mContentResolver; - private final String mPackageName; - private final int mPid; - private final int mUid; - private final boolean mIsLowRamDevice; - private final ExecutorService mExecutor = Executors.newSingleThreadExecutor(); - private final HashMap<Integer, TranscodingSession> mPendingTranscodingSessions = new HashMap(); - private final Object mLock = new Object(); - @GuardedBy("mLock") - @NonNull private ITranscodingClient mTranscodingClient = null; - private static MediaTranscodingManager sMediaTranscodingManager; - - private void handleTranscodingFinished(int sessionId, TranscodingResultParcel result) { - synchronized (mPendingTranscodingSessions) { - // Gets the session associated with the sessionId and removes it from - // mPendingTranscodingSessions. - final TranscodingSession session = mPendingTranscodingSessions.remove(sessionId); - - if (session == null) { - // This should not happen in reality. - Log.e(TAG, "Session " + sessionId + " is not in Pendingsessions"); - return; - } - - // Updates the session status and result. - session.updateStatusAndResult(TranscodingSession.STATUS_FINISHED, - TranscodingSession.RESULT_SUCCESS, - TranscodingSession.ERROR_NONE); - - // Notifies client the session is done. - if (session.mListener != null && session.mListenerExecutor != null) { - session.mListenerExecutor.execute( - () -> session.mListener.onTranscodingFinished(session)); - } - } - } - - private void handleTranscodingFailed(int sessionId, int errorCode) { - synchronized (mPendingTranscodingSessions) { - // Gets the session associated with the sessionId and removes it from - // mPendingTranscodingSessions. - final TranscodingSession session = mPendingTranscodingSessions.remove(sessionId); - - if (session == null) { - // This should not happen in reality. - Log.e(TAG, "Session " + sessionId + " is not in Pendingsessions"); - return; - } - - // Updates the session status and result. - session.updateStatusAndResult(TranscodingSession.STATUS_FINISHED, - TranscodingSession.RESULT_ERROR, errorCode); - - // Notifies client the session failed. - if (session.mListener != null && session.mListenerExecutor != null) { - session.mListenerExecutor.execute( - () -> session.mListener.onTranscodingFinished(session)); - } - } - } - - private void handleTranscodingProgressUpdate(int sessionId, int newProgress) { - synchronized (mPendingTranscodingSessions) { - // Gets the session associated with the sessionId. - final TranscodingSession session = mPendingTranscodingSessions.get(sessionId); - - if (session == null) { - // This should not happen in reality. - Log.e(TAG, "Session " + sessionId + " is not in Pendingsessions"); - return; - } - - // Updates the session progress. - session.updateProgress(newProgress); - - // Notifies client the progress update. - if (session.mProgressUpdateExecutor != null - && session.mProgressUpdateListener != null) { - session.mProgressUpdateExecutor.execute( - () -> session.mProgressUpdateListener.onProgressUpdate(session, - newProgress)); - } - } - } - - private IMediaTranscodingService getService(boolean retry) { - // Do not try to get the service on pre-S. The service is lazy-start and getting the - // service could block. - if (!SdkLevel.isAtLeastS()) { - return null; - } - // Do not try to get the service on AndroidGo (low-ram) devices. - if (mIsLowRamDevice) { - return null; - } - int retryCount = !retry ? 1 : CONNECT_SERVICE_RETRY_COUNT; - Log.i(TAG, "get service with retry " + retryCount); - for (int count = 1; count <= retryCount; count++) { - Log.d(TAG, "Trying to connect to service. Try count: " + count); - IMediaTranscodingService service = IMediaTranscodingService.Stub.asInterface( - MediaFrameworkInitializer - .getMediaServiceManager() - .getMediaTranscodingServiceRegisterer() - .get()); - if (service != null) { - return service; - } - try { - // Sleep a bit before retry. - Thread.sleep(INTERVAL_CONNECT_SERVICE_RETRY_MS); - } catch (InterruptedException ie) { - /* ignore */ - } - } - Log.w(TAG, "Failed to get service"); - return null; - } - - /* - * Handle client binder died event. - * Upon receiving a binder died event of the client, we will do the following: - * 1) For the session that is running, notify the client that the session is failed with - * error code, so client could choose to retry the session or not. - * TODO(hkuang): Add a new error code to signal service died error. - * 2) For the sessions that is still pending or paused, we will resubmit the session - * once we successfully reconnect to the service and register a new client. - * 3) When trying to connect to the service and register a new client. The service may need time - * to reboot or never boot up again. So we will retry for a number of times. If we still - * could not connect, we will notify client session failure for the pending and paused - * sessions. - */ - private void onClientDied() { - synchronized (mLock) { - mTranscodingClient = null; - } - - // Delegates the session notification and retry to the executor as it may take some time. - mExecutor.execute(() -> { - // List to track the sessions that we want to retry. - List<TranscodingSession> retrySessions = new ArrayList<TranscodingSession>(); - - // First notify the client of session failure for all the running sessions. - synchronized (mPendingTranscodingSessions) { - for (Map.Entry<Integer, TranscodingSession> entry : - mPendingTranscodingSessions.entrySet()) { - TranscodingSession session = entry.getValue(); - - if (session.getStatus() == TranscodingSession.STATUS_RUNNING) { - session.updateStatusAndResult(TranscodingSession.STATUS_FINISHED, - TranscodingSession.RESULT_ERROR, - TranscodingSession.ERROR_SERVICE_DIED); - - // Remove the session from pending sessions. - mPendingTranscodingSessions.remove(entry.getKey()); - - if (session.mListener != null && session.mListenerExecutor != null) { - Log.i(TAG, "Notify client session failed"); - session.mListenerExecutor.execute( - () -> session.mListener.onTranscodingFinished(session)); - } - } else if (session.getStatus() == TranscodingSession.STATUS_PENDING - || session.getStatus() == TranscodingSession.STATUS_PAUSED) { - // Add the session to retrySessions to handle them later. - retrySessions.add(session); - } - } - } - - // Try to register with the service once it boots up. - IMediaTranscodingService service = getService(true /*retry*/); - boolean haveTranscodingClient = false; - if (service != null) { - synchronized (mLock) { - mTranscodingClient = registerClient(service); - if (mTranscodingClient != null) { - haveTranscodingClient = true; - } - } - } - - for (TranscodingSession session : retrySessions) { - // Notify the session failure if we fails to connect to the service or fail - // to retry the session. - if (!haveTranscodingClient) { - // TODO(hkuang): Return correct error code to the client. - handleTranscodingFailed(session.getSessionId(), 0 /*unused */); - } - - try { - // Do not set hasRetried for retry initiated by MediaTranscodingManager. - session.retryInternal(false /*setHasRetried*/); - } catch (Exception re) { - // TODO(hkuang): Return correct error code to the client. - handleTranscodingFailed(session.getSessionId(), 0 /*unused */); - } - } - }); - } - - private void updateStatus(int sessionId, int status) { - synchronized (mPendingTranscodingSessions) { - final TranscodingSession session = mPendingTranscodingSessions.get(sessionId); - - if (session == null) { - // This should not happen in reality. - Log.e(TAG, "Session " + sessionId + " is not in Pendingsessions"); - return; - } - - // Updates the session status. - session.updateStatus(status); - } - } - - // Just forwards all the events to the event handler. - private ITranscodingClientCallback mTranscodingClientCallback = - new ITranscodingClientCallback.Stub() { - // TODO(hkuang): Add more unit test to test difference file open mode. - @Override - public ParcelFileDescriptor openFileDescriptor(String fileUri, String mode) - throws RemoteException { - if (!mode.equals("r") && !mode.equals("w") && !mode.equals("rw")) { - Log.e(TAG, "Unsupport mode: " + mode); - return null; - } - - Uri uri = Uri.parse(fileUri); - try { - AssetFileDescriptor afd = mContentResolver.openAssetFileDescriptor(uri, - mode); - if (afd != null) { - return afd.getParcelFileDescriptor(); - } - } catch (FileNotFoundException e) { - Log.w(TAG, "Cannot find content uri: " + uri, e); - } catch (SecurityException e) { - Log.w(TAG, "Cannot open content uri: " + uri, e); - } catch (Exception e) { - Log.w(TAG, "Unknown content uri: " + uri, e); - } - return null; - } - - @Override - public void onTranscodingStarted(int sessionId) throws RemoteException { - updateStatus(sessionId, TranscodingSession.STATUS_RUNNING); - } - - @Override - public void onTranscodingPaused(int sessionId) throws RemoteException { - updateStatus(sessionId, TranscodingSession.STATUS_PAUSED); - } - - @Override - public void onTranscodingResumed(int sessionId) throws RemoteException { - updateStatus(sessionId, TranscodingSession.STATUS_RUNNING); - } - - @Override - public void onTranscodingFinished(int sessionId, TranscodingResultParcel result) - throws RemoteException { - handleTranscodingFinished(sessionId, result); - } - - @Override - public void onTranscodingFailed(int sessionId, int errorCode) - throws RemoteException { - handleTranscodingFailed(sessionId, errorCode); - } - - @Override - public void onAwaitNumberOfSessionsChanged(int sessionId, int oldAwaitNumber, - int newAwaitNumber) throws RemoteException { - //TODO(hkuang): Implement this. - } - - @Override - public void onProgressUpdate(int sessionId, int newProgress) - throws RemoteException { - handleTranscodingProgressUpdate(sessionId, newProgress); - } - }; - - private ITranscodingClient registerClient(IMediaTranscodingService service) { - synchronized (mLock) { - try { - // Registers the client with MediaTranscoding service. - mTranscodingClient = service.registerClient( - mTranscodingClientCallback, - mPackageName, - mPackageName); - - if (mTranscodingClient != null) { - mTranscodingClient.asBinder().linkToDeath(() -> onClientDied(), /* flags */ 0); - } - } catch (Exception ex) { - Log.e(TAG, "Failed to register new client due to exception " + ex); - mTranscodingClient = null; - } - } - return mTranscodingClient; - } - - /** - * @hide - */ - public MediaTranscodingManager(@NonNull Context context) { - mContext = context; - mContentResolver = mContext.getContentResolver(); - mPackageName = mContext.getPackageName(); - mUid = Os.getuid(); - mPid = Os.getpid(); - mIsLowRamDevice = mContext.getSystemService(ActivityManager.class).isLowRamDevice(); - } - - /** - * Abstract base class for all the TranscodingRequest. - * <p> TranscodingRequest encapsulates the desired configuration for the transcoding. - */ - public abstract static class TranscodingRequest { - /** - * - * Default transcoding type. - * @hide - */ - public static final int TRANSCODING_TYPE_UNKNOWN = 0; - - /** - * TRANSCODING_TYPE_VIDEO indicates that client wants to perform transcoding on a video. - * <p>Note that currently only support transcoding video file in mp4 format. - * @hide - */ - public static final int TRANSCODING_TYPE_VIDEO = 1; - - /** - * TRANSCODING_TYPE_IMAGE indicates that client wants to perform transcoding on an image. - * @hide - */ - public static final int TRANSCODING_TYPE_IMAGE = 2; - - /** @hide */ - @IntDef(prefix = {"TRANSCODING_TYPE_"}, value = { - TRANSCODING_TYPE_UNKNOWN, - TRANSCODING_TYPE_VIDEO, - TRANSCODING_TYPE_IMAGE, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface TranscodingType {} - - /** - * Default value. - * - * @hide - */ - public static final int PRIORITY_UNKNOWN = 0; - /** - * PRIORITY_REALTIME indicates that the transcoding request is time-critical and that the - * client wants the transcoding result as soon as possible. - * <p> Set PRIORITY_REALTIME only if the transcoding is time-critical as it will involve - * performance penalty due to resource reallocation to prioritize the sessions with higher - * priority. - * - * @hide - */ - public static final int PRIORITY_REALTIME = 1; - - /** - * PRIORITY_OFFLINE indicates the transcoding is not time-critical and the client does not - * need the transcoding result as soon as possible. - * <p>Sessions with PRIORITY_OFFLINE will be scheduled behind PRIORITY_REALTIME. Always set - * to - * PRIORITY_OFFLINE if client does not need the result as soon as possible and could accept - * delay of the transcoding result. - * - * @hide - * - */ - public static final int PRIORITY_OFFLINE = 2; - - /** @hide */ - @IntDef(prefix = {"PRIORITY_"}, value = { - PRIORITY_UNKNOWN, - PRIORITY_REALTIME, - PRIORITY_OFFLINE, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface TranscodingPriority {} - - /** Uri of the source media file. */ - private @NonNull Uri mSourceUri; - - /** Uri of the destination media file. */ - private @NonNull Uri mDestinationUri; - - /** FileDescriptor of the source media file. */ - private @Nullable ParcelFileDescriptor mSourceFileDescriptor; - - /** FileDescriptor of the destination media file. */ - private @Nullable ParcelFileDescriptor mDestinationFileDescriptor; - - /** - * The UID of the client that the TranscodingRequest is for. Only privileged caller could - * set this Uid as only they could do the transcoding on behalf of the client. - * -1 means not available. - */ - private int mClientUid = -1; - - /** - * The Pid of the client that the TranscodingRequest is for. Only privileged caller could - * set this Uid as only they could do the transcoding on behalf of the client. - * -1 means not available. - */ - private int mClientPid = -1; - - /** Type of the transcoding. */ - private @TranscodingType int mType = TRANSCODING_TYPE_UNKNOWN; - - /** Priority of the transcoding. */ - private @TranscodingPriority int mPriority = PRIORITY_UNKNOWN; - - /** - * Desired image format for the destination file. - * <p> If this is null, source file's image track will be passed through and copied to the - * destination file. - * @hide - */ - private @Nullable MediaFormat mImageFormat = null; - - @VisibleForTesting - private TranscodingTestConfig mTestConfig = null; - - /** - * Prevent public constructor access. - */ - /* package private */ TranscodingRequest() { - } - - private TranscodingRequest(Builder b) { - mSourceUri = b.mSourceUri; - mSourceFileDescriptor = b.mSourceFileDescriptor; - mDestinationUri = b.mDestinationUri; - mDestinationFileDescriptor = b.mDestinationFileDescriptor; - mClientUid = b.mClientUid; - mClientPid = b.mClientPid; - mPriority = b.mPriority; - mType = b.mType; - mTestConfig = b.mTestConfig; - } - - /** - * Return the type of the transcoding. - * @hide - */ - @TranscodingType - public int getType() { - return mType; - } - - /** Return source uri of the transcoding. */ - @NonNull - public Uri getSourceUri() { - return mSourceUri; - } - - /** - * Return source file descriptor of the transcoding. - * This will be null if client has not provided it. - */ - @Nullable - public ParcelFileDescriptor getSourceFileDescriptor() { - return mSourceFileDescriptor; - } - - /** Return the UID of the client that this request is for. -1 means not available. */ - public int getClientUid() { - return mClientUid; - } - - /** Return the PID of the client that this request is for. -1 means not available. */ - public int getClientPid() { - return mClientPid; - } - - /** Return destination uri of the transcoding. */ - @NonNull - public Uri getDestinationUri() { - return mDestinationUri; - } - - /** - * Return destination file descriptor of the transcoding. - * This will be null if client has not provided it. - */ - @Nullable - public ParcelFileDescriptor getDestinationFileDescriptor() { - return mDestinationFileDescriptor; - } - - /** - * Return priority of the transcoding. - * @hide - */ - @TranscodingPriority - public int getPriority() { - return mPriority; - } - - /** - * Return TestConfig of the transcoding. - * @hide - */ - @Nullable - public TranscodingTestConfig getTestConfig() { - return mTestConfig; - } - - abstract void writeFormatToParcel(TranscodingRequestParcel parcel); - - /* Writes the TranscodingRequest to a parcel. */ - private TranscodingRequestParcel writeToParcel(@NonNull Context context) { - TranscodingRequestParcel parcel = new TranscodingRequestParcel(); - switch (mPriority) { - case PRIORITY_OFFLINE: - parcel.priority = TranscodingSessionPriority.kUnspecified; - break; - case PRIORITY_REALTIME: - case PRIORITY_UNKNOWN: - default: - parcel.priority = TranscodingSessionPriority.kNormal; - break; - } - parcel.transcodingType = mType; - parcel.sourceFilePath = mSourceUri.toString(); - parcel.sourceFd = mSourceFileDescriptor; - parcel.destinationFilePath = mDestinationUri.toString(); - parcel.destinationFd = mDestinationFileDescriptor; - parcel.clientUid = mClientUid; - parcel.clientPid = mClientPid; - if (mClientUid < 0) { - parcel.clientPackageName = context.getPackageName(); - } else { - String packageName = context.getPackageManager().getNameForUid(mClientUid); - // PackageName is optional as some uid does not have package name. Set to - // "Unavailable" string in this case. - if (packageName == null) { - Log.w(TAG, "Failed to find package for uid: " + mClientUid); - packageName = "Unavailable"; - } - parcel.clientPackageName = packageName; - } - writeFormatToParcel(parcel); - if (mTestConfig != null) { - parcel.isForTesting = true; - parcel.testConfig = mTestConfig; - } - return parcel; - } - - /** - * Builder to build a {@link TranscodingRequest} object. - * - * @param <T> The subclass to be built. - */ - abstract static class Builder<T extends Builder<T>> { - private @NonNull Uri mSourceUri; - private @NonNull Uri mDestinationUri; - private @Nullable ParcelFileDescriptor mSourceFileDescriptor = null; - private @Nullable ParcelFileDescriptor mDestinationFileDescriptor = null; - private int mClientUid = -1; - private int mClientPid = -1; - private @TranscodingType int mType = TRANSCODING_TYPE_UNKNOWN; - private @TranscodingPriority int mPriority = PRIORITY_UNKNOWN; - private TranscodingTestConfig mTestConfig; - - abstract T self(); - - /** - * Creates a builder for building {@link TranscodingRequest}s. - * - * Client must set the source Uri. If client also provides the source fileDescriptor - * through is provided by {@link #setSourceFileDescriptor(ParcelFileDescriptor)}, - * TranscodingSession will use the fd instead of calling back to the client to open the - * sourceUri. - * - * - * @param type The transcoding type. - * @param sourceUri Content uri for the source media file. - * @param destinationUri Content uri for the destination media file. - * - */ - private Builder(@TranscodingType int type, @NonNull Uri sourceUri, - @NonNull Uri destinationUri) { - mType = type; - - if (sourceUri == null || Uri.EMPTY.equals(sourceUri)) { - throw new IllegalArgumentException( - "You must specify a non-empty source Uri."); - } - mSourceUri = sourceUri; - - if (destinationUri == null || Uri.EMPTY.equals(destinationUri)) { - throw new IllegalArgumentException( - "You must specify a non-empty destination Uri."); - } - mDestinationUri = destinationUri; - } - - /** - * Specifies the fileDescriptor opened from the source media file. - * - * This call is optional. If the source fileDescriptor is provided, TranscodingSession - * will use it directly instead of opening the uri from {@link #Builder(int, Uri, Uri)}. - * It is client's responsibility to make sure the fileDescriptor is opened from the - * source uri. - * @param fileDescriptor a {@link ParcelFileDescriptor} opened from source media file. - * @return The same builder instance. - * @throws IllegalArgumentException if fileDescriptor is invalid. - */ - @NonNull - public T setSourceFileDescriptor(@NonNull ParcelFileDescriptor fileDescriptor) { - if (fileDescriptor == null || fileDescriptor.getFd() < 0) { - throw new IllegalArgumentException( - "Invalid source descriptor."); - } - mSourceFileDescriptor = fileDescriptor; - return self(); - } - - /** - * Specifies the fileDescriptor opened from the destination media file. - * - * This call is optional. If the destination fileDescriptor is provided, - * TranscodingSession will use it directly instead of opening the source uri from - * {@link #Builder(int, Uri, Uri)} upon transcoding starts. It is client's - * responsibility to make sure the fileDescriptor is opened from the destination uri. - * @param fileDescriptor a {@link ParcelFileDescriptor} opened from destination media - * file. - * @return The same builder instance. - * @throws IllegalArgumentException if fileDescriptor is invalid. - */ - @NonNull - public T setDestinationFileDescriptor( - @NonNull ParcelFileDescriptor fileDescriptor) { - if (fileDescriptor == null || fileDescriptor.getFd() < 0) { - throw new IllegalArgumentException( - "Invalid destination descriptor."); - } - mDestinationFileDescriptor = fileDescriptor; - return self(); - } - - /** - * Specify the UID of the client that this request is for. - * <p> - * Only privilege caller with android.permission.WRITE_MEDIA_STORAGE could forward the - * pid. Note that the permission check happens on the service side upon starting the - * transcoding. If the client does not have the permission, the transcoding will fail. - * - * @param uid client Uid. - * @return The same builder instance. - * @throws IllegalArgumentException if uid is invalid. - */ - @NonNull - public T setClientUid(int uid) { - if (uid < 0) { - throw new IllegalArgumentException("Invalid Uid"); - } - mClientUid = uid; - return self(); - } - - /** - * Specify the pid of the client that this request is for. - * <p> - * Only privilege caller with android.permission.WRITE_MEDIA_STORAGE could forward the - * pid. Note that the permission check happens on the service side upon starting the - * transcoding. If the client does not have the permission, the transcoding will fail. - * - * @param pid client Pid. - * @return The same builder instance. - * @throws IllegalArgumentException if pid is invalid. - */ - @NonNull - public T setClientPid(int pid) { - if (pid < 0) { - throw new IllegalArgumentException("Invalid pid"); - } - mClientPid = pid; - return self(); - } - - /** - * Specifies the priority of the transcoding. - * - * @param priority Must be one of the {@code PRIORITY_*} - * @return The same builder instance. - * @throws IllegalArgumentException if flags is invalid. - * @hide - */ - @NonNull - public T setPriority(@TranscodingPriority int priority) { - if (priority != PRIORITY_OFFLINE && priority != PRIORITY_REALTIME) { - throw new IllegalArgumentException("Invalid priority: " + priority); - } - mPriority = priority; - return self(); - } - - /** - * Sets the delay in processing this request. - * @param config test config. - * @return The same builder instance. - * @hide - */ - @VisibleForTesting - @NonNull - public T setTestConfig(@NonNull TranscodingTestConfig config) { - mTestConfig = config; - return self(); - } - } - - /** - * Abstract base class for all the format resolvers. - */ - abstract static class MediaFormatResolver { - private @NonNull ApplicationMediaCapabilities mClientCaps; - - /** - * Prevents public constructor access. - */ - /* package private */ MediaFormatResolver() { - } - - /** - * Constructs MediaFormatResolver object. - * - * @param clientCaps An ApplicationMediaCapabilities object containing the client's - * capabilities. - */ - MediaFormatResolver(@NonNull ApplicationMediaCapabilities clientCaps) { - if (clientCaps == null) { - throw new IllegalArgumentException("Client capabilities must not be null"); - } - mClientCaps = clientCaps; - } - - /** - * Returns the client capabilities. - */ - @NonNull - /* package */ ApplicationMediaCapabilities getClientCapabilities() { - return mClientCaps; - } - - abstract boolean shouldTranscode(); - } - - /** - * VideoFormatResolver for deciding if video transcoding is needed, and if so, the track - * formats to use. - */ - public static class VideoFormatResolver extends MediaFormatResolver { - private static final int BIT_RATE = 20000000; // 20Mbps - - private MediaFormat mSrcVideoFormatHint; - private MediaFormat mSrcAudioFormatHint; - - /** - * Constructs a new VideoFormatResolver object. - * - * @param clientCaps An ApplicationMediaCapabilities object containing the client's - * capabilities. - * @param srcVideoFormatHint A MediaFormat object containing information about the - * source's video track format that could affect the - * transcoding decision. Such information could include video - * codec types, color spaces, whether special format info (eg. - * slow-motion markers) are present, etc.. If a particular - * information is not present, it will not be used to make the - * decision. - */ - public VideoFormatResolver(@NonNull ApplicationMediaCapabilities clientCaps, - @NonNull MediaFormat srcVideoFormatHint) { - super(clientCaps); - mSrcVideoFormatHint = srcVideoFormatHint; - } - - /** - * Constructs a new VideoFormatResolver object. - * - * @param clientCaps An ApplicationMediaCapabilities object containing the client's - * capabilities. - * @param srcVideoFormatHint A MediaFormat object containing information about the - * source's video track format that could affect the - * transcoding decision. Such information could include video - * codec types, color spaces, whether special format info (eg. - * slow-motion markers) are present, etc.. If a particular - * information is not present, it will not be used to make the - * decision. - * @param srcAudioFormatHint A MediaFormat object containing information about the - * source's audio track format that could affect the - * transcoding decision. - * @hide - */ - VideoFormatResolver(@NonNull ApplicationMediaCapabilities clientCaps, - @NonNull MediaFormat srcVideoFormatHint, - @NonNull MediaFormat srcAudioFormatHint) { - super(clientCaps); - mSrcVideoFormatHint = srcVideoFormatHint; - mSrcAudioFormatHint = srcAudioFormatHint; - } - - /** - * Returns whether the source content should be transcoded. - * - * @return true if the source should be transcoded. - */ - public boolean shouldTranscode() { - boolean supportHevc = getClientCapabilities().isVideoMimeTypeSupported( - MediaFormat.MIMETYPE_VIDEO_HEVC); - if (!supportHevc && MediaFormat.MIMETYPE_VIDEO_HEVC.equals( - mSrcVideoFormatHint.getString(MediaFormat.KEY_MIME))) { - return true; - } - // TODO: add more checks as needed below. - return false; - } - - /** - * Retrieves the video track format to be used on - * {@link VideoTranscodingRequest.Builder#setVideoTrackFormat(MediaFormat)} for this - * configuration. - * - * @return the video track format to be used if transcoding should be performed, - * and null otherwise. - * @throws IllegalArgumentException if the hinted source video format contains invalid - * parameters. - */ - @Nullable - public MediaFormat resolveVideoFormat() { - if (!shouldTranscode()) { - return null; - } - - MediaFormat videoTrackFormat = new MediaFormat(mSrcVideoFormatHint); - videoTrackFormat.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_VIDEO_AVC); - - int width = mSrcVideoFormatHint.getInteger(MediaFormat.KEY_WIDTH, -1); - int height = mSrcVideoFormatHint.getInteger(MediaFormat.KEY_HEIGHT, -1); - if (width <= 0 || height <= 0) { - throw new IllegalArgumentException( - "Source Width and height must be larger than 0"); - } - - float frameRate = - mSrcVideoFormatHint.getNumber(MediaFormat.KEY_FRAME_RATE, 30.0) - .floatValue(); - if (frameRate <= 0) { - throw new IllegalArgumentException( - "frameRate must be larger than 0"); - } - - int bitrate = getAVCBitrate(width, height, frameRate); - videoTrackFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate); - return videoTrackFormat; - } - - /** - * Generate a default bitrate with the fixed bpp(bits-per-pixel) 0.25. - * This maps to: - * 1080P@30fps -> 16Mbps - * 1080P@60fps-> 32Mbps - * 4K@30fps -> 62Mbps - */ - private static int getDefaultBitrate(int width, int height, float frameRate) { - return (int) (width * height * frameRate * BPP); - } - - /** - * Query the bitrate from CamcorderProfile. If there are two profiles that match the - * width/height/framerate, we will use the higher one to get better quality. - * Return default bitrate if could not find any match profile. - */ - private static int getAVCBitrate(int width, int height, float frameRate) { - int bitrate = -1; - int[] cameraIds = {0, 1}; - - // Profiles ordered in decreasing order of preference. - int[] preferQualities = { - CamcorderProfile.QUALITY_2160P, - CamcorderProfile.QUALITY_1080P, - CamcorderProfile.QUALITY_720P, - CamcorderProfile.QUALITY_480P, - CamcorderProfile.QUALITY_LOW, - }; - - for (int cameraId : cameraIds) { - for (int quality : preferQualities) { - // Check if camera id has profile for the quality level. - if (!CamcorderProfile.hasProfile(cameraId, quality)) { - continue; - } - CamcorderProfile profile = CamcorderProfile.get(cameraId, quality); - // Check the width/height/framerate/codec, also consider portrait case. - if (((width == profile.videoFrameWidth - && height == profile.videoFrameHeight) - || (height == profile.videoFrameWidth - && width == profile.videoFrameHeight)) - && (int) frameRate == profile.videoFrameRate - && profile.videoCodec == MediaRecorder.VideoEncoder.H264) { - if (bitrate < profile.videoBitRate) { - bitrate = profile.videoBitRate; - } - break; - } - } - } - - if (bitrate == -1) { - Log.w(TAG, "Failed to find CamcorderProfile for w: " + width + "h: " + height - + " fps: " - + frameRate); - bitrate = getDefaultBitrate(width, height, frameRate); - } - Log.d(TAG, "Using bitrate " + bitrate + " for " + width + " " + height + " " - + frameRate); - return bitrate; - } - - /** - * Retrieves the audio track format to be used for transcoding. - * - * @return the audio track format to be used if transcoding should be performed, and - * null otherwise. - * @hide - */ - @Nullable - public MediaFormat resolveAudioFormat() { - if (!shouldTranscode()) { - return null; - } - // Audio transcoding is not supported yet, always return null. - return null; - } - } - } - - /** - * VideoTranscodingRequest encapsulates the configuration for transcoding a video. - */ - public static final class VideoTranscodingRequest extends TranscodingRequest { - /** - * Desired output video format of the destination file. - * <p> If this is null, source file's video track will be passed through and copied to the - * destination file. - */ - private @Nullable MediaFormat mVideoTrackFormat = null; - - /** - * Desired output audio format of the destination file. - * <p> If this is null, source file's audio track will be passed through and copied to the - * destination file. - */ - private @Nullable MediaFormat mAudioTrackFormat = null; - - private VideoTranscodingRequest(VideoTranscodingRequest.Builder builder) { - super(builder); - mVideoTrackFormat = builder.mVideoTrackFormat; - mAudioTrackFormat = builder.mAudioTrackFormat; - } - - /** - * Return the video track format of the transcoding. - * This will be null if client has not specified the video track format. - */ - @NonNull - public MediaFormat getVideoTrackFormat() { - return mVideoTrackFormat; - } - - @Override - void writeFormatToParcel(TranscodingRequestParcel parcel) { - parcel.requestedVideoTrackFormat = convertToVideoTrackFormat(mVideoTrackFormat); - } - - /* Converts the MediaFormat to TranscodingVideoTrackFormat. */ - private static TranscodingVideoTrackFormat convertToVideoTrackFormat(MediaFormat format) { - if (format == null) { - throw new IllegalArgumentException("Invalid MediaFormat"); - } - - TranscodingVideoTrackFormat trackFormat = new TranscodingVideoTrackFormat(); - - if (format.containsKey(MediaFormat.KEY_MIME)) { - String mime = format.getString(MediaFormat.KEY_MIME); - if (MediaFormat.MIMETYPE_VIDEO_AVC.equals(mime)) { - trackFormat.codecType = TranscodingVideoCodecType.kAvc; - } else if (MediaFormat.MIMETYPE_VIDEO_HEVC.equals(mime)) { - trackFormat.codecType = TranscodingVideoCodecType.kHevc; - } else { - throw new UnsupportedOperationException("Only support transcode to avc/hevc"); - } - } - - if (format.containsKey(MediaFormat.KEY_BIT_RATE)) { - int bitrateBps = format.getInteger(MediaFormat.KEY_BIT_RATE); - if (bitrateBps <= 0) { - throw new IllegalArgumentException("Bitrate must be larger than 0"); - } - trackFormat.bitrateBps = bitrateBps; - } - - if (format.containsKey(MediaFormat.KEY_WIDTH) && format.containsKey( - MediaFormat.KEY_HEIGHT)) { - int width = format.getInteger(MediaFormat.KEY_WIDTH); - int height = format.getInteger(MediaFormat.KEY_HEIGHT); - if (width <= 0 || height <= 0) { - throw new IllegalArgumentException("Width and height must be larger than 0"); - } - // TODO: Validate the aspect ratio after adding scaling. - trackFormat.width = width; - trackFormat.height = height; - } - - if (format.containsKey(MediaFormat.KEY_PROFILE)) { - int profile = format.getInteger(MediaFormat.KEY_PROFILE); - if (profile <= 0) { - throw new IllegalArgumentException("Invalid codec profile"); - } - // TODO: Validate the profile according to codec type. - trackFormat.profile = profile; - } - - if (format.containsKey(MediaFormat.KEY_LEVEL)) { - int level = format.getInteger(MediaFormat.KEY_LEVEL); - if (level <= 0) { - throw new IllegalArgumentException("Invalid codec level"); - } - // TODO: Validate the level according to codec type. - trackFormat.level = level; - } - - return trackFormat; - } - - /** - * Builder class for {@link VideoTranscodingRequest}. - */ - public static final class Builder extends - TranscodingRequest.Builder<VideoTranscodingRequest.Builder> { - /** - * Desired output video format of the destination file. - * <p> If this is null, source file's video track will be passed through and - * copied to the destination file. - */ - private @Nullable MediaFormat mVideoTrackFormat = null; - - /** - * Desired output audio format of the destination file. - * <p> If this is null, source file's audio track will be passed through and copied - * to the destination file. - */ - private @Nullable MediaFormat mAudioTrackFormat = null; - - /** - * Creates a builder for building {@link VideoTranscodingRequest}s. - * - * <p> Client could only specify the settings that matters to them, e.g. codec format or - * bitrate. And by default, transcoding will preserve the original video's settings - * (bitrate, framerate, resolution) if not provided. - * <p>Note that some settings may silently fail to apply if the device does not support - * them. - * @param sourceUri Content uri for the source media file. - * @param destinationUri Content uri for the destination media file. - * @param videoFormat MediaFormat containing the settings that client wants override in - * the original video's video track. - * @throws IllegalArgumentException if videoFormat is invalid. - */ - public Builder(@NonNull Uri sourceUri, @NonNull Uri destinationUri, - @NonNull MediaFormat videoFormat) { - super(TRANSCODING_TYPE_VIDEO, sourceUri, destinationUri); - setVideoTrackFormat(videoFormat); - } - - @Override - @NonNull - public Builder setClientUid(int uid) { - super.setClientUid(uid); - return self(); - } - - @Override - @NonNull - public Builder setClientPid(int pid) { - super.setClientPid(pid); - return self(); - } - - @Override - @NonNull - public Builder setSourceFileDescriptor(@NonNull ParcelFileDescriptor fd) { - super.setSourceFileDescriptor(fd); - return self(); - } - - @Override - @NonNull - public Builder setDestinationFileDescriptor(@NonNull ParcelFileDescriptor fd) { - super.setDestinationFileDescriptor(fd); - return self(); - } - - private void setVideoTrackFormat(@NonNull MediaFormat videoFormat) { - if (videoFormat == null) { - throw new IllegalArgumentException("videoFormat must not be null"); - } - - // Check if the MediaFormat is for video by looking at the MIME type. - String mime = videoFormat.containsKey(MediaFormat.KEY_MIME) - ? videoFormat.getString(MediaFormat.KEY_MIME) : null; - if (mime == null || !mime.startsWith("video/")) { - throw new IllegalArgumentException("Invalid video format: wrong mime type"); - } - - mVideoTrackFormat = videoFormat; - } - - /** - * @return a new {@link TranscodingRequest} instance successfully initialized - * with all the parameters set on this <code>Builder</code>. - * @throws UnsupportedOperationException if the parameters set on the - * <code>Builder</code> were incompatible, or - * if they are not supported by the - * device. - */ - @NonNull - public VideoTranscodingRequest build() { - return new VideoTranscodingRequest(this); - } - - @Override - VideoTranscodingRequest.Builder self() { - return this; - } - } - } - - /** - * Handle to an enqueued transcoding operation. An instance of this class represents a single - * enqueued transcoding operation. The caller can use that instance to query the status or - * progress, and to get the result once the operation has completed. - */ - public static final class TranscodingSession { - /** The session is enqueued but not yet running. */ - public static final int STATUS_PENDING = 1; - /** The session is currently running. */ - public static final int STATUS_RUNNING = 2; - /** The session is finished. */ - public static final int STATUS_FINISHED = 3; - /** The session is paused. */ - public static final int STATUS_PAUSED = 4; - - /** @hide */ - @IntDef(prefix = { "STATUS_" }, value = { - STATUS_PENDING, - STATUS_RUNNING, - STATUS_FINISHED, - STATUS_PAUSED, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface Status {} - - /** The session does not have a result yet. */ - public static final int RESULT_NONE = 1; - /** The session completed successfully. */ - public static final int RESULT_SUCCESS = 2; - /** The session encountered an error while running. */ - public static final int RESULT_ERROR = 3; - /** The session was canceled by the caller. */ - public static final int RESULT_CANCELED = 4; - - /** @hide */ - @IntDef(prefix = { "RESULT_" }, value = { - RESULT_NONE, - RESULT_SUCCESS, - RESULT_ERROR, - RESULT_CANCELED, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface Result {} - - - // The error code exposed here should be in sync with: - // frameworks/av/media/libmediatranscoding/aidl/android/media/TranscodingErrorCode.aidl - /** @hide */ - @IntDef(prefix = { "TRANSCODING_SESSION_ERROR_" }, value = { - ERROR_NONE, - ERROR_DROPPED_BY_SERVICE, - ERROR_SERVICE_DIED}) - @Retention(RetentionPolicy.SOURCE) - public @interface TranscodingSessionErrorCode{} - /** - * Constant indicating that no error occurred. - */ - public static final int ERROR_NONE = 0; - - /** - * Constant indicating that the session is dropped by Transcoding service due to hitting - * the limit, e.g. too many back to back transcoding happen in a short time frame. - */ - public static final int ERROR_DROPPED_BY_SERVICE = 1; - - /** - * Constant indicating the backing transcoding service is died. Client should enqueue the - * the request again. - */ - public static final int ERROR_SERVICE_DIED = 2; - - /** Listener that gets notified when the progress changes. */ - @FunctionalInterface - public interface OnProgressUpdateListener { - /** - * Called when the progress changes. The progress is in percentage between 0 and 1, - * where 0 means the session has not yet started and 100 means that it has finished. - * - * @param session The session associated with the progress. - * @param progress The new progress ranging from 0 ~ 100 inclusive. - */ - void onProgressUpdate(@NonNull TranscodingSession session, - @IntRange(from = 0, to = 100) int progress); - } - - private final MediaTranscodingManager mManager; - private Executor mListenerExecutor; - private OnTranscodingFinishedListener mListener; - private int mSessionId = -1; - // Lock for internal state. - private final Object mLock = new Object(); - @GuardedBy("mLock") - private Executor mProgressUpdateExecutor = null; - @GuardedBy("mLock") - private OnProgressUpdateListener mProgressUpdateListener = null; - @GuardedBy("mLock") - private int mProgress = 0; - @GuardedBy("mLock") - private int mProgressUpdateInterval = 0; - @GuardedBy("mLock") - private @Status int mStatus = STATUS_PENDING; - @GuardedBy("mLock") - private @Result int mResult = RESULT_NONE; - @GuardedBy("mLock") - private @TranscodingSessionErrorCode int mErrorCode = ERROR_NONE; - @GuardedBy("mLock") - private boolean mHasRetried = false; - // The original request that associated with this session. - private final TranscodingRequest mRequest; - - private TranscodingSession( - @NonNull MediaTranscodingManager manager, - @NonNull TranscodingRequest request, - @NonNull TranscodingSessionParcel parcel, - @NonNull @CallbackExecutor Executor executor, - @NonNull OnTranscodingFinishedListener listener) { - Objects.requireNonNull(manager, "manager must not be null"); - Objects.requireNonNull(parcel, "parcel must not be null"); - Objects.requireNonNull(executor, "listenerExecutor must not be null"); - Objects.requireNonNull(listener, "listener must not be null"); - mManager = manager; - mSessionId = parcel.sessionId; - mListenerExecutor = executor; - mListener = listener; - mRequest = request; - } - - /** - * Set a progress listener. - * @param executor The executor on which listener will be invoked. - * @param listener The progress listener. - */ - public void setOnProgressUpdateListener( - @NonNull @CallbackExecutor Executor executor, - @Nullable OnProgressUpdateListener listener) { - synchronized (mLock) { - Objects.requireNonNull(executor, "listenerExecutor must not be null"); - Objects.requireNonNull(listener, "listener must not be null"); - mProgressUpdateExecutor = executor; - mProgressUpdateListener = listener; - } - } - - private void updateStatusAndResult(@Status int sessionStatus, - @Result int sessionResult, @TranscodingSessionErrorCode int errorCode) { - synchronized (mLock) { - mStatus = sessionStatus; - mResult = sessionResult; - mErrorCode = errorCode; - } - } - - /** - * Retrieve the error code associated with the RESULT_ERROR. - */ - public @TranscodingSessionErrorCode int getErrorCode() { - synchronized (mLock) { - return mErrorCode; - } - } - - /** - * Resubmit the transcoding session to the service. - * Note that only the session that fails or gets cancelled could be retried and each session - * could be retried only once. After that, Client need to enqueue a new request if they want - * to try again. - * - * @return true if successfully resubmit the job to service. False otherwise. - * @throws UnsupportedOperationException if the retry could not be fulfilled. - * @hide - */ - public boolean retry() { - return retryInternal(true /*setHasRetried*/); - } - - // TODO(hkuang): Add more test for it. - private boolean retryInternal(boolean setHasRetried) { - synchronized (mLock) { - if (mStatus == STATUS_PENDING || mStatus == STATUS_RUNNING) { - throw new UnsupportedOperationException( - "Failed to retry as session is in processing"); - } - - if (mHasRetried) { - throw new UnsupportedOperationException("Session has been retried already"); - } - - // Get the client interface. - ITranscodingClient client = mManager.getTranscodingClient(); - if (client == null) { - Log.e(TAG, "Service rebooting. Try again later"); - return false; - } - - synchronized (mManager.mPendingTranscodingSessions) { - try { - // Submits the request to MediaTranscoding service. - TranscodingSessionParcel sessionParcel = new TranscodingSessionParcel(); - if (!client.submitRequest(mRequest.writeToParcel(mManager.mContext), - sessionParcel)) { - mHasRetried = true; - throw new UnsupportedOperationException("Failed to enqueue request"); - } - - // Replace the old session id wit the new one. - mSessionId = sessionParcel.sessionId; - // Adds the new session back into pending sessions. - mManager.mPendingTranscodingSessions.put(mSessionId, this); - } catch (RemoteException re) { - return false; - } - mStatus = STATUS_PENDING; - mHasRetried = setHasRetried ? true : false; - } - } - return true; - } - - /** - * Cancels the transcoding session and notify the listener. - * If the session happened to finish before being canceled this call is effectively a no-op - * and will not update the result in that case. - */ - public void cancel() { - synchronized (mLock) { - // Check if the session is finished already. - if (mStatus != STATUS_FINISHED) { - try { - ITranscodingClient client = mManager.getTranscodingClient(); - // The client may be gone. - if (client != null) { - client.cancelSession(mSessionId); - } - } catch (RemoteException re) { - //TODO(hkuang): Find out what to do if failing to cancel the session. - Log.e(TAG, "Failed to cancel the session due to exception: " + re); - } - mStatus = STATUS_FINISHED; - mResult = RESULT_CANCELED; - - // Notifies client the session is canceled. - mListenerExecutor.execute(() -> mListener.onTranscodingFinished(this)); - } - } - } - - /** - * Gets the progress of the transcoding session. The progress is between 0 and 100, where 0 - * means that the session has not yet started and 100 means that it is finished. For the - * cancelled session, the progress will be the last updated progress before it is cancelled. - * @return The progress. - */ - @IntRange(from = 0, to = 100) - public int getProgress() { - synchronized (mLock) { - return mProgress; - } - } - - /** - * Gets the status of the transcoding session. - * @return The status. - */ - public @Status int getStatus() { - synchronized (mLock) { - return mStatus; - } - } - - /** - * Adds a client uid that is also waiting for this transcoding session. - * <p> - * Only privilege caller with android.permission.WRITE_MEDIA_STORAGE could add the - * uid. Note that the permission check happens on the service side upon starting the - * transcoding. If the client does not have the permission, the transcoding will fail. - * @param uid the additional client uid to be added. - * @return true if successfully added, false otherwise. - */ - public boolean addClientUid(int uid) { - if (uid < 0) { - throw new IllegalArgumentException("Invalid Uid"); - } - - // Get the client interface. - ITranscodingClient client = mManager.getTranscodingClient(); - if (client == null) { - Log.e(TAG, "Service is dead..."); - return false; - } - - try { - if (!client.addClientUid(mSessionId, uid)) { - Log.e(TAG, "Failed to add client uid"); - return false; - } - } catch (Exception ex) { - Log.e(TAG, "Failed to get client uids due to " + ex); - return false; - } - return true; - } - - /** - * Query all the client that waiting for this transcoding session - * @return a list containing all the client uids. - */ - @NonNull - public List<Integer> getClientUids() { - List<Integer> uidList = new ArrayList<Integer>(); - - // Get the client interface. - ITranscodingClient client = mManager.getTranscodingClient(); - if (client == null) { - Log.e(TAG, "Service is dead..."); - return uidList; - } - - try { - int[] clientUids = client.getClientUids(mSessionId); - for (int i : clientUids) { - uidList.add(i); - } - } catch (Exception ex) { - Log.e(TAG, "Failed to get client uids due to " + ex); - } - - return uidList; - } - - /** - * Gets sessionId of the transcoding session. - * @return session id. - */ - public int getSessionId() { - return mSessionId; - } - - /** - * Gets the result of the transcoding session. - * @return The result. - */ - public @Result int getResult() { - synchronized (mLock) { - return mResult; - } - } - - @Override - public String toString() { - String result; - String status; - - switch (mResult) { - case RESULT_NONE: - result = "RESULT_NONE"; - break; - case RESULT_SUCCESS: - result = "RESULT_SUCCESS"; - break; - case RESULT_ERROR: - result = "RESULT_ERROR(" + mErrorCode + ")"; - break; - case RESULT_CANCELED: - result = "RESULT_CANCELED"; - break; - default: - result = String.valueOf(mResult); - break; - } - - switch (mStatus) { - case STATUS_PENDING: - status = "STATUS_PENDING"; - break; - case STATUS_PAUSED: - status = "STATUS_PAUSED"; - break; - case STATUS_RUNNING: - status = "STATUS_RUNNING"; - break; - case STATUS_FINISHED: - status = "STATUS_FINISHED"; - break; - default: - status = String.valueOf(mStatus); - break; - } - return String.format(" session: {id: %d, status: %s, result: %s, progress: %d}", - mSessionId, status, result, mProgress); - } - - private void updateProgress(int newProgress) { - synchronized (mLock) { - mProgress = newProgress; - } - } - - private void updateStatus(int newStatus) { - synchronized (mLock) { - mStatus = newStatus; - } - } - } - - private ITranscodingClient getTranscodingClient() { - synchronized (mLock) { - return mTranscodingClient; - } - } - - /** - * Enqueues a TranscodingRequest for execution. - * <p> Upon successfully accepting the request, MediaTranscodingManager will return a - * {@link TranscodingSession} to the client. Client should use {@link TranscodingSession} to - * track the progress and get the result. - * <p> MediaTranscodingManager will return null if fails to accept the request due to service - * rebooting. Client could retry again after receiving null. - * - * @param transcodingRequest The TranscodingRequest to enqueue. - * @param listenerExecutor Executor on which the listener is notified. - * @param listener Listener to get notified when the transcoding session is finished. - * @return A TranscodingSession for this operation. - * @throws UnsupportedOperationException if the request could not be fulfilled. - */ - @Nullable - public TranscodingSession enqueueRequest( - @NonNull TranscodingRequest transcodingRequest, - @NonNull @CallbackExecutor Executor listenerExecutor, - @NonNull OnTranscodingFinishedListener listener) { - Log.i(TAG, "enqueueRequest called."); - Objects.requireNonNull(transcodingRequest, "transcodingRequest must not be null"); - Objects.requireNonNull(listenerExecutor, "listenerExecutor must not be null"); - Objects.requireNonNull(listener, "listener must not be null"); - - // Converts the request to TranscodingRequestParcel. - TranscodingRequestParcel requestParcel = transcodingRequest.writeToParcel(mContext); - - Log.i(TAG, "Getting transcoding request " + transcodingRequest.getSourceUri()); - - // Submits the request to MediaTranscoding service. - try { - TranscodingSessionParcel sessionParcel = new TranscodingSessionParcel(); - // Synchronizes the access to mPendingTranscodingSessions to make sure the session Id is - // inserted in the mPendingTranscodingSessions in the callback handler. - synchronized (mPendingTranscodingSessions) { - synchronized (mLock) { - if (mTranscodingClient == null) { - // Try to register with the service again. - IMediaTranscodingService service = getService(false /*retry*/); - if (service == null) { - Log.w(TAG, "Service rebooting. Try again later"); - return null; - } - mTranscodingClient = registerClient(service); - // If still fails, throws an exception to tell client to try later. - if (mTranscodingClient == null) { - Log.w(TAG, "Service rebooting. Try again later"); - return null; - } - } - - if (!mTranscodingClient.submitRequest(requestParcel, sessionParcel)) { - throw new UnsupportedOperationException("Failed to enqueue request"); - } - } - - // Wraps the TranscodingSessionParcel into a TranscodingSession and returns it to - // client for tracking. - TranscodingSession session = new TranscodingSession(this, transcodingRequest, - sessionParcel, - listenerExecutor, - listener); - - // Adds the new session into pending sessions. - mPendingTranscodingSessions.put(session.getSessionId(), session); - return session; - } - } catch (RemoteException ex) { - Log.w(TAG, "Service rebooting. Try again later"); - return null; - } catch (ServiceSpecificException ex) { - throw new UnsupportedOperationException( - "Failed to submit request to Transcoding service. Error: " + ex); - } - } -} diff --git a/apex/media/framework/java/android/media/ProxyDataSourceCallback.java b/apex/media/framework/java/android/media/ProxyDataSourceCallback.java deleted file mode 100644 index 14d3ce87f03d..000000000000 --- a/apex/media/framework/java/android/media/ProxyDataSourceCallback.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2019 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 android.media; - -import android.os.ParcelFileDescriptor; -import android.system.ErrnoException; -import android.system.Os; -import android.system.OsConstants; -import android.util.Log; - -import java.io.FileDescriptor; -import java.io.IOException; - -/** - * A DataSourceCallback that is backed by a ParcelFileDescriptor. - */ -class ProxyDataSourceCallback extends DataSourceCallback { - private static final String TAG = "TestDataSourceCallback"; - - ParcelFileDescriptor mPFD; - FileDescriptor mFD; - - ProxyDataSourceCallback(ParcelFileDescriptor pfd) throws IOException { - mPFD = pfd.dup(); - mFD = mPFD.getFileDescriptor(); - } - - @Override - public synchronized int readAt(long position, byte[] buffer, int offset, int size) - throws IOException { - try { - Os.lseek(mFD, position, OsConstants.SEEK_SET); - int ret = Os.read(mFD, buffer, offset, size); - return (ret == 0) ? END_OF_STREAM : ret; - } catch (ErrnoException e) { - throw new IOException(e); - } - } - - @Override - public synchronized long getSize() throws IOException { - return mPFD.getStatSize(); - } - - @Override - public synchronized void close() { - try { - mPFD.close(); - } catch (IOException e) { - Log.e(TAG, "Failed to close the PFD.", e); - } - } -} - diff --git a/apex/media/framework/java/android/media/RoutingDelegate.java b/apex/media/framework/java/android/media/RoutingDelegate.java deleted file mode 100644 index 23598130f391..000000000000 --- a/apex/media/framework/java/android/media/RoutingDelegate.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2018 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 android.media; - -import android.os.Handler; - -class RoutingDelegate implements AudioRouting.OnRoutingChangedListener { - private AudioRouting mAudioRouting; - private AudioRouting.OnRoutingChangedListener mOnRoutingChangedListener; - private Handler mHandler; - - RoutingDelegate(final AudioRouting audioRouting, - final AudioRouting.OnRoutingChangedListener listener, - Handler handler) { - mAudioRouting = audioRouting; - mOnRoutingChangedListener = listener; - mHandler = handler; - } - - public AudioRouting.OnRoutingChangedListener getListener() { - return mOnRoutingChangedListener; - } - - public Handler getHandler() { - return mHandler; - } - - @Override - public void onRoutingChanged(AudioRouting router) { - if (mOnRoutingChangedListener != null) { - mOnRoutingChangedListener.onRoutingChanged(mAudioRouting); - } - } -} diff --git a/apex/media/framework/java/android/media/Session2Command.java b/apex/media/framework/java/android/media/Session2Command.java deleted file mode 100644 index 26f4568fa7e5..000000000000 --- a/apex/media/framework/java/android/media/Session2Command.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright 2018 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 android.media; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.os.Bundle; -import android.os.Parcel; -import android.os.Parcelable; -import android.text.TextUtils; - -import java.util.Objects; - -/** - * This API is not generally intended for third party application developers. - * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a> - * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session - * Library</a> for consistent behavior across all devices. - * <p> - * Define a command that a {@link MediaController2} can send to a {@link MediaSession2}. - * <p> - * If {@link #getCommandCode()} isn't {@link #COMMAND_CODE_CUSTOM}), it's predefined command. - * If {@link #getCommandCode()} is {@link #COMMAND_CODE_CUSTOM}), it's custom command and - * {@link #getCustomAction()} shouldn't be {@code null}. - * <p> - * Refer to the - * <a href="{@docRoot}reference/androidx/media2/SessionCommand2.html">AndroidX SessionCommand</a> - * class for the list of valid commands. - */ -public final class Session2Command implements Parcelable { - /** - * Command code for the custom command which can be defined by string action in the - * {@link Session2Command}. - */ - public static final int COMMAND_CODE_CUSTOM = 0; - - public static final @android.annotation.NonNull Parcelable.Creator<Session2Command> CREATOR = - new Parcelable.Creator<Session2Command>() { - @Override - public Session2Command createFromParcel(Parcel in) { - return new Session2Command(in); - } - - @Override - public Session2Command[] newArray(int size) { - return new Session2Command[size]; - } - }; - - private final int mCommandCode; - // Nonnull if it's custom command - private final String mCustomAction; - private final Bundle mCustomExtras; - - /** - * Constructor for creating a command predefined in AndroidX media2. - * - * @param commandCode A command code for a command predefined in AndroidX media2. - */ - public Session2Command(int commandCode) { - if (commandCode == COMMAND_CODE_CUSTOM) { - throw new IllegalArgumentException("commandCode shouldn't be COMMAND_CODE_CUSTOM"); - } - mCommandCode = commandCode; - mCustomAction = null; - mCustomExtras = null; - } - - /** - * Constructor for creating a custom command. - * - * @param action The action of this custom command. - * @param extras An extra bundle for this custom command. - */ - public Session2Command(@NonNull String action, @Nullable Bundle extras) { - if (action == null) { - throw new IllegalArgumentException("action shouldn't be null"); - } - mCommandCode = COMMAND_CODE_CUSTOM; - mCustomAction = action; - mCustomExtras = extras; - } - - /** - * Used by parcelable creator. - */ - @SuppressWarnings("WeakerAccess") /* synthetic access */ - Session2Command(Parcel in) { - mCommandCode = in.readInt(); - mCustomAction = in.readString(); - mCustomExtras = in.readBundle(); - } - - /** - * Gets the command code of a predefined command. - * This will return {@link #COMMAND_CODE_CUSTOM} for a custom command. - */ - public int getCommandCode() { - return mCommandCode; - } - - /** - * Gets the action of a custom command. - * This will return {@code null} for a predefined command. - */ - @Nullable - public String getCustomAction() { - return mCustomAction; - } - - /** - * Gets the extra bundle of a custom command. - * This will return {@code null} for a predefined command. - */ - @Nullable - public Bundle getCustomExtras() { - return mCustomExtras; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - if (dest == null) { - throw new IllegalArgumentException("parcel shouldn't be null"); - } - dest.writeInt(mCommandCode); - dest.writeString(mCustomAction); - dest.writeBundle(mCustomExtras); - } - - @Override - public boolean equals(@Nullable Object obj) { - if (!(obj instanceof Session2Command)) { - return false; - } - Session2Command other = (Session2Command) obj; - return mCommandCode == other.mCommandCode - && TextUtils.equals(mCustomAction, other.mCustomAction); - } - - @Override - public int hashCode() { - return Objects.hash(mCustomAction, mCommandCode); - } - - /** - * This API is not generally intended for third party application developers. - * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a> - * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session - * Library</a> for consistent behavior across all devices. - * <p> - * Contains the result of {@link Session2Command}. - */ - public static final class Result { - private final int mResultCode; - private final Bundle mResultData; - - /** - * Result code representing that the command is skipped or canceled. For an example, a seek - * command can be skipped if it is followed by another seek command. - */ - public static final int RESULT_INFO_SKIPPED = 1; - - /** - * Result code representing that the command is successfully completed. - */ - public static final int RESULT_SUCCESS = 0; - - /** - * Result code represents that call is ended with an unknown error. - */ - public static final int RESULT_ERROR_UNKNOWN_ERROR = -1; - - /** - * Constructor of {@link Result}. - * - * @param resultCode result code - * @param resultData result data - */ - public Result(int resultCode, @Nullable Bundle resultData) { - mResultCode = resultCode; - mResultData = resultData; - } - - /** - * Returns the result code. - */ - public int getResultCode() { - return mResultCode; - } - - /** - * Returns the result data. - */ - @Nullable - public Bundle getResultData() { - return mResultData; - } - } -} diff --git a/apex/media/framework/java/android/media/Session2CommandGroup.java b/apex/media/framework/java/android/media/Session2CommandGroup.java deleted file mode 100644 index 13aabfc45ab7..000000000000 --- a/apex/media/framework/java/android/media/Session2CommandGroup.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright 2018 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 android.media; - -import static android.media.Session2Command.COMMAND_CODE_CUSTOM; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.os.Parcel; -import android.os.Parcelable; - -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - -/** - * This API is not generally intended for third party application developers. - * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a> - * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session - * Library</a> for consistent behavior across all devices. - * <p> - * A set of {@link Session2Command} which represents a command group. - */ -public final class Session2CommandGroup implements Parcelable { - private static final String TAG = "Session2CommandGroup"; - - public static final @android.annotation.NonNull Parcelable.Creator<Session2CommandGroup> - CREATOR = new Parcelable.Creator<Session2CommandGroup>() { - @Override - public Session2CommandGroup createFromParcel(Parcel in) { - return new Session2CommandGroup(in); - } - - @Override - public Session2CommandGroup[] newArray(int size) { - return new Session2CommandGroup[size]; - } - }; - - Set<Session2Command> mCommands = new HashSet<>(); - - /** - * Creates a new Session2CommandGroup with commands copied from another object. - * - * @param commands The collection of commands to copy. - */ - @SuppressWarnings("WeakerAccess") /* synthetic access */ - Session2CommandGroup(@Nullable Collection<Session2Command> commands) { - if (commands != null) { - mCommands.addAll(commands); - } - } - - /** - * Used by parcelable creator. - */ - @SuppressWarnings("WeakerAccess") /* synthetic access */ - Session2CommandGroup(Parcel in) { - Parcelable[] commands = in.readParcelableArray(Session2Command.class.getClassLoader()); - if (commands != null) { - for (Parcelable command : commands) { - mCommands.add((Session2Command) command); - } - } - } - - /** - * Checks whether this command group has a command that matches given {@code command}. - * - * @param command A command to find. Shouldn't be {@code null}. - */ - public boolean hasCommand(@NonNull Session2Command command) { - if (command == null) { - throw new IllegalArgumentException("command shouldn't be null"); - } - return mCommands.contains(command); - } - - /** - * Checks whether this command group has a command that matches given {@code commandCode}. - * - * @param commandCode A command code to find. - * Shouldn't be {@link Session2Command#COMMAND_CODE_CUSTOM}. - */ - public boolean hasCommand(int commandCode) { - if (commandCode == COMMAND_CODE_CUSTOM) { - throw new IllegalArgumentException("Use hasCommand(Command) for custom command"); - } - for (Session2Command command : mCommands) { - if (command.getCommandCode() == commandCode) { - return true; - } - } - return false; - } - - /** - * Gets all commands of this command group. - */ - @NonNull - public Set<Session2Command> getCommands() { - return new HashSet<>(mCommands); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - if (dest == null) { - throw new IllegalArgumentException("parcel shouldn't be null"); - } - dest.writeParcelableArray(mCommands.toArray(new Session2Command[0]), 0); - } - - /** - * This API is not generally intended for third party application developers. - * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a> - * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session - * Library</a> for consistent behavior across all devices. - * <p> - * Builds a {@link Session2CommandGroup} object. - */ - public static final class Builder { - private Set<Session2Command> mCommands; - - public Builder() { - mCommands = new HashSet<>(); - } - - /** - * Creates a new builder for {@link Session2CommandGroup} with commands copied from another - * {@link Session2CommandGroup} object. - * @param commandGroup - */ - public Builder(@NonNull Session2CommandGroup commandGroup) { - if (commandGroup == null) { - throw new IllegalArgumentException("command group shouldn't be null"); - } - mCommands = commandGroup.getCommands(); - } - - /** - * Adds a command to this command group. - * - * @param command A command to add. Shouldn't be {@code null}. - */ - @NonNull - public Builder addCommand(@NonNull Session2Command command) { - if (command == null) { - throw new IllegalArgumentException("command shouldn't be null"); - } - mCommands.add(command); - return this; - } - - /** - * Removes a command from this group which matches given {@code command}. - * - * @param command A command to find. Shouldn't be {@code null}. - */ - @NonNull - public Builder removeCommand(@NonNull Session2Command command) { - if (command == null) { - throw new IllegalArgumentException("command shouldn't be null"); - } - mCommands.remove(command); - return this; - } - - /** - * Builds {@link Session2CommandGroup}. - * - * @return a new {@link Session2CommandGroup}. - */ - @NonNull - public Session2CommandGroup build() { - return new Session2CommandGroup(mCommands); - } - } -} diff --git a/apex/media/framework/java/android/media/Session2Link.java b/apex/media/framework/java/android/media/Session2Link.java deleted file mode 100644 index 6e550e86a9fe..000000000000 --- a/apex/media/framework/java/android/media/Session2Link.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright 2018 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 android.media; - -import android.annotation.NonNull; -import android.os.Binder; -import android.os.Bundle; -import android.os.IBinder; -import android.os.Parcel; -import android.os.Parcelable; -import android.os.RemoteException; -import android.os.ResultReceiver; -import android.util.Log; - -import java.util.Objects; - -/** - * Handles incoming commands from {@link MediaController2} to {@link MediaSession2}. - * @hide - */ -// @SystemApi -public final class Session2Link implements Parcelable { - private static final String TAG = "Session2Link"; - private static final boolean DEBUG = MediaSession2.DEBUG; - - public static final @android.annotation.NonNull Parcelable.Creator<Session2Link> CREATOR = - new Parcelable.Creator<Session2Link>() { - @Override - public Session2Link createFromParcel(Parcel in) { - return new Session2Link(in); - } - - @Override - public Session2Link[] newArray(int size) { - return new Session2Link[size]; - } - }; - - private final MediaSession2 mSession; - private final IMediaSession2 mISession; - - public Session2Link(MediaSession2 session) { - mSession = session; - mISession = new Session2Stub(); - } - - Session2Link(Parcel in) { - mSession = null; - mISession = IMediaSession2.Stub.asInterface(in.readStrongBinder()); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeStrongBinder(mISession.asBinder()); - } - - @Override - public int hashCode() { - return mISession.asBinder().hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof Session2Link)) { - return false; - } - Session2Link other = (Session2Link) obj; - return Objects.equals(mISession.asBinder(), other.mISession.asBinder()); - } - - /** Link to death with mISession */ - public void linkToDeath(@NonNull IBinder.DeathRecipient recipient, int flags) { - if (mISession != null) { - try { - mISession.asBinder().linkToDeath(recipient, flags); - } catch (RemoteException e) { - if (DEBUG) { - Log.d(TAG, "Session died too early.", e); - } - } - } - } - - /** Unlink to death with mISession */ - public boolean unlinkToDeath(@NonNull IBinder.DeathRecipient recipient, int flags) { - if (mISession != null) { - return mISession.asBinder().unlinkToDeath(recipient, flags); - } - return true; - } - - /** Interface method for IMediaSession2.connect */ - public void connect(final Controller2Link caller, int seq, Bundle connectionRequest) { - try { - mISession.connect(caller, seq, connectionRequest); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** Interface method for IMediaSession2.disconnect */ - public void disconnect(final Controller2Link caller, int seq) { - try { - mISession.disconnect(caller, seq); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** Interface method for IMediaSession2.sendSessionCommand */ - public void sendSessionCommand(final Controller2Link caller, final int seq, - final Session2Command command, final Bundle args, ResultReceiver resultReceiver) { - try { - mISession.sendSessionCommand(caller, seq, command, args, resultReceiver); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** Interface method for IMediaSession2.sendSessionCommand */ - public void cancelSessionCommand(final Controller2Link caller, final int seq) { - try { - mISession.cancelSessionCommand(caller, seq); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** Stub implementation for IMediaSession2.connect */ - public void onConnect(final Controller2Link caller, int pid, int uid, int seq, - Bundle connectionRequest) { - mSession.onConnect(caller, pid, uid, seq, connectionRequest); - } - - /** Stub implementation for IMediaSession2.disconnect */ - public void onDisconnect(final Controller2Link caller, int seq) { - mSession.onDisconnect(caller, seq); - } - - /** Stub implementation for IMediaSession2.sendSessionCommand */ - public void onSessionCommand(final Controller2Link caller, final int seq, - final Session2Command command, final Bundle args, ResultReceiver resultReceiver) { - mSession.onSessionCommand(caller, seq, command, args, resultReceiver); - } - - /** Stub implementation for IMediaSession2.cancelSessionCommand */ - public void onCancelCommand(final Controller2Link caller, final int seq) { - mSession.onCancelCommand(caller, seq); - } - - private class Session2Stub extends IMediaSession2.Stub { - @Override - public void connect(final Controller2Link caller, int seq, Bundle connectionRequest) { - if (caller == null || connectionRequest == null) { - return; - } - final int pid = Binder.getCallingPid(); - final int uid = Binder.getCallingUid(); - final long token = Binder.clearCallingIdentity(); - try { - Session2Link.this.onConnect(caller, pid, uid, seq, connectionRequest); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public void disconnect(final Controller2Link caller, int seq) { - if (caller == null) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { - Session2Link.this.onDisconnect(caller, seq); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public void sendSessionCommand(final Controller2Link caller, final int seq, - final Session2Command command, final Bundle args, ResultReceiver resultReceiver) { - if (caller == null) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { - Session2Link.this.onSessionCommand(caller, seq, command, args, resultReceiver); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public void cancelSessionCommand(final Controller2Link caller, final int seq) { - if (caller == null) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { - Session2Link.this.onCancelCommand(caller, seq); - } finally { - Binder.restoreCallingIdentity(token); - } - } - } -} diff --git a/apex/media/framework/java/android/media/Session2Token.java b/apex/media/framework/java/android/media/Session2Token.java deleted file mode 100644 index aae2e1bcb6df..000000000000 --- a/apex/media/framework/java/android/media/Session2Token.java +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright 2018 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 android.media; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.os.Bundle; -import android.os.Parcel; -import android.os.Parcelable; -import android.text.TextUtils; -import android.util.Log; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.List; -import java.util.Objects; - -/** - * This API is not generally intended for third party application developers. - * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a> - * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session - * Library</a> for consistent behavior across all devices. - * <p> - * Represents an ongoing {@link MediaSession2} or a {@link MediaSession2Service}. - * If it's representing a session service, it may not be ongoing. - * <p> - * This may be passed to apps by the session owner to allow them to create a - * {@link MediaController2} to communicate with the session. - * <p> - * It can be also obtained by {@link android.media.session.MediaSessionManager}. - */ -public final class Session2Token implements Parcelable { - private static final String TAG = "Session2Token"; - - public static final @android.annotation.NonNull Creator<Session2Token> CREATOR = - new Creator<Session2Token>() { - @Override - public Session2Token createFromParcel(Parcel p) { - return new Session2Token(p); - } - - @Override - public Session2Token[] newArray(int size) { - return new Session2Token[size]; - } - }; - - /** - * @hide - */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = "TYPE_", value = {TYPE_SESSION, TYPE_SESSION_SERVICE}) - public @interface TokenType { - } - - /** - * Type for {@link MediaSession2}. - */ - public static final int TYPE_SESSION = 0; - - /** - * Type for {@link MediaSession2Service}. - */ - public static final int TYPE_SESSION_SERVICE = 1; - - private final int mUid; - @TokenType - private final int mType; - private final String mPackageName; - private final String mServiceName; - private final Session2Link mSessionLink; - private final ComponentName mComponentName; - private final Bundle mExtras; - - /** - * Constructor for the token with type {@link #TYPE_SESSION_SERVICE}. - * - * @param context The context. - * @param serviceComponent The component name of the service. - */ - public Session2Token(@NonNull Context context, @NonNull ComponentName serviceComponent) { - if (context == null) { - throw new IllegalArgumentException("context shouldn't be null"); - } - if (serviceComponent == null) { - throw new IllegalArgumentException("serviceComponent shouldn't be null"); - } - - final PackageManager manager = context.getPackageManager(); - final int uid = getUid(manager, serviceComponent.getPackageName()); - - if (!isInterfaceDeclared(manager, MediaSession2Service.SERVICE_INTERFACE, - serviceComponent)) { - Log.w(TAG, serviceComponent + " doesn't implement MediaSession2Service."); - } - mComponentName = serviceComponent; - mPackageName = serviceComponent.getPackageName(); - mServiceName = serviceComponent.getClassName(); - mUid = uid; - mType = TYPE_SESSION_SERVICE; - mSessionLink = null; - mExtras = Bundle.EMPTY; - } - - Session2Token(int uid, int type, String packageName, Session2Link sessionLink, - @NonNull Bundle tokenExtras) { - mUid = uid; - mType = type; - mPackageName = packageName; - mServiceName = null; - mComponentName = null; - mSessionLink = sessionLink; - mExtras = tokenExtras; - } - - Session2Token(Parcel in) { - mUid = in.readInt(); - mType = in.readInt(); - mPackageName = in.readString(); - mServiceName = in.readString(); - mSessionLink = in.readParcelable(null); - mComponentName = ComponentName.unflattenFromString(in.readString()); - - Bundle extras = in.readBundle(); - if (extras == null) { - Log.w(TAG, "extras shouldn't be null."); - extras = Bundle.EMPTY; - } else if (MediaSession2.hasCustomParcelable(extras)) { - Log.w(TAG, "extras contain custom parcelable. Ignoring."); - extras = Bundle.EMPTY; - } - mExtras = extras; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mUid); - dest.writeInt(mType); - dest.writeString(mPackageName); - dest.writeString(mServiceName); - dest.writeParcelable(mSessionLink, flags); - dest.writeString(mComponentName == null ? "" : mComponentName.flattenToString()); - dest.writeBundle(mExtras); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public int hashCode() { - return Objects.hash(mType, mUid, mPackageName, mServiceName, mSessionLink); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof Session2Token)) { - return false; - } - Session2Token other = (Session2Token) obj; - return mUid == other.mUid - && TextUtils.equals(mPackageName, other.mPackageName) - && TextUtils.equals(mServiceName, other.mServiceName) - && mType == other.mType - && Objects.equals(mSessionLink, other.mSessionLink); - } - - @Override - public String toString() { - return "Session2Token {pkg=" + mPackageName + " type=" + mType - + " service=" + mServiceName + " Session2Link=" + mSessionLink + "}"; - } - - /** - * @return uid of the session - */ - public int getUid() { - return mUid; - } - - /** - * @return package name of the session - */ - @NonNull - public String getPackageName() { - return mPackageName; - } - - /** - * @return service name of the session. Can be {@code null} for {@link #TYPE_SESSION}. - */ - @Nullable - public String getServiceName() { - return mServiceName; - } - - /** - * @return type of the token - * @see #TYPE_SESSION - * @see #TYPE_SESSION_SERVICE - */ - public @TokenType int getType() { - return mType; - } - - /** - * @return extras of the token - * @see MediaSession2.Builder#setExtras(Bundle) - */ - @NonNull - public Bundle getExtras() { - return new Bundle(mExtras); - } - - Session2Link getSessionLink() { - return mSessionLink; - } - - private static boolean isInterfaceDeclared(PackageManager manager, String serviceInterface, - ComponentName serviceComponent) { - Intent serviceIntent = new Intent(serviceInterface); - // Use queryIntentServices to find services with MediaSession2Service.SERVICE_INTERFACE. - // We cannot use resolveService with intent specified class name, because resolveService - // ignores actions if Intent.setClassName() is specified. - serviceIntent.setPackage(serviceComponent.getPackageName()); - - List<ResolveInfo> list = manager.queryIntentServices( - serviceIntent, PackageManager.GET_META_DATA); - if (list != null) { - for (int i = 0; i < list.size(); i++) { - ResolveInfo resolveInfo = list.get(i); - if (resolveInfo == null || resolveInfo.serviceInfo == null) { - continue; - } - if (TextUtils.equals( - resolveInfo.serviceInfo.name, serviceComponent.getClassName())) { - return true; - } - } - } - return false; - } - - private static int getUid(PackageManager manager, String packageName) { - try { - return manager.getApplicationInfo(packageName, 0).uid; - } catch (PackageManager.NameNotFoundException e) { - throw new IllegalArgumentException("Cannot find package " + packageName); - } - } -} diff --git a/apex/media/framework/jni/android_media_MediaParserJNI.cpp b/apex/media/framework/jni/android_media_MediaParserJNI.cpp deleted file mode 100644 index c81152c0954c..000000000000 --- a/apex/media/framework/jni/android_media_MediaParserJNI.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2020, 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. - */ - -#include <jni.h> -#include <media/MediaMetrics.h> - -#define JNI_FUNCTION(RETURN_TYPE, NAME, ...) \ - extern "C" { \ - JNIEXPORT RETURN_TYPE Java_android_media_MediaParser_##NAME(JNIEnv* env, jobject thiz, \ - ##__VA_ARGS__); \ - } \ - JNIEXPORT RETURN_TYPE Java_android_media_MediaParser_##NAME(JNIEnv* env, jobject thiz, \ - ##__VA_ARGS__) - -namespace { - -constexpr char kMediaMetricsKey[] = "mediaparser"; - -constexpr char kAttributeLogSessionId[] = "android.media.mediaparser.logSessionId"; -constexpr char kAttributeParserName[] = "android.media.mediaparser.parserName"; -constexpr char kAttributeCreatedByName[] = "android.media.mediaparser.createdByName"; -constexpr char kAttributeParserPool[] = "android.media.mediaparser.parserPool"; -constexpr char kAttributeLastException[] = "android.media.mediaparser.lastException"; -constexpr char kAttributeResourceByteCount[] = "android.media.mediaparser.resourceByteCount"; -constexpr char kAttributeDurationMillis[] = "android.media.mediaparser.durationMillis"; -constexpr char kAttributeTrackMimeTypes[] = "android.media.mediaparser.trackMimeTypes"; -constexpr char kAttributeTrackCodecs[] = "android.media.mediaparser.trackCodecs"; -constexpr char kAttributeAlteredParameters[] = "android.media.mediaparser.alteredParameters"; -constexpr char kAttributeVideoWidth[] = "android.media.mediaparser.videoWidth"; -constexpr char kAttributeVideoHeight[] = "android.media.mediaparser.videoHeight"; - -// Util class to handle string resource management. -class JstringHandle { -public: - JstringHandle(JNIEnv* env, jstring value) : mEnv(env), mJstringValue(value) { - mCstringValue = env->GetStringUTFChars(value, /* isCopy= */ nullptr); - } - - ~JstringHandle() { - if (mCstringValue != nullptr) { - mEnv->ReleaseStringUTFChars(mJstringValue, mCstringValue); - } - } - - [[nodiscard]] const char* value() const { - return mCstringValue != nullptr ? mCstringValue : ""; - } - - JNIEnv* mEnv; - jstring mJstringValue; - const char* mCstringValue; -}; - -} // namespace - -JNI_FUNCTION(void, nativeSubmitMetrics, jstring logSessionIdJstring, jstring parserNameJstring, - jboolean createdByName, jstring parserPoolJstring, jstring lastExceptionJstring, - jlong resourceByteCount, jlong durationMillis, jstring trackMimeTypesJstring, - jstring trackCodecsJstring, jstring alteredParameters, jint videoWidth, - jint videoHeight) { - mediametrics_handle_t item(mediametrics_create(kMediaMetricsKey)); - mediametrics_setCString(item, kAttributeLogSessionId, - JstringHandle(env, logSessionIdJstring).value()); - mediametrics_setCString(item, kAttributeParserName, - JstringHandle(env, parserNameJstring).value()); - mediametrics_setInt32(item, kAttributeCreatedByName, createdByName ? 1 : 0); - mediametrics_setCString(item, kAttributeParserPool, - JstringHandle(env, parserPoolJstring).value()); - mediametrics_setCString(item, kAttributeLastException, - JstringHandle(env, lastExceptionJstring).value()); - mediametrics_setInt64(item, kAttributeResourceByteCount, resourceByteCount); - mediametrics_setInt64(item, kAttributeDurationMillis, durationMillis); - mediametrics_setCString(item, kAttributeTrackMimeTypes, - JstringHandle(env, trackMimeTypesJstring).value()); - mediametrics_setCString(item, kAttributeTrackCodecs, - JstringHandle(env, trackCodecsJstring).value()); - mediametrics_setCString(item, kAttributeAlteredParameters, - JstringHandle(env, alteredParameters).value()); - mediametrics_setInt32(item, kAttributeVideoWidth, videoWidth); - mediametrics_setInt32(item, kAttributeVideoHeight, videoHeight); - mediametrics_selfRecord(item); - mediametrics_delete(item); -} diff --git a/apex/media/framework/lint-baseline.xml b/apex/media/framework/lint-baseline.xml deleted file mode 100644 index e1b145083f80..000000000000 --- a/apex/media/framework/lint-baseline.xml +++ /dev/null @@ -1,312 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0"> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `new android.media.ApplicationMediaCapabilities.Builder`" - errorLine1=" new ApplicationMediaCapabilities.Builder();" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java" - line="208" - column="29"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 29): `new android.media.ApplicationMediaCapabilities.Builder`" - errorLine1=" ApplicationMediaCapabilities.Builder builder = new ApplicationMediaCapabilities.Builder();" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java" - line="314" - column="56"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level R (current min is 29): `android.os.RemoteException#rethrowFromSystemServer`" - errorLine1=" e.rethrowFromSystemServer();" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/apex/media/framework/java/android/media/MediaCommunicationManager.java" - line="110" - column="15"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level R (current min is 29): `android.os.Parcel#writeParcelableCreator`" - errorLine1=" dest.writeParcelableCreator((Parcelable) parcelable);" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/apex/media/framework/java/android/media/MediaParceledListSlice.java" - line="77" - column="14"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level R (current min is 29): `android.os.Parcel#readParcelableCreator`" - errorLine1=" return from.readParcelableCreator(loader);" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/apex/media/framework/java/android/media/MediaParceledListSlice.java" - line="82" - column="21"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level R (current min is 29): `android.media.MediaParser.TrackData#mediaFormat`" - errorLine1=" this.mediaFormat = mediaFormat;" - errorLine2=" ~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/apex/media/framework/java/android/media/MediaParser.java" - line="273" - column="13"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level R (current min is 29): `android.media.MediaParser.TrackData#drmInitData`" - errorLine1=" this.drmInitData = drmInitData;" - errorLine2=" ~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/apex/media/framework/java/android/media/MediaParser.java" - line="274" - column="13"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level R (current min is 29): `android.media.MediaParser.SeekPoint#timeMicros`" - errorLine1=" this.timeMicros = timeMicros;" - errorLine2=" ~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/apex/media/framework/java/android/media/MediaParser.java" - line="295" - column="13"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level R (current min is 29): `android.media.MediaParser.SeekPoint#position`" - errorLine1=" this.position = position;" - errorLine2=" ~~~~~~~~~~~~~"> - <location - file="frameworks/base/apex/media/framework/java/android/media/MediaParser.java" - line="296" - column="13"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level R (current min is 29): `android.media.MediaParser.SeekPoint#position`" - errorLine1=" return "[timeMicros=" + timeMicros + ", position=" + position + "]";" - errorLine2=" ~~~~~~~~"> - <location - file="frameworks/base/apex/media/framework/java/android/media/MediaParser.java" - line="302" - column="66"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level R (current min is 29): `android.media.MediaParser.SeekPoint#timeMicros`" - errorLine1=" return "[timeMicros=" + timeMicros + ", position=" + position + "]";" - errorLine2=" ~~~~~~~~~~"> - <location - file="frameworks/base/apex/media/framework/java/android/media/MediaParser.java" - line="302" - column="37"/> - </issue> - - <issue - id="NewApi" - message="Class requires API level R (current min is 29): `android.media.MediaParser.SeekPoint`" - errorLine1=" SeekPoint other = (SeekPoint) obj;" - errorLine2=" ~~~~~~~~~"> - <location - file="frameworks/base/apex/media/framework/java/android/media/MediaParser.java" - line="313" - column="32"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level R (current min is 29): `android.media.MediaParser.SeekPoint#position`" - errorLine1=" return timeMicros == other.timeMicros && position == other.position;" - errorLine2=" ~~~~~~~~"> - <location - file="frameworks/base/apex/media/framework/java/android/media/MediaParser.java" - line="314" - column="54"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level R (current min is 29): `android.media.MediaParser.SeekPoint#position`" - errorLine1=" return timeMicros == other.timeMicros && position == other.position;" - errorLine2=" ~~~~~~~~~~~~~~"> - <location - file="frameworks/base/apex/media/framework/java/android/media/MediaParser.java" - line="314" - column="66"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level R (current min is 29): `android.media.MediaParser.SeekPoint#timeMicros`" - errorLine1=" return timeMicros == other.timeMicros && position == other.position;" - errorLine2=" ~~~~~~~~~~"> - <location - file="frameworks/base/apex/media/framework/java/android/media/MediaParser.java" - line="314" - column="20"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level R (current min is 29): `android.media.MediaParser.SeekPoint#timeMicros`" - errorLine1=" return timeMicros == other.timeMicros && position == other.position;" - errorLine2=" ~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/apex/media/framework/java/android/media/MediaParser.java" - line="314" - column="34"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level R (current min is 29): `android.media.MediaParser.SeekPoint#timeMicros`" - errorLine1=" int result = (int) timeMicros;" - errorLine2=" ~~~~~~~~~~"> - <location - file="frameworks/base/apex/media/framework/java/android/media/MediaParser.java" - line="319" - column="32"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level R (current min is 29): `android.media.MediaParser.SeekPoint#position`" - errorLine1=" result = 31 * result + (int) position;" - errorLine2=" ~~~~~~~~"> - <location - file="frameworks/base/apex/media/framework/java/android/media/MediaParser.java" - line="320" - column="42"/> - </issue> - - <issue - id="NewApi" - message="Class requires API level R (current min is 29): `android.media.MediaParser.InputReader`" - errorLine1=" public interface SeekableInputReader extends InputReader {" - errorLine2=" ~~~~~~~~~~~"> - <location - file="frameworks/base/apex/media/framework/java/android/media/MediaParser.java" - line="352" - column="50"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level 31 (current min is 29): `android.media.metrics.LogSessionId#LOG_SESSION_ID_NONE`" - errorLine1=" @NonNull private LogSessionId mLogSessionId = LogSessionId.LOG_SESSION_ID_NONE;" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/apex/media/framework/java/android/media/MediaParser.java" - line="1071" - column="51"/> - </issue> - - <issue - id="NewApi" - message="Cast from `SeekableInputReader` to `InputReader` requires API level 30 (current min is 29)" - errorLine1=" mExoDataReader.mInputReader = seekableInputReader;" - errorLine2=" ~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/apex/media/framework/java/android/media/MediaParser.java" - line="1201" - column="39"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level R (current min is 29): `android.media.MediaParser.SeekPoint#position`" - errorLine1=" mPendingSeekPosition = seekPoint.position;" - errorLine2=" ~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/apex/media/framework/java/android/media/MediaParser.java" - line="1287" - column="36"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level R (current min is 29): `android.media.MediaParser.SeekPoint#timeMicros`" - errorLine1=" mPendingSeekTimeMicros = seekPoint.timeMicros;" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/apex/media/framework/java/android/media/MediaParser.java" - line="1288" - column="38"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level R (current min is 29): `android.media.MediaParser.SeekPoint#position`" - errorLine1=" mExtractor.seek(seekPoint.position, seekPoint.timeMicros);" - errorLine2=" ~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/apex/media/framework/java/android/media/MediaParser.java" - line="1290" - column="29"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level R (current min is 29): `android.media.MediaParser.SeekPoint#timeMicros`" - errorLine1=" mExtractor.seek(seekPoint.position, seekPoint.timeMicros);" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/apex/media/framework/java/android/media/MediaParser.java" - line="1290" - column="49"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level R (current min is 29): `android.media.DrmInitData.SchemeInitData#uuid`" - errorLine1=" if (schemeInitData.uuid.equals(schemeUuid)) {" - errorLine2=" ~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/apex/media/framework/java/android/media/MediaParser.java" - line="1579" - column="21"/> - </issue> - - <issue - id="NewApi" - message="Class requires API level R (current min is 29): `android.media.MediaParser.InputReader`" - errorLine1=" private static final class DataReaderAdapter implements InputReader {" - errorLine2=" ~~~~~~~~~~~"> - <location - file="frameworks/base/apex/media/framework/java/android/media/MediaParser.java" - line="1872" - column="61"/> - </issue> - - <issue - id="NewApi" - message="Class requires API level R (current min is 29): `android.media.MediaParser.InputReader`" - errorLine1=" private static final class ParsableByteArrayAdapter implements InputReader {" - errorLine2=" ~~~~~~~~~~~"> - <location - file="frameworks/base/apex/media/framework/java/android/media/MediaParser.java" - line="1905" - column="68"/> - </issue> - -</issues> diff --git a/apex/media/framework/updatable-media-proguard.flags b/apex/media/framework/updatable-media-proguard.flags deleted file mode 100644 index 4e7d8422bf44..000000000000 --- a/apex/media/framework/updatable-media-proguard.flags +++ /dev/null @@ -1,2 +0,0 @@ -# Keep all symbols in android.media. --keep class android.media.* {*;} diff --git a/apex/media/service/Android.bp b/apex/media/service/Android.bp deleted file mode 100644 index 271fc5312f8f..000000000000 --- a/apex/media/service/Android.bp +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2020 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 { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "frameworks_base_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["frameworks_base_license"], -} - -filegroup { - name: "service-media-s-sources", - srcs: [ - "java/**/*.java", - ], - path: "java", - visibility: ["//visibility:private"], -} - -java_sdk_library { - name: "service-media-s", - permitted_packages: [ - "com.android.server.media", - ], - defaults: ["framework-system-server-module-defaults"], - srcs: [ - ":service-media-s-sources", - ], - libs: [ - "updatable-media", - ], - sdk_version: "system_server_current", - min_sdk_version: "29", // TODO: We may need to bump this at some point. - apex_available: [ - "com.android.media", - ], -} diff --git a/apex/media/service/api/current.txt b/apex/media/service/api/current.txt deleted file mode 100644 index d802177e249b..000000000000 --- a/apex/media/service/api/current.txt +++ /dev/null @@ -1 +0,0 @@ -// Signature format: 2.0 diff --git a/apex/media/service/api/removed.txt b/apex/media/service/api/removed.txt deleted file mode 100644 index d802177e249b..000000000000 --- a/apex/media/service/api/removed.txt +++ /dev/null @@ -1 +0,0 @@ -// Signature format: 2.0 diff --git a/apex/media/service/api/system-server-current.txt b/apex/media/service/api/system-server-current.txt deleted file mode 100644 index d802177e249b..000000000000 --- a/apex/media/service/api/system-server-current.txt +++ /dev/null @@ -1 +0,0 @@ -// Signature format: 2.0 diff --git a/apex/media/service/api/system-server-removed.txt b/apex/media/service/api/system-server-removed.txt deleted file mode 100644 index d802177e249b..000000000000 --- a/apex/media/service/api/system-server-removed.txt +++ /dev/null @@ -1 +0,0 @@ -// Signature format: 2.0 diff --git a/apex/media/service/java/com/android/server/media/MediaCommunicationService.java b/apex/media/service/java/com/android/server/media/MediaCommunicationService.java deleted file mode 100644 index ed31aa3d2a39..000000000000 --- a/apex/media/service/java/com/android/server/media/MediaCommunicationService.java +++ /dev/null @@ -1,620 +0,0 @@ -/* - * Copyright 2020 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 com.android.server.media; - -import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; -import static android.os.UserHandle.ALL; -import static android.os.UserHandle.getUserHandleForUid; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.app.ActivityManager; -import android.app.NotificationManager; -import android.content.Context; -import android.content.pm.PackageManager; -import android.media.IMediaCommunicationService; -import android.media.IMediaCommunicationServiceCallback; -import android.media.MediaController2; -import android.media.MediaParceledListSlice; -import android.media.Session2CommandGroup; -import android.media.Session2Token; -import android.os.Binder; -import android.os.Handler; -import android.os.IBinder; -import android.os.Looper; -import android.os.Process; -import android.os.RemoteException; -import android.os.UserHandle; -import android.os.UserManager; -import android.util.Log; -import android.util.SparseArray; -import android.util.SparseIntArray; - -import com.android.internal.annotations.GuardedBy; -import com.android.server.SystemService; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; -import java.util.stream.Collectors; - -/** - * A system service that manages {@link android.media.MediaSession2} creations - * and their ongoing media playback state. - * @hide - */ -public class MediaCommunicationService extends SystemService { - private static final String TAG = "MediaCommunicationService"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - - final Context mContext; - - final Object mLock = new Object(); - final Handler mHandler = new Handler(Looper.getMainLooper()); - - @GuardedBy("mLock") - private final SparseIntArray mFullUserIds = new SparseIntArray(); - @GuardedBy("mLock") - private final SparseArray<FullUserRecord> mUserRecords = new SparseArray<>(); - - final Executor mRecordExecutor = Executors.newSingleThreadExecutor(); - @GuardedBy("mLock") - final List<CallbackRecord> mCallbackRecords = new ArrayList<>(); - final NotificationManager mNotificationManager; - - public MediaCommunicationService(Context context) { - super(context); - mContext = context; - mNotificationManager = context.getSystemService(NotificationManager.class); - } - - @Override - public void onStart() { - publishBinderService(Context.MEDIA_COMMUNICATION_SERVICE, new Stub()); - updateUser(); - } - - @Override - public void onUserStarting(@NonNull TargetUser user) { - if (DEBUG) Log.d(TAG, "onUserStarting: " + user); - updateUser(); - } - - @Override - public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) { - if (DEBUG) Log.d(TAG, "onUserSwitching: " + to); - updateUser(); - } - - @Override - public void onUserStopped(@NonNull TargetUser targetUser) { - int userId = targetUser.getUserHandle().getIdentifier(); - - if (DEBUG) Log.d(TAG, "onUserStopped: " + userId); - synchronized (mLock) { - FullUserRecord user = getFullUserRecordLocked(userId); - if (user != null) { - if (user.getFullUserId() == userId) { - user.destroyAllSessions(); - mUserRecords.remove(userId); - } else { - user.destroySessionsForUser(userId); - } - } - } - updateUser(); - } - - @Nullable - CallbackRecord findCallbackRecordLocked(@Nullable IMediaCommunicationServiceCallback callback) { - if (callback == null) { - return null; - } - for (CallbackRecord record : mCallbackRecords) { - if (Objects.equals(callback.asBinder(), record.mCallback.asBinder())) { - return record; - } - } - return null; - } - - List<Session2Token> getSession2TokensLocked(int userId) { - List<Session2Token> list = new ArrayList<>(); - if (userId == ALL.getIdentifier()) { - int size = mUserRecords.size(); - for (int i = 0; i < size; i++) { - list.addAll(mUserRecords.valueAt(i).getAllSession2Tokens()); - } - } else { - FullUserRecord user = getFullUserRecordLocked(userId); - if (user != null) { - list.addAll(user.getSession2Tokens(userId)); - } - } - return list; - } - - private FullUserRecord getFullUserRecordLocked(int userId) { - int fullUserId = mFullUserIds.get(userId, -1); - if (fullUserId < 0) { - return null; - } - return mUserRecords.get(fullUserId); - } - - private boolean hasMediaControlPermission(int pid, int uid) { - // Check if it's system server or has MEDIA_CONTENT_CONTROL. - // Note that system server doesn't have MEDIA_CONTENT_CONTROL, so we need extra - // check here. - if (uid == Process.SYSTEM_UID || mContext.checkPermission( - android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid) - == PackageManager.PERMISSION_GRANTED) { - return true; - } else if (DEBUG) { - Log.d(TAG, "uid(" + uid + ") hasn't granted MEDIA_CONTENT_CONTROL"); - } - return false; - } - - private void updateUser() { - UserManager manager = mContext.getSystemService(UserManager.class); - List<UserHandle> allUsers = manager.getUserHandles(/*excludeDying=*/false); - - synchronized (mLock) { - mFullUserIds.clear(); - if (allUsers != null) { - for (UserHandle user : allUsers) { - UserHandle parent = manager.getProfileParent(user); - if (parent != null) { - mFullUserIds.put(user.getIdentifier(), parent.getIdentifier()); - } else { - mFullUserIds.put(user.getIdentifier(), user.getIdentifier()); - if (mUserRecords.get(user.getIdentifier()) == null) { - mUserRecords.put(user.getIdentifier(), - new FullUserRecord(user.getIdentifier())); - } - } - } - } - // Ensure that the current full user exists. - int currentFullUserId = ActivityManager.getCurrentUser(); - FullUserRecord currentFullUserRecord = mUserRecords.get(currentFullUserId); - if (currentFullUserRecord == null) { - Log.w(TAG, "Cannot find FullUserInfo for the current user " + currentFullUserId); - currentFullUserRecord = new FullUserRecord(currentFullUserId); - mUserRecords.put(currentFullUserId, currentFullUserRecord); - } - mFullUserIds.put(currentFullUserId, currentFullUserId); - } - } - - void dispatchSession2Created(Session2Token token) { - synchronized (mLock) { - for (CallbackRecord record : mCallbackRecords) { - if (record.mUserId != ALL.getIdentifier() - && record.mUserId != getUserHandleForUid(token.getUid()).getIdentifier()) { - continue; - } - try { - record.mCallback.onSession2Created(token); - } catch (RemoteException e) { - Log.w(TAG, "Failed to notify session2 token created " + record); - } - } - } - } - - void dispatchSession2Changed(int userId) { - MediaParceledListSlice<Session2Token> allSession2Tokens; - MediaParceledListSlice<Session2Token> userSession2Tokens; - - synchronized (mLock) { - allSession2Tokens = - new MediaParceledListSlice<>(getSession2TokensLocked(ALL.getIdentifier())); - userSession2Tokens = new MediaParceledListSlice<>(getSession2TokensLocked(userId)); - } - allSession2Tokens.setInlineCountLimit(1); - userSession2Tokens.setInlineCountLimit(1); - - synchronized (mLock) { - for (CallbackRecord record : mCallbackRecords) { - if (record.mUserId == ALL.getIdentifier()) { - try { - record.mCallback.onSession2Changed(allSession2Tokens); - } catch (RemoteException e) { - Log.w(TAG, "Failed to notify session2 tokens changed " + record); - } - } else if (record.mUserId == userId) { - try { - record.mCallback.onSession2Changed(userSession2Tokens); - } catch (RemoteException e) { - Log.w(TAG, "Failed to notify session2 tokens changed " + record); - } - } - } - } - } - - void onSessionDied(Session2Record session) { - if (DEBUG) { - Log.d(TAG, "Destroying " + session); - } - if (session.isClosed()) { - Log.w(TAG, "Destroying already destroyed session. Ignoring."); - return; - } - - FullUserRecord user = session.getFullUser(); - if (user != null) { - user.removeSession(session); - } - session.close(); - } - - private class Stub extends IMediaCommunicationService.Stub { - @Override - public void notifySession2Created(Session2Token sessionToken) { - final int pid = Binder.getCallingPid(); - final int uid = Binder.getCallingUid(); - final long token = Binder.clearCallingIdentity(); - - try { - if (DEBUG) { - Log.d(TAG, "Session2 is created " + sessionToken); - } - if (uid != sessionToken.getUid()) { - throw new SecurityException("Unexpected Session2Token's UID, expected=" + uid - + " but actually=" + sessionToken.getUid()); - } - FullUserRecord user; - int userId = getUserHandleForUid(sessionToken.getUid()).getIdentifier(); - synchronized (mLock) { - user = getFullUserRecordLocked(userId); - } - if (user == null) { - Log.w(TAG, "notifySession2Created: Ignore session of an unknown user"); - return; - } - user.addSession(new Session2Record(MediaCommunicationService.this, - user, sessionToken, mRecordExecutor)); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - /** - * Returns if the controller's package is trusted (i.e. has either MEDIA_CONTENT_CONTROL - * permission or an enabled notification listener) - * - * @param controllerPackageName package name of the controller app - * @param controllerPid pid of the controller app - * @param controllerUid uid of the controller app - */ - @Override - public boolean isTrusted(String controllerPackageName, int controllerPid, - int controllerUid) { - final int uid = Binder.getCallingUid(); - final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier(); - final long token = Binder.clearCallingIdentity(); - try { - // Don't perform check between controllerPackageName and controllerUid. - // When an (activity|service) runs on the another apps process by specifying - // android:process in the AndroidManifest.xml, then PID and UID would have the - // running process' information instead of the (activity|service) that has created - // MediaController. - // Note that we can use Context#getOpPackageName() instead of - // Context#getPackageName() for getting package name that matches with the PID/UID, - // but it doesn't tell which package has created the MediaController, so useless. - return hasMediaControlPermission(controllerPid, controllerUid) - || hasEnabledNotificationListener( - userId, controllerPackageName, controllerUid); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public MediaParceledListSlice getSession2Tokens(int userId) { - final int pid = Binder.getCallingPid(); - final int uid = Binder.getCallingUid(); - final long token = Binder.clearCallingIdentity(); - - try { - // Check that they can make calls on behalf of the user and get the final user id - int resolvedUserId = handleIncomingUser(pid, uid, userId, null); - List<Session2Token> result; - synchronized (mLock) { - result = getSession2TokensLocked(resolvedUserId); - } - MediaParceledListSlice parceledListSlice = new MediaParceledListSlice<>(result); - parceledListSlice.setInlineCountLimit(1); - return parceledListSlice; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public void registerCallback(IMediaCommunicationServiceCallback callback, - String packageName) throws RemoteException { - Objects.requireNonNull(callback, "callback should not be null"); - Objects.requireNonNull(packageName, "packageName should not be null"); - - synchronized (mLock) { - if (findCallbackRecordLocked(callback) == null) { - - CallbackRecord record = new CallbackRecord(callback, packageName, - Binder.getCallingUid(), Binder.getCallingPid()); - mCallbackRecords.add(record); - try { - callback.asBinder().linkToDeath(record, 0); - } catch (RemoteException e) { - Log.w(TAG, "Failed to register callback", e); - mCallbackRecords.remove(record); - } - } else { - Log.e(TAG, "registerCallback is called with already registered callback. " - + "packageName=" + packageName); - } - } - } - - @Override - public void unregisterCallback(IMediaCommunicationServiceCallback callback) - throws RemoteException { - synchronized (mLock) { - CallbackRecord existingRecord = findCallbackRecordLocked(callback); - if (existingRecord != null) { - mCallbackRecords.remove(existingRecord); - callback.asBinder().unlinkToDeath(existingRecord, 0); - } else { - Log.e(TAG, "unregisterCallback is called with unregistered callback."); - } - } - } - - private boolean hasEnabledNotificationListener(int callingUserId, - String controllerPackageName, int controllerUid) { - int controllerUserId = UserHandle.getUserHandleForUid(controllerUid).getIdentifier(); - if (callingUserId != controllerUserId) { - // Enabled notification listener only works within the same user. - return false; - } - - if (mNotificationManager.hasEnabledNotificationListener(controllerPackageName, - UserHandle.getUserHandleForUid(controllerUid))) { - return true; - } - if (DEBUG) { - Log.d(TAG, controllerPackageName + " (uid=" + controllerUid - + ") doesn't have an enabled notification listener"); - } - return false; - } - - // Handles incoming user by checking whether the caller has permission to access the - // given user id's information or not. Permission is not necessary if the given user id is - // equal to the caller's user id, but if not, the caller needs to have the - // INTERACT_ACROSS_USERS_FULL permission. Otherwise, a security exception will be thrown. - // The return value will be the given user id, unless the given user id is - // UserHandle.CURRENT, which will return the ActivityManager.getCurrentUser() value instead. - private int handleIncomingUser(int pid, int uid, int userId, String packageName) { - int callingUserId = UserHandle.getUserHandleForUid(uid).getIdentifier(); - if (userId == callingUserId) { - return userId; - } - - boolean canInteractAcrossUsersFull = mContext.checkPermission( - INTERACT_ACROSS_USERS_FULL, pid, uid) == PackageManager.PERMISSION_GRANTED; - if (canInteractAcrossUsersFull) { - if (userId == UserHandle.CURRENT.getIdentifier()) { - return ActivityManager.getCurrentUser(); - } - return userId; - } - - throw new SecurityException("Permission denied while calling from " + packageName - + " with user id: " + userId + "; Need to run as either the calling user id (" - + callingUserId + "), or with " + INTERACT_ACROSS_USERS_FULL + " permission"); - } - } - - final class CallbackRecord implements IBinder.DeathRecipient { - private final IMediaCommunicationServiceCallback mCallback; - private final String mPackageName; - private final int mUid; - private int mPid; - private final int mUserId; - - CallbackRecord(IMediaCommunicationServiceCallback callback, - String packageName, int uid, int pid) { - mCallback = callback; - mPackageName = packageName; - mUid = uid; - mPid = pid; - mUserId = (mContext.checkPermission( - INTERACT_ACROSS_USERS_FULL, pid, uid) == PackageManager.PERMISSION_GRANTED) - ? ALL.getIdentifier() : UserHandle.getUserHandleForUid(mUid).getIdentifier(); - } - - @Override - public String toString() { - return "CallbackRecord[callback=" + mCallback + ", pkg=" + mPackageName - + ", uid=" + mUid + ", pid=" + mPid + "]"; - } - - @Override - public void binderDied() { - synchronized (mLock) { - mCallbackRecords.remove(this); - } - } - } - - final class FullUserRecord { - private final int mFullUserId; - private final Object mUserLock = new Object(); - @GuardedBy("mUserLock") - private final List<Session2Record> mSessionRecords = new ArrayList<>(); - - FullUserRecord(int fullUserId) { - mFullUserId = fullUserId; - } - - public void addSession(Session2Record record) { - synchronized (mUserLock) { - mSessionRecords.add(record); - } - mHandler.post(() -> dispatchSession2Created(record.mSessionToken)); - mHandler.post(() -> dispatchSession2Changed(mFullUserId)); - } - - private void removeSession(Session2Record record) { - synchronized (mUserLock) { - mSessionRecords.remove(record); - } - mHandler.post(() -> dispatchSession2Changed(mFullUserId)); - //TODO: Handle if the removed session was the media button session. - } - - public int getFullUserId() { - return mFullUserId; - } - - public List<Session2Token> getAllSession2Tokens() { - synchronized (mUserLock) { - return mSessionRecords.stream() - .map(Session2Record::getSessionToken) - .collect(Collectors.toList()); - } - } - - public List<Session2Token> getSession2Tokens(int userId) { - synchronized (mUserLock) { - return mSessionRecords.stream() - .filter(record -> record.getUserId() == userId) - .map(Session2Record::getSessionToken) - .collect(Collectors.toList()); - } - } - - public void destroyAllSessions() { - synchronized (mUserLock) { - for (Session2Record session : mSessionRecords) { - session.close(); - } - mSessionRecords.clear(); - } - mHandler.post(() -> dispatchSession2Changed(mFullUserId)); - } - - public void destroySessionsForUser(int userId) { - boolean changed = false; - synchronized (mUserLock) { - for (int i = mSessionRecords.size() - 1; i >= 0; i--) { - Session2Record session = mSessionRecords.get(i); - if (session.getUserId() == userId) { - mSessionRecords.remove(i); - session.close(); - changed = true; - } - } - } - if (changed) { - mHandler.post(() -> dispatchSession2Changed(mFullUserId)); - } - } - } - - static final class Session2Record { - final Session2Token mSessionToken; - final Object mSession2RecordLock = new Object(); - final WeakReference<MediaCommunicationService> mServiceRef; - final WeakReference<FullUserRecord> mFullUserRef; - @GuardedBy("mSession2RecordLock") - private final MediaController2 mController; - - @GuardedBy("mSession2RecordLock") - boolean mIsConnected; - @GuardedBy("mSession2RecordLock") - private boolean mIsClosed; - - Session2Record(MediaCommunicationService service, FullUserRecord fullUser, - Session2Token token, Executor controllerExecutor) { - mServiceRef = new WeakReference<>(service); - mFullUserRef = new WeakReference<>(fullUser); - mSessionToken = token; - mController = new MediaController2.Builder(service.getContext(), token) - .setControllerCallback(controllerExecutor, new Controller2Callback()) - .build(); - } - - public int getUserId() { - return UserHandle.getUserHandleForUid(mSessionToken.getUid()).getIdentifier(); - } - - public FullUserRecord getFullUser() { - return mFullUserRef.get(); - } - - public boolean isClosed() { - synchronized (mSession2RecordLock) { - return mIsClosed; - } - } - - public void close() { - synchronized (mSession2RecordLock) { - mIsClosed = true; - mController.close(); - } - } - - public Session2Token getSessionToken() { - return mSessionToken; - } - - private class Controller2Callback extends MediaController2.ControllerCallback { - @Override - public void onConnected(MediaController2 controller, - Session2CommandGroup allowedCommands) { - if (DEBUG) { - Log.d(TAG, "connected to " + mSessionToken + ", allowed=" + allowedCommands); - } - synchronized (mSession2RecordLock) { - mIsConnected = true; - } - } - - @Override - public void onDisconnected(MediaController2 controller) { - if (DEBUG) { - Log.d(TAG, "disconnected from " + mSessionToken); - } - synchronized (mSession2RecordLock) { - mIsConnected = false; - } - MediaCommunicationService service = mServiceRef.get(); - if (service != null) { - service.onSessionDied(Session2Record.this); - } - } - } - } -} diff --git a/api/Android.bp b/api/Android.bp index 15356bdc0797..69d602a34380 100644 --- a/api/Android.bp +++ b/api/Android.bp @@ -112,7 +112,7 @@ combined_apis { "framework-appsearch", "framework-bluetooth", "framework-connectivity", - "framework-connectivity-tiramisu", + "framework-connectivity-t", "framework-graphics", "framework-media", "framework-mediaprovider", @@ -178,8 +178,10 @@ genrule { cmd: metalava_cmd + "--check-compatibility:api:released $(location :android.api.module-lib.latest) " + // Note: having "public" be the base of module-lib is not perfect -- it should - // ideally be a merged public+system), but this will help when migrating from - // MODULE_LIBS -> public. + // ideally be a merged public+system (which metalava is not currently able to generate). + // This "base" will help when migrating from MODULE_LIBS -> public, but not when + // migrating from MODULE_LIBS -> system (where it needs to instead be listed as + // an incompatibility). "--check-compatibility:base $(location :frameworks-base-api-current.txt) " + "--baseline:compatibility:released $(location :android-incompatibilities.api.module-lib.latest) " + "--update-baseline:compatibility:released $(genDir)/updated-baseline.txt " + diff --git a/api/OWNERS b/api/OWNERS index a0272709ffc0..4d8ed0347f43 100644 --- a/api/OWNERS +++ b/api/OWNERS @@ -4,3 +4,6 @@ hansson@google.com file:platform/packages/modules/common:/OWNERS per-file Android.bp = file:platform/build/soong:/OWNERS + +# For metalava team to disable lint checks in platform +per-file Android.bp = aurimas@google.com,emberrose@google.com,sjgilbert@google.com
\ No newline at end of file diff --git a/api/api.go b/api/api.go index 17649e80e81a..5e5f60ee993f 100644 --- a/api/api.go +++ b/api/api.go @@ -27,6 +27,7 @@ import ( const art = "art.module.public.api" const conscrypt = "conscrypt.module.public.api" const i18n = "i18n.module.public.api" +var core_libraries_modules = []string{art, conscrypt, i18n} // The intention behind this soong plugin is to generate a number of "merged" // API-related modules that would otherwise require a large amount of very @@ -199,9 +200,28 @@ func createMergedSystemStubs(ctx android.LoadHookContext, modules []string) { ctx.CreateModule(java.LibraryFactory, &props) } -func createMergedModuleLibStubs(ctx android.LoadHookContext, modules []string) { +func createMergedFrameworkImpl(ctx android.LoadHookContext, modules []string) { + // This module is for the "framework-all" module, which should not include the core libraries. + modules = removeAll(modules, core_libraries_modules) + // TODO(b/214988855): remove the line below when framework-bluetooth has an impl jar. + modules = remove(modules, "framework-bluetooth") + props := libraryProps{} + props.Name = proptools.StringPtr("all-framework-module-impl") + props.Static_libs = transformArray(modules, "", ".impl") + // Media module's impl jar is called "updatable-media" + for i, v := range props.Static_libs { + if v == "framework-media.impl" { + props.Static_libs[i] = "updatable-media" + } + } + props.Sdk_version = proptools.StringPtr("module_current") + props.Visibility = []string{"//frameworks/base"} + ctx.CreateModule(java.LibraryFactory, &props) +} + +func createMergedFrameworkModuleLibStubs(ctx android.LoadHookContext, modules []string) { // The user of this module compiles against the "core" SDK, so remove core libraries to avoid dupes. - modules = removeAll(modules, []string{art, conscrypt, i18n}) + modules = removeAll(modules, core_libraries_modules) props := libraryProps{} props.Name = proptools.StringPtr("framework-updatable-stubs-module_libs_api") props.Static_libs = transformArray(modules, "", ".stubs.module_lib") @@ -269,7 +289,8 @@ func (a *CombinedApis) createInternalModules(ctx android.LoadHookContext) { createMergedPublicStubs(ctx, bootclasspath) createMergedSystemStubs(ctx, bootclasspath) - createMergedModuleLibStubs(ctx, bootclasspath) + createMergedFrameworkModuleLibStubs(ctx, bootclasspath) + createMergedFrameworkImpl(ctx, bootclasspath) createMergedAnnotations(ctx, bootclasspath) diff --git a/boot/hiddenapi/hiddenapi-max-target-o.txt b/boot/hiddenapi/hiddenapi-max-target-o.txt index 9153426b29ab..e346ebf827ae 100644 --- a/boot/hiddenapi/hiddenapi-max-target-o.txt +++ b/boot/hiddenapi/hiddenapi-max-target-o.txt @@ -9315,78 +9315,6 @@ Landroid/app/usage/IUsageStatsManager;->setAppStandbyBucket(Ljava/lang/String;II Landroid/app/usage/IUsageStatsManager;->setAppStandbyBuckets(Landroid/content/pm/ParceledListSlice;I)V Landroid/app/usage/IUsageStatsManager;->unregisterAppUsageObserver(ILjava/lang/String;)V Landroid/app/usage/IUsageStatsManager;->whitelistAppTemporarily(Ljava/lang/String;JI)V -Landroid/app/usage/NetworkStats$Bucket;->convertDefaultNetworkStatus(I)I -Landroid/app/usage/NetworkStats$Bucket;->convertMetered(I)I -Landroid/app/usage/NetworkStats$Bucket;->convertRoaming(I)I -Landroid/app/usage/NetworkStats$Bucket;->convertSet(I)I -Landroid/app/usage/NetworkStats$Bucket;->convertState(I)I -Landroid/app/usage/NetworkStats$Bucket;->convertTag(I)I -Landroid/app/usage/NetworkStats$Bucket;->convertUid(I)I -Landroid/app/usage/NetworkStats$Bucket;->mBeginTimeStamp:J -Landroid/app/usage/NetworkStats$Bucket;->mDefaultNetworkStatus:I -Landroid/app/usage/NetworkStats$Bucket;->mEndTimeStamp:J -Landroid/app/usage/NetworkStats$Bucket;->mMetered:I -Landroid/app/usage/NetworkStats$Bucket;->mRoaming:I -Landroid/app/usage/NetworkStats$Bucket;->mRxBytes:J -Landroid/app/usage/NetworkStats$Bucket;->mRxPackets:J -Landroid/app/usage/NetworkStats$Bucket;->mState:I -Landroid/app/usage/NetworkStats$Bucket;->mTag:I -Landroid/app/usage/NetworkStats$Bucket;->mTxBytes:J -Landroid/app/usage/NetworkStats$Bucket;->mTxPackets:J -Landroid/app/usage/NetworkStats$Bucket;->mUid:I -Landroid/app/usage/NetworkStats;-><init>(Landroid/content/Context;Landroid/net/NetworkTemplate;IJJLandroid/net/INetworkStatsService;)V -Landroid/app/usage/NetworkStats;->fillBucketFromSummaryEntry(Landroid/app/usage/NetworkStats$Bucket;)V -Landroid/app/usage/NetworkStats;->getDeviceSummaryForNetwork()Landroid/app/usage/NetworkStats$Bucket; -Landroid/app/usage/NetworkStats;->getNextHistoryBucket(Landroid/app/usage/NetworkStats$Bucket;)Z -Landroid/app/usage/NetworkStats;->getNextSummaryBucket(Landroid/app/usage/NetworkStats$Bucket;)Z -Landroid/app/usage/NetworkStats;->getSummaryAggregate()Landroid/app/usage/NetworkStats$Bucket; -Landroid/app/usage/NetworkStats;->getUid()I -Landroid/app/usage/NetworkStats;->hasNextUid()Z -Landroid/app/usage/NetworkStats;->isUidEnumeration()Z -Landroid/app/usage/NetworkStats;->mCloseGuard:Ldalvik/system/CloseGuard; -Landroid/app/usage/NetworkStats;->mEndTimeStamp:J -Landroid/app/usage/NetworkStats;->mEnumerationIndex:I -Landroid/app/usage/NetworkStats;->mHistory:Landroid/net/NetworkStatsHistory; -Landroid/app/usage/NetworkStats;->mRecycledHistoryEntry:Landroid/net/NetworkStatsHistory$Entry; -Landroid/app/usage/NetworkStats;->mRecycledSummaryEntry:Landroid/net/NetworkStats$Entry; -Landroid/app/usage/NetworkStats;->mSession:Landroid/net/INetworkStatsSession; -Landroid/app/usage/NetworkStats;->mStartTimeStamp:J -Landroid/app/usage/NetworkStats;->mState:I -Landroid/app/usage/NetworkStats;->mSummary:Landroid/net/NetworkStats; -Landroid/app/usage/NetworkStats;->mTag:I -Landroid/app/usage/NetworkStats;->mTemplate:Landroid/net/NetworkTemplate; -Landroid/app/usage/NetworkStats;->mUidOrUidIndex:I -Landroid/app/usage/NetworkStats;->mUids:[I -Landroid/app/usage/NetworkStats;->setSingleUidTagState(III)V -Landroid/app/usage/NetworkStats;->startHistoryEnumeration(III)V -Landroid/app/usage/NetworkStats;->startSummaryEnumeration()V -Landroid/app/usage/NetworkStats;->startUserUidEnumeration()V -Landroid/app/usage/NetworkStats;->stepHistory()V -Landroid/app/usage/NetworkStats;->stepUid()V -Landroid/app/usage/NetworkStats;->TAG:Ljava/lang/String; -Landroid/app/usage/NetworkStatsManager$CallbackHandler;-><init>(Landroid/os/Looper;ILjava/lang/String;Landroid/app/usage/NetworkStatsManager$UsageCallback;)V -Landroid/app/usage/NetworkStatsManager$CallbackHandler;->getObject(Landroid/os/Message;Ljava/lang/String;)Ljava/lang/Object; -Landroid/app/usage/NetworkStatsManager$CallbackHandler;->mCallback:Landroid/app/usage/NetworkStatsManager$UsageCallback; -Landroid/app/usage/NetworkStatsManager$CallbackHandler;->mNetworkType:I -Landroid/app/usage/NetworkStatsManager$CallbackHandler;->mSubscriberId:Ljava/lang/String; -Landroid/app/usage/NetworkStatsManager$UsageCallback;->request:Landroid/net/DataUsageRequest; -Landroid/app/usage/NetworkStatsManager;-><init>(Landroid/content/Context;Landroid/net/INetworkStatsService;)V -Landroid/app/usage/NetworkStatsManager;->CALLBACK_LIMIT_REACHED:I -Landroid/app/usage/NetworkStatsManager;->CALLBACK_RELEASED:I -Landroid/app/usage/NetworkStatsManager;->createTemplate(ILjava/lang/String;)Landroid/net/NetworkTemplate; -Landroid/app/usage/NetworkStatsManager;->DBG:Z -Landroid/app/usage/NetworkStatsManager;->FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN:I -Landroid/app/usage/NetworkStatsManager;->FLAG_POLL_FORCE:I -Landroid/app/usage/NetworkStatsManager;->FLAG_POLL_ON_OPEN:I -Landroid/app/usage/NetworkStatsManager;->mContext:Landroid/content/Context; -Landroid/app/usage/NetworkStatsManager;->mFlags:I -Landroid/app/usage/NetworkStatsManager;->MIN_THRESHOLD_BYTES:J -Landroid/app/usage/NetworkStatsManager;->mService:Landroid/net/INetworkStatsService; -Landroid/app/usage/NetworkStatsManager;->querySummaryForDevice(Landroid/net/NetworkTemplate;JJ)Landroid/app/usage/NetworkStats$Bucket; -Landroid/app/usage/NetworkStatsManager;->registerUsageCallback(Landroid/net/NetworkTemplate;IJLandroid/app/usage/NetworkStatsManager$UsageCallback;Landroid/os/Handler;)V -Landroid/app/usage/NetworkStatsManager;->setAugmentWithSubscriptionPlan(Z)V -Landroid/app/usage/NetworkStatsManager;->setPollOnOpen(Z)V -Landroid/app/usage/NetworkStatsManager;->TAG:Ljava/lang/String; Landroid/app/usage/StorageStats;-><init>()V Landroid/app/usage/StorageStats;-><init>(Landroid/os/Parcel;)V Landroid/app/usage/StorageStats;->cacheBytes:J @@ -35338,13 +35266,6 @@ Landroid/net/ConnectivityMetricsEvent;->transports:J Landroid/net/Credentials;->gid:I Landroid/net/Credentials;->pid:I Landroid/net/Credentials;->uid:I -Landroid/net/DataUsageRequest;-><init>(ILandroid/net/NetworkTemplate;J)V -Landroid/net/DataUsageRequest;->CREATOR:Landroid/os/Parcelable$Creator; -Landroid/net/DataUsageRequest;->PARCELABLE_KEY:Ljava/lang/String; -Landroid/net/DataUsageRequest;->requestId:I -Landroid/net/DataUsageRequest;->REQUEST_ID_UNSET:I -Landroid/net/DataUsageRequest;->template:Landroid/net/NetworkTemplate; -Landroid/net/DataUsageRequest;->thresholdInBytes:J Landroid/net/DhcpResults;->addDns(Ljava/lang/String;)Z Landroid/net/DhcpResults;->clear()V Landroid/net/DhcpResults;->CREATOR:Landroid/os/Parcelable$Creator; @@ -35446,51 +35367,6 @@ Landroid/net/IIpConnectivityMetrics$Stub;->TRANSACTION_removeNetdEventCallback:I Landroid/net/IIpConnectivityMetrics;->addNetdEventCallback(ILandroid/net/INetdEventCallback;)Z Landroid/net/IIpConnectivityMetrics;->logEvent(Landroid/net/ConnectivityMetricsEvent;)I Landroid/net/IIpConnectivityMetrics;->removeNetdEventCallback(I)Z -Landroid/net/IIpSecService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V -Landroid/net/IIpSecService$Stub$Proxy;->addAddressToTunnelInterface(ILandroid/net/LinkAddress;Ljava/lang/String;)V -Landroid/net/IIpSecService$Stub$Proxy;->allocateSecurityParameterIndex(Ljava/lang/String;ILandroid/os/IBinder;)Landroid/net/IpSecSpiResponse; -Landroid/net/IIpSecService$Stub$Proxy;->applyTransportModeTransform(Landroid/os/ParcelFileDescriptor;II)V -Landroid/net/IIpSecService$Stub$Proxy;->applyTunnelModeTransform(IIILjava/lang/String;)V -Landroid/net/IIpSecService$Stub$Proxy;->closeUdpEncapsulationSocket(I)V -Landroid/net/IIpSecService$Stub$Proxy;->createTransform(Landroid/net/IpSecConfig;Landroid/os/IBinder;Ljava/lang/String;)Landroid/net/IpSecTransformResponse; -Landroid/net/IIpSecService$Stub$Proxy;->createTunnelInterface(Ljava/lang/String;Ljava/lang/String;Landroid/net/Network;Landroid/os/IBinder;Ljava/lang/String;)Landroid/net/IpSecTunnelInterfaceResponse; -Landroid/net/IIpSecService$Stub$Proxy;->deleteTransform(I)V -Landroid/net/IIpSecService$Stub$Proxy;->deleteTunnelInterface(ILjava/lang/String;)V -Landroid/net/IIpSecService$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String; -Landroid/net/IIpSecService$Stub$Proxy;->mRemote:Landroid/os/IBinder; -Landroid/net/IIpSecService$Stub$Proxy;->openUdpEncapsulationSocket(ILandroid/os/IBinder;)Landroid/net/IpSecUdpEncapResponse; -Landroid/net/IIpSecService$Stub$Proxy;->releaseSecurityParameterIndex(I)V -Landroid/net/IIpSecService$Stub$Proxy;->removeAddressFromTunnelInterface(ILandroid/net/LinkAddress;Ljava/lang/String;)V -Landroid/net/IIpSecService$Stub$Proxy;->removeTransportModeTransforms(Landroid/os/ParcelFileDescriptor;)V -Landroid/net/IIpSecService$Stub;-><init>()V -Landroid/net/IIpSecService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/IIpSecService; -Landroid/net/IIpSecService$Stub;->DESCRIPTOR:Ljava/lang/String; -Landroid/net/IIpSecService$Stub;->TRANSACTION_addAddressToTunnelInterface:I -Landroid/net/IIpSecService$Stub;->TRANSACTION_allocateSecurityParameterIndex:I -Landroid/net/IIpSecService$Stub;->TRANSACTION_applyTransportModeTransform:I -Landroid/net/IIpSecService$Stub;->TRANSACTION_applyTunnelModeTransform:I -Landroid/net/IIpSecService$Stub;->TRANSACTION_closeUdpEncapsulationSocket:I -Landroid/net/IIpSecService$Stub;->TRANSACTION_createTransform:I -Landroid/net/IIpSecService$Stub;->TRANSACTION_createTunnelInterface:I -Landroid/net/IIpSecService$Stub;->TRANSACTION_deleteTransform:I -Landroid/net/IIpSecService$Stub;->TRANSACTION_deleteTunnelInterface:I -Landroid/net/IIpSecService$Stub;->TRANSACTION_openUdpEncapsulationSocket:I -Landroid/net/IIpSecService$Stub;->TRANSACTION_releaseSecurityParameterIndex:I -Landroid/net/IIpSecService$Stub;->TRANSACTION_removeAddressFromTunnelInterface:I -Landroid/net/IIpSecService$Stub;->TRANSACTION_removeTransportModeTransforms:I -Landroid/net/IIpSecService;->addAddressToTunnelInterface(ILandroid/net/LinkAddress;Ljava/lang/String;)V -Landroid/net/IIpSecService;->allocateSecurityParameterIndex(Ljava/lang/String;ILandroid/os/IBinder;)Landroid/net/IpSecSpiResponse; -Landroid/net/IIpSecService;->applyTransportModeTransform(Landroid/os/ParcelFileDescriptor;II)V -Landroid/net/IIpSecService;->applyTunnelModeTransform(IIILjava/lang/String;)V -Landroid/net/IIpSecService;->closeUdpEncapsulationSocket(I)V -Landroid/net/IIpSecService;->createTransform(Landroid/net/IpSecConfig;Landroid/os/IBinder;Ljava/lang/String;)Landroid/net/IpSecTransformResponse; -Landroid/net/IIpSecService;->createTunnelInterface(Ljava/lang/String;Ljava/lang/String;Landroid/net/Network;Landroid/os/IBinder;Ljava/lang/String;)Landroid/net/IpSecTunnelInterfaceResponse; -Landroid/net/IIpSecService;->deleteTransform(I)V -Landroid/net/IIpSecService;->deleteTunnelInterface(ILjava/lang/String;)V -Landroid/net/IIpSecService;->openUdpEncapsulationSocket(ILandroid/os/IBinder;)Landroid/net/IpSecUdpEncapResponse; -Landroid/net/IIpSecService;->releaseSecurityParameterIndex(I)V -Landroid/net/IIpSecService;->removeAddressFromTunnelInterface(ILandroid/net/LinkAddress;Ljava/lang/String;)V -Landroid/net/IIpSecService;->removeTransportModeTransforms(Landroid/os/ParcelFileDescriptor;)V Landroid/net/INetd$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Landroid/net/INetd$Stub$Proxy;->addVirtualTunnelInterface(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;II)V Landroid/net/INetd$Stub$Proxy;->bandwidthEnableDataSaver(Z)Z @@ -35838,68 +35714,6 @@ Landroid/net/INetworkScoreService;->requestScores([Landroid/net/NetworkKey;)Z Landroid/net/INetworkScoreService;->setActiveScorer(Ljava/lang/String;)Z Landroid/net/INetworkScoreService;->unregisterNetworkScoreCache(ILandroid/net/INetworkScoreCache;)V Landroid/net/INetworkScoreService;->updateScores([Landroid/net/ScoredNetwork;)Z -Landroid/net/INetworkStatsService$Stub$Proxy;->forceUpdate()V -Landroid/net/INetworkStatsService$Stub$Proxy;->forceUpdateIfaces([Landroid/net/Network;)V -Landroid/net/INetworkStatsService$Stub$Proxy;->getDataLayerSnapshotForUid(I)Landroid/net/NetworkStats; -Landroid/net/INetworkStatsService$Stub$Proxy;->getDetailedUidStats([Ljava/lang/String;)Landroid/net/NetworkStats; -Landroid/net/INetworkStatsService$Stub$Proxy;->getIfaceStats(Ljava/lang/String;I)J -Landroid/net/INetworkStatsService$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String; -Landroid/net/INetworkStatsService$Stub$Proxy;->getTotalStats(I)J -Landroid/net/INetworkStatsService$Stub$Proxy;->getUidStats(II)J -Landroid/net/INetworkStatsService$Stub$Proxy;->incrementOperationCount(III)V -Landroid/net/INetworkStatsService$Stub$Proxy;->mRemote:Landroid/os/IBinder; -Landroid/net/INetworkStatsService$Stub$Proxy;->openSession()Landroid/net/INetworkStatsSession; -Landroid/net/INetworkStatsService$Stub$Proxy;->openSessionForUsageStats(ILjava/lang/String;)Landroid/net/INetworkStatsSession; -Landroid/net/INetworkStatsService$Stub$Proxy;->registerUsageCallback(Ljava/lang/String;Landroid/net/DataUsageRequest;Landroid/os/Messenger;Landroid/os/IBinder;)Landroid/net/DataUsageRequest; -Landroid/net/INetworkStatsService$Stub$Proxy;->unregisterUsageRequest(Landroid/net/DataUsageRequest;)V -Landroid/net/INetworkStatsService$Stub;-><init>()V -Landroid/net/INetworkStatsService$Stub;->DESCRIPTOR:Ljava/lang/String; -Landroid/net/INetworkStatsService$Stub;->TRANSACTION_forceUpdate:I -Landroid/net/INetworkStatsService$Stub;->TRANSACTION_forceUpdateIfaces:I -Landroid/net/INetworkStatsService$Stub;->TRANSACTION_getDataLayerSnapshotForUid:I -Landroid/net/INetworkStatsService$Stub;->TRANSACTION_getDetailedUidStats:I -Landroid/net/INetworkStatsService$Stub;->TRANSACTION_getIfaceStats:I -Landroid/net/INetworkStatsService$Stub;->TRANSACTION_getMobileIfaces:I -Landroid/net/INetworkStatsService$Stub;->TRANSACTION_getTotalStats:I -Landroid/net/INetworkStatsService$Stub;->TRANSACTION_getUidStats:I -Landroid/net/INetworkStatsService$Stub;->TRANSACTION_incrementOperationCount:I -Landroid/net/INetworkStatsService$Stub;->TRANSACTION_openSession:I -Landroid/net/INetworkStatsService$Stub;->TRANSACTION_openSessionForUsageStats:I -Landroid/net/INetworkStatsService$Stub;->TRANSACTION_registerUsageCallback:I -Landroid/net/INetworkStatsService$Stub;->TRANSACTION_unregisterUsageRequest:I -Landroid/net/INetworkStatsService;->forceUpdateIfaces([Landroid/net/Network;)V -Landroid/net/INetworkStatsService;->getDetailedUidStats([Ljava/lang/String;)Landroid/net/NetworkStats; -Landroid/net/INetworkStatsService;->getIfaceStats(Ljava/lang/String;I)J -Landroid/net/INetworkStatsService;->getTotalStats(I)J -Landroid/net/INetworkStatsService;->getUidStats(II)J -Landroid/net/INetworkStatsService;->incrementOperationCount(III)V -Landroid/net/INetworkStatsService;->registerUsageCallback(Ljava/lang/String;Landroid/net/DataUsageRequest;Landroid/os/Messenger;Landroid/os/IBinder;)Landroid/net/DataUsageRequest; -Landroid/net/INetworkStatsService;->unregisterUsageRequest(Landroid/net/DataUsageRequest;)V -Landroid/net/INetworkStatsSession$Stub$Proxy;-><init>(Landroid/os/IBinder;)V -Landroid/net/INetworkStatsSession$Stub$Proxy;->close()V -Landroid/net/INetworkStatsSession$Stub$Proxy;->getDeviceSummaryForNetwork(Landroid/net/NetworkTemplate;JJ)Landroid/net/NetworkStats; -Landroid/net/INetworkStatsSession$Stub$Proxy;->getHistoryForNetwork(Landroid/net/NetworkTemplate;I)Landroid/net/NetworkStatsHistory; -Landroid/net/INetworkStatsSession$Stub$Proxy;->getHistoryForUid(Landroid/net/NetworkTemplate;IIII)Landroid/net/NetworkStatsHistory; -Landroid/net/INetworkStatsSession$Stub$Proxy;->getHistoryIntervalForUid(Landroid/net/NetworkTemplate;IIIIJJ)Landroid/net/NetworkStatsHistory; -Landroid/net/INetworkStatsSession$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String; -Landroid/net/INetworkStatsSession$Stub$Proxy;->getRelevantUids()[I -Landroid/net/INetworkStatsSession$Stub$Proxy;->getSummaryForAllUid(Landroid/net/NetworkTemplate;JJZ)Landroid/net/NetworkStats; -Landroid/net/INetworkStatsSession$Stub$Proxy;->getSummaryForNetwork(Landroid/net/NetworkTemplate;JJ)Landroid/net/NetworkStats; -Landroid/net/INetworkStatsSession$Stub$Proxy;->mRemote:Landroid/os/IBinder; -Landroid/net/INetworkStatsSession$Stub;-><init>()V -Landroid/net/INetworkStatsSession$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/INetworkStatsSession; -Landroid/net/INetworkStatsSession$Stub;->DESCRIPTOR:Ljava/lang/String; -Landroid/net/INetworkStatsSession$Stub;->TRANSACTION_close:I -Landroid/net/INetworkStatsSession$Stub;->TRANSACTION_getDeviceSummaryForNetwork:I -Landroid/net/INetworkStatsSession$Stub;->TRANSACTION_getHistoryForNetwork:I -Landroid/net/INetworkStatsSession$Stub;->TRANSACTION_getHistoryForUid:I -Landroid/net/INetworkStatsSession$Stub;->TRANSACTION_getHistoryIntervalForUid:I -Landroid/net/INetworkStatsSession$Stub;->TRANSACTION_getRelevantUids:I -Landroid/net/INetworkStatsSession$Stub;->TRANSACTION_getSummaryForAllUid:I -Landroid/net/INetworkStatsSession$Stub;->TRANSACTION_getSummaryForNetwork:I -Landroid/net/INetworkStatsSession;->getDeviceSummaryForNetwork(Landroid/net/NetworkTemplate;JJ)Landroid/net/NetworkStats; -Landroid/net/INetworkStatsSession;->getHistoryIntervalForUid(Landroid/net/NetworkTemplate;IIIIJJ)Landroid/net/NetworkStatsHistory; -Landroid/net/INetworkStatsSession;->getRelevantUids()[I Landroid/net/InterfaceConfiguration;->CREATOR:Landroid/os/Parcelable$Creator; Landroid/net/InterfaceConfiguration;->FLAG_DOWN:Ljava/lang/String; Landroid/net/InterfaceConfiguration;->FLAG_UP:Ljava/lang/String; @@ -35914,174 +35728,6 @@ Landroid/net/InterfaceConfiguration;->mFlags:Ljava/util/HashSet; Landroid/net/InterfaceConfiguration;->mHwAddr:Ljava/lang/String; Landroid/net/InterfaceConfiguration;->setHardwareAddress(Ljava/lang/String;)V Landroid/net/InterfaceConfiguration;->validateFlag(Ljava/lang/String;)V -Landroid/net/IpSecAlgorithm;->checkValidOrThrow(Ljava/lang/String;II)V -Landroid/net/IpSecAlgorithm;->CRYPT_NULL:Ljava/lang/String; -Landroid/net/IpSecAlgorithm;->equals(Landroid/net/IpSecAlgorithm;Landroid/net/IpSecAlgorithm;)Z -Landroid/net/IpSecAlgorithm;->isAead()Z -Landroid/net/IpSecAlgorithm;->isAuthentication()Z -Landroid/net/IpSecAlgorithm;->isEncryption()Z -Landroid/net/IpSecAlgorithm;->isUnsafeBuild()Z -Landroid/net/IpSecAlgorithm;->mKey:[B -Landroid/net/IpSecAlgorithm;->mName:Ljava/lang/String; -Landroid/net/IpSecAlgorithm;->mTruncLenBits:I -Landroid/net/IpSecAlgorithm;->TAG:Ljava/lang/String; -Landroid/net/IpSecConfig;-><init>()V -Landroid/net/IpSecConfig;-><init>(Landroid/net/IpSecConfig;)V -Landroid/net/IpSecConfig;-><init>(Landroid/os/Parcel;)V -Landroid/net/IpSecConfig;->CREATOR:Landroid/os/Parcelable$Creator; -Landroid/net/IpSecConfig;->equals(Landroid/net/IpSecConfig;Landroid/net/IpSecConfig;)Z -Landroid/net/IpSecConfig;->getAuthenticatedEncryption()Landroid/net/IpSecAlgorithm; -Landroid/net/IpSecConfig;->getAuthentication()Landroid/net/IpSecAlgorithm; -Landroid/net/IpSecConfig;->getDestinationAddress()Ljava/lang/String; -Landroid/net/IpSecConfig;->getEncapRemotePort()I -Landroid/net/IpSecConfig;->getEncapSocketResourceId()I -Landroid/net/IpSecConfig;->getEncapType()I -Landroid/net/IpSecConfig;->getEncryption()Landroid/net/IpSecAlgorithm; -Landroid/net/IpSecConfig;->getMarkMask()I -Landroid/net/IpSecConfig;->getMarkValue()I -Landroid/net/IpSecConfig;->getMode()I -Landroid/net/IpSecConfig;->getNattKeepaliveInterval()I -Landroid/net/IpSecConfig;->getNetwork()Landroid/net/Network; -Landroid/net/IpSecConfig;->getSourceAddress()Ljava/lang/String; -Landroid/net/IpSecConfig;->getSpiResourceId()I -Landroid/net/IpSecConfig;->mAuthenticatedEncryption:Landroid/net/IpSecAlgorithm; -Landroid/net/IpSecConfig;->mAuthentication:Landroid/net/IpSecAlgorithm; -Landroid/net/IpSecConfig;->mDestinationAddress:Ljava/lang/String; -Landroid/net/IpSecConfig;->mEncapRemotePort:I -Landroid/net/IpSecConfig;->mEncapSocketResourceId:I -Landroid/net/IpSecConfig;->mEncapType:I -Landroid/net/IpSecConfig;->mEncryption:Landroid/net/IpSecAlgorithm; -Landroid/net/IpSecConfig;->mMarkMask:I -Landroid/net/IpSecConfig;->mMarkValue:I -Landroid/net/IpSecConfig;->mMode:I -Landroid/net/IpSecConfig;->mNattKeepaliveInterval:I -Landroid/net/IpSecConfig;->mNetwork:Landroid/net/Network; -Landroid/net/IpSecConfig;->mSourceAddress:Ljava/lang/String; -Landroid/net/IpSecConfig;->mSpiResourceId:I -Landroid/net/IpSecConfig;->setAuthenticatedEncryption(Landroid/net/IpSecAlgorithm;)V -Landroid/net/IpSecConfig;->setAuthentication(Landroid/net/IpSecAlgorithm;)V -Landroid/net/IpSecConfig;->setDestinationAddress(Ljava/lang/String;)V -Landroid/net/IpSecConfig;->setEncapRemotePort(I)V -Landroid/net/IpSecConfig;->setEncapSocketResourceId(I)V -Landroid/net/IpSecConfig;->setEncapType(I)V -Landroid/net/IpSecConfig;->setEncryption(Landroid/net/IpSecAlgorithm;)V -Landroid/net/IpSecConfig;->setMarkMask(I)V -Landroid/net/IpSecConfig;->setMarkValue(I)V -Landroid/net/IpSecConfig;->setMode(I)V -Landroid/net/IpSecConfig;->setNattKeepaliveInterval(I)V -Landroid/net/IpSecConfig;->setNetwork(Landroid/net/Network;)V -Landroid/net/IpSecConfig;->setSourceAddress(Ljava/lang/String;)V -Landroid/net/IpSecConfig;->setSpiResourceId(I)V -Landroid/net/IpSecConfig;->TAG:Ljava/lang/String; -Landroid/net/IpSecManager$IpSecTunnelInterface;-><init>(Landroid/content/Context;Landroid/net/IIpSecService;Ljava/net/InetAddress;Ljava/net/InetAddress;Landroid/net/Network;)V -Landroid/net/IpSecManager$IpSecTunnelInterface;->addAddress(Ljava/net/InetAddress;I)V -Landroid/net/IpSecManager$IpSecTunnelInterface;->getInterfaceName()Ljava/lang/String; -Landroid/net/IpSecManager$IpSecTunnelInterface;->getResourceId()I -Landroid/net/IpSecManager$IpSecTunnelInterface;->mCloseGuard:Ldalvik/system/CloseGuard; -Landroid/net/IpSecManager$IpSecTunnelInterface;->mInterfaceName:Ljava/lang/String; -Landroid/net/IpSecManager$IpSecTunnelInterface;->mLocalAddress:Ljava/net/InetAddress; -Landroid/net/IpSecManager$IpSecTunnelInterface;->mOpPackageName:Ljava/lang/String; -Landroid/net/IpSecManager$IpSecTunnelInterface;->mRemoteAddress:Ljava/net/InetAddress; -Landroid/net/IpSecManager$IpSecTunnelInterface;->mResourceId:I -Landroid/net/IpSecManager$IpSecTunnelInterface;->mService:Landroid/net/IIpSecService; -Landroid/net/IpSecManager$IpSecTunnelInterface;->mUnderlyingNetwork:Landroid/net/Network; -Landroid/net/IpSecManager$IpSecTunnelInterface;->removeAddress(Ljava/net/InetAddress;I)V -Landroid/net/IpSecManager$ResourceUnavailableException;-><init>(Ljava/lang/String;)V -Landroid/net/IpSecManager$SecurityParameterIndex;-><init>(Landroid/net/IIpSecService;Ljava/net/InetAddress;I)V -Landroid/net/IpSecManager$SecurityParameterIndex;->getResourceId()I -Landroid/net/IpSecManager$SecurityParameterIndex;->mCloseGuard:Ldalvik/system/CloseGuard; -Landroid/net/IpSecManager$SecurityParameterIndex;->mDestinationAddress:Ljava/net/InetAddress; -Landroid/net/IpSecManager$SecurityParameterIndex;->mResourceId:I -Landroid/net/IpSecManager$SecurityParameterIndex;->mService:Landroid/net/IIpSecService; -Landroid/net/IpSecManager$SecurityParameterIndex;->mSpi:I -Landroid/net/IpSecManager$SpiUnavailableException;-><init>(Ljava/lang/String;I)V -Landroid/net/IpSecManager$SpiUnavailableException;->mSpi:I -Landroid/net/IpSecManager$Status;->OK:I -Landroid/net/IpSecManager$Status;->RESOURCE_UNAVAILABLE:I -Landroid/net/IpSecManager$Status;->SPI_UNAVAILABLE:I -Landroid/net/IpSecManager$UdpEncapsulationSocket;-><init>(Landroid/net/IIpSecService;I)V -Landroid/net/IpSecManager$UdpEncapsulationSocket;->getResourceId()I -Landroid/net/IpSecManager$UdpEncapsulationSocket;->mCloseGuard:Ldalvik/system/CloseGuard; -Landroid/net/IpSecManager$UdpEncapsulationSocket;->mPfd:Landroid/os/ParcelFileDescriptor; -Landroid/net/IpSecManager$UdpEncapsulationSocket;->mPort:I -Landroid/net/IpSecManager$UdpEncapsulationSocket;->mResourceId:I -Landroid/net/IpSecManager$UdpEncapsulationSocket;->mService:Landroid/net/IIpSecService; -Landroid/net/IpSecManager;-><init>(Landroid/content/Context;Landroid/net/IIpSecService;)V -Landroid/net/IpSecManager;->applyTunnelModeTransform(Landroid/net/IpSecManager$IpSecTunnelInterface;ILandroid/net/IpSecTransform;)V -Landroid/net/IpSecManager;->createIpSecTunnelInterface(Ljava/net/InetAddress;Ljava/net/InetAddress;Landroid/net/Network;)Landroid/net/IpSecManager$IpSecTunnelInterface; -Landroid/net/IpSecManager;->INVALID_RESOURCE_ID:I -Landroid/net/IpSecManager;->maybeHandleServiceSpecificException(Landroid/os/ServiceSpecificException;)V -Landroid/net/IpSecManager;->mContext:Landroid/content/Context; -Landroid/net/IpSecManager;->mService:Landroid/net/IIpSecService; -Landroid/net/IpSecManager;->removeTunnelModeTransform(Landroid/net/Network;Landroid/net/IpSecTransform;)V -Landroid/net/IpSecManager;->rethrowCheckedExceptionFromServiceSpecificException(Landroid/os/ServiceSpecificException;)Ljava/io/IOException; -Landroid/net/IpSecManager;->rethrowUncheckedExceptionFromServiceSpecificException(Landroid/os/ServiceSpecificException;)Ljava/lang/RuntimeException; -Landroid/net/IpSecManager;->TAG:Ljava/lang/String; -Landroid/net/IpSecSpiResponse;-><init>(I)V -Landroid/net/IpSecSpiResponse;-><init>(III)V -Landroid/net/IpSecSpiResponse;-><init>(Landroid/os/Parcel;)V -Landroid/net/IpSecSpiResponse;->CREATOR:Landroid/os/Parcelable$Creator; -Landroid/net/IpSecSpiResponse;->resourceId:I -Landroid/net/IpSecSpiResponse;->spi:I -Landroid/net/IpSecSpiResponse;->status:I -Landroid/net/IpSecSpiResponse;->TAG:Ljava/lang/String; -Landroid/net/IpSecTransform$Builder;->buildTunnelModeTransform(Ljava/net/InetAddress;Landroid/net/IpSecManager$SecurityParameterIndex;)Landroid/net/IpSecTransform; -Landroid/net/IpSecTransform$Builder;->mConfig:Landroid/net/IpSecConfig; -Landroid/net/IpSecTransform$Builder;->mContext:Landroid/content/Context; -Landroid/net/IpSecTransform$NattKeepaliveCallback;-><init>()V -Landroid/net/IpSecTransform$NattKeepaliveCallback;->ERROR_HARDWARE_ERROR:I -Landroid/net/IpSecTransform$NattKeepaliveCallback;->ERROR_HARDWARE_UNSUPPORTED:I -Landroid/net/IpSecTransform$NattKeepaliveCallback;->ERROR_INVALID_NETWORK:I -Landroid/net/IpSecTransform$NattKeepaliveCallback;->onError(I)V -Landroid/net/IpSecTransform$NattKeepaliveCallback;->onStarted()V -Landroid/net/IpSecTransform$NattKeepaliveCallback;->onStopped()V -Landroid/net/IpSecTransform;-><init>(Landroid/content/Context;Landroid/net/IpSecConfig;)V -Landroid/net/IpSecTransform;->activate()Landroid/net/IpSecTransform; -Landroid/net/IpSecTransform;->checkResultStatus(I)V -Landroid/net/IpSecTransform;->ENCAP_ESPINUDP:I -Landroid/net/IpSecTransform;->ENCAP_ESPINUDP_NON_IKE:I -Landroid/net/IpSecTransform;->ENCAP_NONE:I -Landroid/net/IpSecTransform;->equals(Landroid/net/IpSecTransform;Landroid/net/IpSecTransform;)Z -Landroid/net/IpSecTransform;->getConfig()Landroid/net/IpSecConfig; -Landroid/net/IpSecTransform;->getIpSecService()Landroid/net/IIpSecService; -Landroid/net/IpSecTransform;->getResourceId()I -Landroid/net/IpSecTransform;->mCallbackHandler:Landroid/os/Handler; -Landroid/net/IpSecTransform;->mCloseGuard:Ldalvik/system/CloseGuard; -Landroid/net/IpSecTransform;->mConfig:Landroid/net/IpSecConfig; -Landroid/net/IpSecTransform;->mContext:Landroid/content/Context; -Landroid/net/IpSecTransform;->mKeepalive:Landroid/net/ConnectivityManager$PacketKeepalive; -Landroid/net/IpSecTransform;->mKeepaliveCallback:Landroid/net/ConnectivityManager$PacketKeepaliveCallback; -Landroid/net/IpSecTransform;->MODE_TRANSPORT:I -Landroid/net/IpSecTransform;->MODE_TUNNEL:I -Landroid/net/IpSecTransform;->mResourceId:I -Landroid/net/IpSecTransform;->mUserKeepaliveCallback:Landroid/net/IpSecTransform$NattKeepaliveCallback; -Landroid/net/IpSecTransform;->startNattKeepalive(Landroid/net/IpSecTransform$NattKeepaliveCallback;ILandroid/os/Handler;)V -Landroid/net/IpSecTransform;->stopNattKeepalive()V -Landroid/net/IpSecTransform;->TAG:Ljava/lang/String; -Landroid/net/IpSecTransformResponse;-><init>(I)V -Landroid/net/IpSecTransformResponse;-><init>(II)V -Landroid/net/IpSecTransformResponse;-><init>(Landroid/os/Parcel;)V -Landroid/net/IpSecTransformResponse;->CREATOR:Landroid/os/Parcelable$Creator; -Landroid/net/IpSecTransformResponse;->resourceId:I -Landroid/net/IpSecTransformResponse;->status:I -Landroid/net/IpSecTransformResponse;->TAG:Ljava/lang/String; -Landroid/net/IpSecTunnelInterfaceResponse;-><init>(I)V -Landroid/net/IpSecTunnelInterfaceResponse;-><init>(IILjava/lang/String;)V -Landroid/net/IpSecTunnelInterfaceResponse;-><init>(Landroid/os/Parcel;)V -Landroid/net/IpSecTunnelInterfaceResponse;->CREATOR:Landroid/os/Parcelable$Creator; -Landroid/net/IpSecTunnelInterfaceResponse;->interfaceName:Ljava/lang/String; -Landroid/net/IpSecTunnelInterfaceResponse;->resourceId:I -Landroid/net/IpSecTunnelInterfaceResponse;->status:I -Landroid/net/IpSecTunnelInterfaceResponse;->TAG:Ljava/lang/String; -Landroid/net/IpSecUdpEncapResponse;-><init>(I)V -Landroid/net/IpSecUdpEncapResponse;-><init>(IIILjava/io/FileDescriptor;)V -Landroid/net/IpSecUdpEncapResponse;-><init>(Landroid/os/Parcel;)V -Landroid/net/IpSecUdpEncapResponse;->CREATOR:Landroid/os/Parcelable$Creator; -Landroid/net/IpSecUdpEncapResponse;->fileDescriptor:Landroid/os/ParcelFileDescriptor; -Landroid/net/IpSecUdpEncapResponse;->port:I -Landroid/net/IpSecUdpEncapResponse;->resourceId:I -Landroid/net/IpSecUdpEncapResponse;->status:I -Landroid/net/IpSecUdpEncapResponse;->TAG:Ljava/lang/String; Landroid/net/ITetheringStatsProvider$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Landroid/net/ITetheringStatsProvider$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String; Landroid/net/ITetheringStatsProvider$Stub$Proxy;->getTetherStats(I)Landroid/net/NetworkStats; @@ -36742,41 +36388,6 @@ Landroid/net/SSLSessionCache;->TAG:Ljava/lang/String; Landroid/net/StringNetworkSpecifier;-><init>(Ljava/lang/String;)V Landroid/net/StringNetworkSpecifier;->CREATOR:Landroid/os/Parcelable$Creator; Landroid/net/StringNetworkSpecifier;->satisfiedBy(Landroid/net/NetworkSpecifier;)Z -Landroid/net/TrafficStats;->addIfSupported(J)J -Landroid/net/TrafficStats;->closeQuietly(Landroid/net/INetworkStatsSession;)V -Landroid/net/TrafficStats;->GB_IN_BYTES:J -Landroid/net/TrafficStats;->getDataLayerSnapshotForUid(Landroid/content/Context;)Landroid/net/NetworkStats; -Landroid/net/TrafficStats;->getRxPackets(Ljava/lang/String;)J -Landroid/net/TrafficStats;->getTxPackets(Ljava/lang/String;)J -Landroid/net/TrafficStats;->KB_IN_BYTES:J -Landroid/net/TrafficStats;->LOOPBACK_IFACE:Ljava/lang/String; -Landroid/net/TrafficStats;->MB_IN_BYTES:J -Landroid/net/TrafficStats;->PB_IN_BYTES:J -Landroid/net/TrafficStats;->sActiveProfilingStart:Landroid/net/NetworkStats; -Landroid/net/TrafficStats;->sProfilingLock:Ljava/lang/Object; -Landroid/net/TrafficStats;->sStatsService:Landroid/net/INetworkStatsService; -Landroid/net/TrafficStats;->startDataProfiling(Landroid/content/Context;)V -Landroid/net/TrafficStats;->stopDataProfiling(Landroid/content/Context;)Landroid/net/NetworkStats; -Landroid/net/TrafficStats;->TAG_SYSTEM_APP:I -Landroid/net/TrafficStats;->TAG_SYSTEM_BACKUP:I -Landroid/net/TrafficStats;->TAG_SYSTEM_DHCP:I -Landroid/net/TrafficStats;->TAG_SYSTEM_DOWNLOAD:I -Landroid/net/TrafficStats;->TAG_SYSTEM_GPS:I -Landroid/net/TrafficStats;->TAG_SYSTEM_MEDIA:I -Landroid/net/TrafficStats;->TAG_SYSTEM_NEIGHBOR:I -Landroid/net/TrafficStats;->TAG_SYSTEM_NTP:I -Landroid/net/TrafficStats;->TAG_SYSTEM_PAC:I -Landroid/net/TrafficStats;->TAG_SYSTEM_PROBE:I -Landroid/net/TrafficStats;->TAG_SYSTEM_RESTORE:I -Landroid/net/TrafficStats;->TB_IN_BYTES:J -Landroid/net/TrafficStats;->TYPE_RX_BYTES:I -Landroid/net/TrafficStats;->TYPE_RX_PACKETS:I -Landroid/net/TrafficStats;->TYPE_TCP_RX_PACKETS:I -Landroid/net/TrafficStats;->TYPE_TCP_TX_PACKETS:I -Landroid/net/TrafficStats;->TYPE_TX_BYTES:I -Landroid/net/TrafficStats;->TYPE_TX_PACKETS:I -Landroid/net/TrafficStats;->UID_REMOVED:I -Landroid/net/TrafficStats;->UID_TETHERING:I Landroid/net/Uri$AbstractHierarchicalUri;-><init>()V Landroid/net/Uri$AbstractHierarchicalUri;->getUserInfoPart()Landroid/net/Uri$Part; Landroid/net/Uri$AbstractHierarchicalUri;->host:Ljava/lang/String; diff --git a/boot/hiddenapi/hiddenapi-unsupported.txt b/boot/hiddenapi/hiddenapi-unsupported.txt index 002d42dbf1dc..e47149b7e671 100644 --- a/boot/hiddenapi/hiddenapi-unsupported.txt +++ b/boot/hiddenapi/hiddenapi-unsupported.txt @@ -170,9 +170,6 @@ Landroid/media/tv/ITvRemoteProvider$Stub;-><init>()V Landroid/net/INetworkManagementEventObserver$Stub;-><init>()V Landroid/net/INetworkPolicyManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/INetworkPolicyManager; Landroid/net/INetworkScoreService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/INetworkScoreService; -Landroid/net/INetworkStatsService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V -Landroid/net/INetworkStatsService$Stub$Proxy;->getMobileIfaces()[Ljava/lang/String; -Landroid/net/INetworkStatsService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/INetworkStatsService; Landroid/os/IBatteryPropertiesRegistrar$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Landroid/os/IDeviceIdentifiersPolicyService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IDeviceIdentifiersPolicyService; Landroid/os/IDeviceIdleController$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IDeviceIdleController; diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp index c134822585e0..c202f6f03b5b 100644 --- a/cmds/idmap2/Android.bp +++ b/cmds/idmap2/Android.bp @@ -39,6 +39,7 @@ cc_defaults { "-modernize-pass-by-value", "-modernize-replace-disallow-copy-and-assign-macro", "-modernize-return-braced-init-list", + "-modernize-use-default-member-init", "-modernize-use-equals-default", "-modernize-use-nodiscard", "-modernize-use-override", diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp index a8d648917b08..1b2d905aec0a 100644 --- a/cmds/idmap2/idmap2d/Idmap2Service.cpp +++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp @@ -39,11 +39,9 @@ #include "idmap2/Result.h" #include "idmap2/SysTrace.h" -using android::IPCThreadState; using android::base::StringPrintf; using android::binder::Status; using android::idmap2::BinaryStreamVisitor; -using android::idmap2::FabricatedOverlay; using android::idmap2::FabricatedOverlayContainer; using android::idmap2::Idmap; using android::idmap2::IdmapHeader; diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp index 9c6402a6e36e..738b9cf237c9 100644 --- a/cmds/idmap2/tests/IdmapTests.cpp +++ b/cmds/idmap2/tests/IdmapTests.cpp @@ -37,7 +37,6 @@ #include "idmap2/Idmap.h" #include "idmap2/LogInfo.h" -using android::Res_value; using ::testing::NotNull; using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags; diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp index 5a1d808af06f..32b3d1326d92 100644 --- a/cmds/idmap2/tests/ResourceMappingTests.cpp +++ b/cmds/idmap2/tests/ResourceMappingTests.cpp @@ -29,8 +29,6 @@ #include "idmap2/LogInfo.h" #include "idmap2/ResourceMapping.h" -using android::Res_value; - using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags; namespace android::idmap2 { diff --git a/core/api/current.txt b/core/api/current.txt index a32a3a9207aa..42407ea10fb5 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -8339,62 +8339,6 @@ package android.app.usage { field @NonNull public static final android.os.Parcelable.Creator<android.app.usage.ExternalStorageStats> CREATOR; } - public final class NetworkStats implements java.lang.AutoCloseable { - method public void close(); - method public boolean getNextBucket(android.app.usage.NetworkStats.Bucket); - method public boolean hasNextBucket(); - } - - public static class NetworkStats.Bucket { - ctor public NetworkStats.Bucket(); - method public int getDefaultNetworkStatus(); - method public long getEndTimeStamp(); - method public int getMetered(); - method public int getRoaming(); - method public long getRxBytes(); - method public long getRxPackets(); - method public long getStartTimeStamp(); - method public int getState(); - method public int getTag(); - method public long getTxBytes(); - method public long getTxPackets(); - method public int getUid(); - field public static final int DEFAULT_NETWORK_ALL = -1; // 0xffffffff - field public static final int DEFAULT_NETWORK_NO = 1; // 0x1 - field public static final int DEFAULT_NETWORK_YES = 2; // 0x2 - field public static final int METERED_ALL = -1; // 0xffffffff - field public static final int METERED_NO = 1; // 0x1 - field public static final int METERED_YES = 2; // 0x2 - field public static final int ROAMING_ALL = -1; // 0xffffffff - field public static final int ROAMING_NO = 1; // 0x1 - field public static final int ROAMING_YES = 2; // 0x2 - field public static final int STATE_ALL = -1; // 0xffffffff - field public static final int STATE_DEFAULT = 1; // 0x1 - field public static final int STATE_FOREGROUND = 2; // 0x2 - field public static final int TAG_NONE = 0; // 0x0 - field public static final int UID_ALL = -1; // 0xffffffff - field public static final int UID_REMOVED = -4; // 0xfffffffc - field public static final int UID_TETHERING = -5; // 0xfffffffb - } - - public class NetworkStatsManager { - method @WorkerThread public android.app.usage.NetworkStats queryDetails(int, String, long, long) throws android.os.RemoteException, java.lang.SecurityException; - method @WorkerThread public android.app.usage.NetworkStats queryDetailsForUid(int, String, long, long, int) throws java.lang.SecurityException; - method @WorkerThread public android.app.usage.NetworkStats queryDetailsForUidTag(int, String, long, long, int, int) throws java.lang.SecurityException; - method @WorkerThread public android.app.usage.NetworkStats queryDetailsForUidTagState(int, String, long, long, int, int, int) throws java.lang.SecurityException; - method @WorkerThread public android.app.usage.NetworkStats querySummary(int, String, long, long) throws android.os.RemoteException, java.lang.SecurityException; - method @WorkerThread public android.app.usage.NetworkStats.Bucket querySummaryForDevice(int, String, long, long) throws android.os.RemoteException, java.lang.SecurityException; - method @WorkerThread public android.app.usage.NetworkStats.Bucket querySummaryForUser(int, String, long, long) throws android.os.RemoteException, java.lang.SecurityException; - method public void registerUsageCallback(int, String, long, android.app.usage.NetworkStatsManager.UsageCallback); - method public void registerUsageCallback(int, String, long, android.app.usage.NetworkStatsManager.UsageCallback, @Nullable android.os.Handler); - method public void unregisterUsageCallback(android.app.usage.NetworkStatsManager.UsageCallback); - } - - public abstract static class NetworkStatsManager.UsageCallback { - ctor public NetworkStatsManager.UsageCallback(); - method public abstract void onThresholdReached(int, String); - } - public final class StorageStats implements android.os.Parcelable { method public int describeContents(); method public long getAppBytes(); @@ -19114,6 +19058,7 @@ package android.media { method public boolean isSink(); method public boolean isSource(); field public static final int TYPE_AUX_LINE = 19; // 0x13 + field public static final int TYPE_BLE_BROADCAST = 30; // 0x1e field public static final int TYPE_BLE_HEADSET = 26; // 0x1a field public static final int TYPE_BLE_SPEAKER = 27; // 0x1b field public static final int TYPE_BLUETOOTH_A2DP = 8; // 0x8 @@ -25198,6 +25143,14 @@ package android.net { method public int getUid(); } + public final class EthernetNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable { + ctor public EthernetNetworkSpecifier(@NonNull String); + method public int describeContents(); + method @Nullable public String getInterfaceName(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.EthernetNetworkSpecifier> CREATOR; + } + public final class Ikev2VpnProfile extends android.net.PlatformVpnProfile { method @NonNull public java.util.List<java.lang.String> getAllowedAlgorithms(); method public int getMaxMtu(); @@ -25223,79 +25176,11 @@ package android.net { method @NonNull public android.net.Ikev2VpnProfile.Builder setAuthPsk(@NonNull byte[]); method @NonNull public android.net.Ikev2VpnProfile.Builder setAuthUsernamePassword(@NonNull String, @NonNull String, @Nullable java.security.cert.X509Certificate); method @NonNull public android.net.Ikev2VpnProfile.Builder setBypassable(boolean); - method @NonNull public android.net.Ikev2VpnProfile.Builder setExcludeLocalRoutes(boolean); + method @NonNull public android.net.Ikev2VpnProfile.Builder setLocalRoutesExcluded(boolean); method @NonNull public android.net.Ikev2VpnProfile.Builder setMaxMtu(int); method @NonNull public android.net.Ikev2VpnProfile.Builder setMetered(boolean); method @NonNull public android.net.Ikev2VpnProfile.Builder setProxy(@Nullable android.net.ProxyInfo); - } - - public final class IpSecAlgorithm implements android.os.Parcelable { - ctor public IpSecAlgorithm(@NonNull String, @NonNull byte[]); - ctor public IpSecAlgorithm(@NonNull String, @NonNull byte[], int); - method public int describeContents(); - method @NonNull public byte[] getKey(); - method @NonNull public String getName(); - method @NonNull public static java.util.Set<java.lang.String> getSupportedAlgorithms(); - method public int getTruncationLengthBits(); - method public void writeToParcel(android.os.Parcel, int); - field public static final String AUTH_AES_CMAC = "cmac(aes)"; - field public static final String AUTH_AES_XCBC = "xcbc(aes)"; - field public static final String AUTH_CRYPT_AES_GCM = "rfc4106(gcm(aes))"; - field public static final String AUTH_CRYPT_CHACHA20_POLY1305 = "rfc7539esp(chacha20,poly1305)"; - field public static final String AUTH_HMAC_MD5 = "hmac(md5)"; - field public static final String AUTH_HMAC_SHA1 = "hmac(sha1)"; - field public static final String AUTH_HMAC_SHA256 = "hmac(sha256)"; - field public static final String AUTH_HMAC_SHA384 = "hmac(sha384)"; - field public static final String AUTH_HMAC_SHA512 = "hmac(sha512)"; - field @NonNull public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR; - field public static final String CRYPT_AES_CBC = "cbc(aes)"; - field public static final String CRYPT_AES_CTR = "rfc3686(ctr(aes))"; - } - - public final class IpSecManager { - method @NonNull public android.net.IpSecManager.SecurityParameterIndex allocateSecurityParameterIndex(@NonNull java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException; - method @NonNull public android.net.IpSecManager.SecurityParameterIndex allocateSecurityParameterIndex(@NonNull java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException; - method public void applyTransportModeTransform(@NonNull java.net.Socket, int, @NonNull android.net.IpSecTransform) throws java.io.IOException; - method public void applyTransportModeTransform(@NonNull java.net.DatagramSocket, int, @NonNull android.net.IpSecTransform) throws java.io.IOException; - method public void applyTransportModeTransform(@NonNull java.io.FileDescriptor, int, @NonNull android.net.IpSecTransform) throws java.io.IOException; - method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException; - method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException; - method public void removeTransportModeTransforms(@NonNull java.net.Socket) throws java.io.IOException; - method public void removeTransportModeTransforms(@NonNull java.net.DatagramSocket) throws java.io.IOException; - method public void removeTransportModeTransforms(@NonNull java.io.FileDescriptor) throws java.io.IOException; - field public static final int DIRECTION_IN = 0; // 0x0 - field public static final int DIRECTION_OUT = 1; // 0x1 - } - - public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException { - } - - public static final class IpSecManager.SecurityParameterIndex implements java.lang.AutoCloseable { - method public void close(); - method public int getSpi(); - } - - public static final class IpSecManager.SpiUnavailableException extends android.util.AndroidException { - method public int getSpi(); - } - - public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable { - method public void close() throws java.io.IOException; - method public java.io.FileDescriptor getFileDescriptor(); - method public int getPort(); - } - - public final class IpSecTransform implements java.lang.AutoCloseable { - method public void close(); - } - - public static class IpSecTransform.Builder { - ctor public IpSecTransform.Builder(@NonNull android.content.Context); - method @NonNull public android.net.IpSecTransform buildTransportModeTransform(@NonNull java.net.InetAddress, @NonNull android.net.IpSecManager.SecurityParameterIndex) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException; - method @NonNull public android.net.IpSecTransform.Builder setAuthenticatedEncryption(@NonNull android.net.IpSecAlgorithm); - method @NonNull public android.net.IpSecTransform.Builder setAuthentication(@NonNull android.net.IpSecAlgorithm); - method @NonNull public android.net.IpSecTransform.Builder setEncryption(@NonNull android.net.IpSecAlgorithm); - method @NonNull public android.net.IpSecTransform.Builder setIpv4Encapsulation(@NonNull android.net.IpSecManager.UdpEncapsulationSocket, int); + method @NonNull public android.net.Ikev2VpnProfile.Builder setRequiresInternetValidation(boolean); } public class LocalServerSocket implements java.io.Closeable { @@ -25369,9 +25254,10 @@ package android.net { } public abstract class PlatformVpnProfile { - method public final boolean getExcludeLocalRoutes(); + method public final boolean areLocalRoutesExcluded(); method public final int getType(); method @NonNull public final String getTypeString(); + method public final boolean isInternetValidationRequired(); field public static final int TYPE_IKEV2_IPSEC_PSK = 7; // 0x7 field public static final int TYPE_IKEV2_IPSEC_RSA = 8; // 0x8 field public static final int TYPE_IKEV2_IPSEC_USER_PASS = 6; // 0x6 @@ -25424,50 +25310,6 @@ package android.net { method @NonNull public android.net.TelephonyNetworkSpecifier.Builder setSubscriptionId(int); } - public class TrafficStats { - ctor public TrafficStats(); - method public static void clearThreadStatsTag(); - method public static void clearThreadStatsUid(); - method public static int getAndSetThreadStatsTag(int); - method public static long getMobileRxBytes(); - method public static long getMobileRxPackets(); - method public static long getMobileTxBytes(); - method public static long getMobileTxPackets(); - method public static long getRxBytes(@NonNull String); - method public static long getRxPackets(@NonNull String); - method public static int getThreadStatsTag(); - method public static int getThreadStatsUid(); - method public static long getTotalRxBytes(); - method public static long getTotalRxPackets(); - method public static long getTotalTxBytes(); - method public static long getTotalTxPackets(); - method public static long getTxBytes(@NonNull String); - method public static long getTxPackets(@NonNull String); - method public static long getUidRxBytes(int); - method public static long getUidRxPackets(int); - method @Deprecated public static long getUidTcpRxBytes(int); - method @Deprecated public static long getUidTcpRxSegments(int); - method @Deprecated public static long getUidTcpTxBytes(int); - method @Deprecated public static long getUidTcpTxSegments(int); - method public static long getUidTxBytes(int); - method public static long getUidTxPackets(int); - method @Deprecated public static long getUidUdpRxBytes(int); - method @Deprecated public static long getUidUdpRxPackets(int); - method @Deprecated public static long getUidUdpTxBytes(int); - method @Deprecated public static long getUidUdpTxPackets(int); - method public static void incrementOperationCount(int); - method public static void incrementOperationCount(int, int); - method public static void setThreadStatsTag(int); - method public static void setThreadStatsUid(int); - method public static void tagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException; - method public static void tagFileDescriptor(java.io.FileDescriptor) throws java.io.IOException; - method public static void tagSocket(java.net.Socket) throws java.net.SocketException; - method public static void untagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException; - method public static void untagFileDescriptor(java.io.FileDescriptor) throws java.io.IOException; - method public static void untagSocket(java.net.Socket) throws java.net.SocketException; - field public static final int UNSUPPORTED = -1; // 0xffffffff - } - public abstract class Uri implements java.lang.Comparable<android.net.Uri> android.os.Parcelable { method public abstract android.net.Uri.Builder buildUpon(); method public int compareTo(android.net.Uri); @@ -25606,8 +25448,26 @@ package android.net { public class VpnManager { method public void deleteProvisionedVpnProfile(); method @Nullable public android.content.Intent provisionVpnProfile(@NonNull android.net.PlatformVpnProfile); - method public void startProvisionedVpnProfile(); + method @Deprecated public void startProvisionedVpnProfile(); + method @NonNull public String startProvisionedVpnProfileSession(); method public void stopProvisionedVpnProfile(); + field public static final String ACTION_VPN_MANAGER_EVENT = "android.net.action.VPN_MANAGER_EVENT"; + field public static final String CATEGORY_EVENT_DEACTIVATED_BY_USER = "android.net.category.EVENT_DEACTIVATED_BY_USER"; + field public static final String CATEGORY_EVENT_IKE_ERROR = "android.net.category.EVENT_IKE_ERROR"; + field public static final String CATEGORY_EVENT_NETWORK_ERROR = "android.net.category.EVENT_NETWORK_ERROR"; + field public static final int ERROR_CLASS_NOT_RECOVERABLE = 1; // 0x1 + field public static final int ERROR_CLASS_RECOVERABLE = 2; // 0x2 + field public static final int ERROR_CODE_NETWORK_IO = 3; // 0x3 + field public static final int ERROR_CODE_NETWORK_LOST = 2; // 0x2 + field public static final int ERROR_CODE_NETWORK_PROTOCOL_TIMEOUT = 1; // 0x1 + field public static final int ERROR_CODE_NETWORK_UNKNOWN_HOST = 0; // 0x0 + field public static final String EXTRA_ERROR_CLASS = "android.net.extra.ERROR_CLASS"; + field public static final String EXTRA_ERROR_CODE = "android.net.extra.ERROR_CODE"; + field public static final String EXTRA_SESSION_KEY = "android.net.extra.SESSION_KEY"; + field public static final String EXTRA_TIMESTAMP_MILLIS = "android.net.extra.TIMESTAMP_MILLIS"; + field public static final String EXTRA_UNDERLYING_LINK_PROPERTIES = "android.net.extra.UNDERLYING_LINK_PROPERTIES"; + field public static final String EXTRA_UNDERLYING_NETWORK = "android.net.extra.UNDERLYING_NETWORK"; + field public static final String EXTRA_UNDERLYING_NETWORK_CAPABILITIES = "android.net.extra.UNDERLYING_NETWORK_CAPABILITIES"; } public class VpnService extends android.app.Service { @@ -26229,7 +26089,6 @@ package android.nfc.cardemulation { field public static final String CATEGORY_PAYMENT = "payment"; field public static final String EXTRA_CATEGORY = "category"; field public static final String EXTRA_SERVICE_COMPONENT = "component"; - field public static final String EXTRA_USERID = "android.nfc.cardemulation.extra.USERID"; field public static final int SELECTION_MODE_ALWAYS_ASK = 1; // 0x1 field public static final int SELECTION_MODE_ASK_IF_CONFLICT = 2; // 0x2 field public static final int SELECTION_MODE_PREFER_DEFAULT = 0; // 0x0 @@ -29464,7 +29323,7 @@ package android.os { public class BaseBundle { method public void clear(); method public boolean containsKey(String); - method @Nullable public Object get(String); + method @Deprecated @Nullable public Object get(String); method public boolean getBoolean(String); method public boolean getBoolean(String, boolean); method @Nullable public boolean[] getBooleanArray(@Nullable String); @@ -29636,6 +29495,7 @@ package android.os { field public static final int PREVIEW_SDK_INT; field public static final String RELEASE; field @NonNull public static final String RELEASE_OR_CODENAME; + field @NonNull public static final String RELEASE_OR_PREVIEW_DISPLAY; field @Deprecated public static final String SDK; field public static final int SDK_INT; field public static final String SECURITY_PATCH; @@ -29675,6 +29535,7 @@ package android.os { field public static final int Q = 29; // 0x1d field public static final int R = 30; // 0x1e field public static final int S = 31; // 0x1f + field public static final int S_V2 = 32; // 0x20 field public static final int TIRAMISU = 10000; // 0x2710 } @@ -29704,16 +29565,21 @@ package android.os { method public float getFloat(String, float); method @Nullable public float[] getFloatArray(@Nullable String); method @Nullable public java.util.ArrayList<java.lang.Integer> getIntegerArrayList(@Nullable String); - method @Nullable public <T extends android.os.Parcelable> T getParcelable(@Nullable String); - method @Nullable public android.os.Parcelable[] getParcelableArray(@Nullable String); - method @Nullable public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayList(@Nullable String); - method @Nullable public java.io.Serializable getSerializable(@Nullable String); + method @Deprecated @Nullable public <T extends android.os.Parcelable> T getParcelable(@Nullable String); + method @Nullable public <T> T getParcelable(@Nullable String, @NonNull Class<T>); + method @Deprecated @Nullable public android.os.Parcelable[] getParcelableArray(@Nullable String); + method @Nullable public <T> T[] getParcelableArray(@Nullable String, @NonNull Class<T>); + method @Deprecated @Nullable public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayList(@Nullable String); + method @Nullable public <T> java.util.ArrayList<T> getParcelableArrayList(@Nullable String, @NonNull Class<? extends T>); + method @Deprecated @Nullable public java.io.Serializable getSerializable(@Nullable String); + method @Nullable public <T extends java.io.Serializable> T getSerializable(@Nullable String, @NonNull Class<T>); method public short getShort(String); method public short getShort(String, short); method @Nullable public short[] getShortArray(@Nullable String); method @Nullable public android.util.Size getSize(@Nullable String); method @Nullable public android.util.SizeF getSizeF(@Nullable String); - method @Nullable public <T extends android.os.Parcelable> android.util.SparseArray<T> getSparseParcelableArray(@Nullable String); + method @Deprecated @Nullable public <T extends android.os.Parcelable> android.util.SparseArray<T> getSparseParcelableArray(@Nullable String); + method @Nullable public <T> android.util.SparseArray<T> getSparseParcelableArray(@Nullable String, @NonNull Class<? extends T>); method @Nullable public java.util.ArrayList<java.lang.String> getStringArrayList(@Nullable String); method public boolean hasFileDescriptors(); method public void putAll(android.os.Bundle); @@ -30269,6 +30135,9 @@ package android.os { method @Nullable public byte[] createByteArray(); method @Nullable public char[] createCharArray(); method @Nullable public double[] createDoubleArray(); + method @Nullable public <T> T createFixedArray(@NonNull Class<T>, @NonNull int...); + method @Nullable public <T, S extends android.os.IInterface> T createFixedArray(@NonNull Class<T>, @NonNull java.util.function.Function<android.os.IBinder,S>, @NonNull int...); + method @Nullable public <T, S extends android.os.Parcelable> T createFixedArray(@NonNull Class<T>, @NonNull android.os.Parcelable.Creator<S>, @NonNull int...); method @Nullable public float[] createFloatArray(); method @Nullable public int[] createIntArray(); method @Nullable public <T extends android.os.IInterface> T[] createInterfaceArray(@NonNull java.util.function.IntFunction<T[]>, @NonNull java.util.function.Function<android.os.IBinder,T>); @@ -30309,6 +30178,9 @@ package android.os { method public void readException(); method public void readException(int, String); method public android.os.ParcelFileDescriptor readFileDescriptor(); + method public <T> void readFixedArray(@NonNull T); + method public <T, S extends android.os.IInterface> void readFixedArray(@NonNull T, @NonNull java.util.function.Function<android.os.IBinder,S>); + method public <T, S extends android.os.Parcelable> void readFixedArray(@NonNull T, @NonNull android.os.Parcelable.Creator<S>); method public float readFloat(); method public void readFloatArray(@NonNull float[]); method @Deprecated @Nullable public java.util.HashMap readHashMap(@Nullable ClassLoader); @@ -30330,7 +30202,7 @@ package android.os { method @Deprecated @Nullable public android.os.Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader); method @Nullable public <T> android.os.Parcelable.Creator<T> readParcelableCreator(@Nullable ClassLoader, @NonNull Class<T>); method @Deprecated @NonNull public <T extends android.os.Parcelable> java.util.List<T> readParcelableList(@NonNull java.util.List<T>, @Nullable ClassLoader); - method @NonNull public <T> java.util.List<T> readParcelableList(@NonNull java.util.List<T>, @Nullable ClassLoader, @NonNull Class<T>); + method @NonNull public <T> java.util.List<T> readParcelableList(@NonNull java.util.List<T>, @Nullable ClassLoader, @NonNull Class<? extends T>); method @Nullable public android.os.PersistableBundle readPersistableBundle(); method @Nullable public android.os.PersistableBundle readPersistableBundle(@Nullable ClassLoader); method @Deprecated @Nullable public java.io.Serializable readSerializable(); @@ -30352,6 +30224,7 @@ package android.os { method public void setDataCapacity(int); method public void setDataPosition(int); method public void setDataSize(int); + method public void setPropagateAllowBlocking(); method public void unmarshall(@NonNull byte[], int, int); method public void writeArray(@Nullable Object[]); method public void writeBinderArray(@Nullable android.os.IBinder[]); @@ -30367,6 +30240,7 @@ package android.os { method public void writeDoubleArray(@Nullable double[]); method public void writeException(@NonNull Exception); method public void writeFileDescriptor(@NonNull java.io.FileDescriptor); + method public <T> void writeFixedArray(@Nullable T, int, @NonNull int...); method public void writeFloat(float); method public void writeFloatArray(@Nullable float[]); method public void writeInt(int); @@ -36183,6 +36057,28 @@ package android.security { method @Deprecated @NonNull public android.security.KeyPairGeneratorSpec.Builder setSubject(@NonNull javax.security.auth.x500.X500Principal); } + public class KeyStoreException extends java.lang.Exception { + method public int getNumericErrorCode(); + method public boolean isSystemError(); + method public boolean isTransientFailure(); + method public boolean requiresUserAuthentication(); + field public static final int ERROR_ATTESTATION_CHALLENGE_TOO_LARGE = 9; // 0x9 + field public static final int ERROR_ID_ATTESTATION_FAILURE = 8; // 0x8 + field public static final int ERROR_INCORRECT_USAGE = 13; // 0xd + field public static final int ERROR_INTERNAL_SYSTEM_ERROR = 4; // 0x4 + field public static final int ERROR_KEYMINT_FAILURE = 10; // 0xa + field public static final int ERROR_KEYSTORE_FAILURE = 11; // 0xb + field public static final int ERROR_KEYSTORE_UNINITIALIZED = 3; // 0x3 + field public static final int ERROR_KEY_CORRUPTED = 7; // 0x7 + field public static final int ERROR_KEY_DOES_NOT_EXIST = 6; // 0x6 + field public static final int ERROR_KEY_NOT_TEMPORALLY_VALID = 14; // 0xe + field public static final int ERROR_KEY_OPERATION_EXPIRED = 15; // 0xf + field public static final int ERROR_OTHER = 1; // 0x1 + field public static final int ERROR_PERMISSION_DENIED = 5; // 0x5 + field public static final int ERROR_UNIMPLEMENTED = 12; // 0xc + field public static final int ERROR_USER_AUTHENTICATION_REQUIRED = 2; // 0x2 + } + @Deprecated public final class KeyStoreParameter implements java.security.KeyStore.ProtectionParameter { method @Deprecated public boolean isEncryptionRequired(); } @@ -39736,13 +39632,14 @@ package android.telephony { field public static final String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool"; field public static final String KEY_CARRIER_SUPPORTS_OPP_DATA_AUTO_PROVISIONING_BOOL = "carrier_supports_opp_data_auto_provisioning_bool"; field public static final String KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL = "carrier_supports_ss_over_ut_bool"; + field public static final String KEY_CARRIER_SUPPORTS_TETHERING_BOOL = "carrier_supports_tethering_bool"; field public static final String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool"; field public static final String KEY_CARRIER_USSD_METHOD_INT = "carrier_ussd_method_int"; - field public static final String KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL = "carrier_ut_provisioning_required_bool"; + field @Deprecated public static final String KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL = "carrier_ut_provisioning_required_bool"; field public static final String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool"; field public static final String KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL = "carrier_volte_override_wfc_provisioning_bool"; - field public static final String KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool"; - field public static final String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool"; + field @Deprecated public static final String KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool"; + field @Deprecated public static final String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool"; field public static final String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool"; field public static final String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool"; field @Deprecated public static final String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string"; @@ -39818,6 +39715,7 @@ package android.telephony { field public static final String KEY_IMS_CONFERENCE_SIZE_LIMIT_INT = "ims_conference_size_limit_int"; field public static final String KEY_IMS_DTMF_TONE_DELAY_INT = "ims_dtmf_tone_delay_int"; field public static final String KEY_IS_IMS_CONFERENCE_SIZE_ENFORCED_BOOL = "is_ims_conference_size_enforced_bool"; + field public static final String KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL = "is_opportunistic_subscription_bool"; field public static final String KEY_LTE_ENABLED_BOOL = "lte_enabled_bool"; field public static final String KEY_LTE_RSRQ_THRESHOLDS_INT_ARRAY = "lte_rsrq_thresholds_int_array"; field public static final String KEY_LTE_RSSNR_THRESHOLDS_INT_ARRAY = "lte_rssnr_thresholds_int_array"; @@ -39902,6 +39800,7 @@ package android.telephony { field public static final String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool"; field public static final String KEY_SMDP_SERVER_ADDRESS_STRING = "smdp_server_address_string"; field public static final String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool"; + field public static final String KEY_SUBSCRIPTION_GROUP_UUID_STRING = "subscription_group_uuid_string"; field public static final String KEY_SUPPORTS_CALL_COMPOSER_BOOL = "supports_call_composer_bool"; field public static final String KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_DTMF_BOOL = "supports_device_to_device_communication_using_dtmf_bool"; field public static final String KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_RTP_BOOL = "supports_device_to_device_communication_using_rtp_bool"; @@ -39945,6 +39844,7 @@ package android.telephony { field public static final String KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING = "wfc_emergency_address_carrier_app_string"; field public static final String KEY_WORLD_MODE_ENABLED_BOOL = "world_mode_enabled_bool"; field public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool"; + field public static final String REMOVE_GROUP_UUID_STRING = "00000000-0000-0000-0000-000000000000"; field public static final int SERVICE_CLASS_NONE = 0; // 0x0 field public static final int SERVICE_CLASS_VOICE = 1; // 0x1 field public static final int USSD_OVER_CS_ONLY = 2; // 0x2 @@ -39968,14 +39868,24 @@ package android.telephony { } public static final class CarrierConfigManager.Ims { + field public static final String KEY_CAPABILITY_TYPE_CALL_COMPOSER_INT_ARRAY = "ims.capability_type_call_composer_int_array"; + field public static final String KEY_CAPABILITY_TYPE_OPTIONS_UCE_INT_ARRAY = "ims.capability_type_options_uce_int_array"; + field public static final String KEY_CAPABILITY_TYPE_PRESENCE_UCE_INT_ARRAY = "ims.capability_type_presence_uce_int_array"; + field public static final String KEY_CAPABILITY_TYPE_SMS_INT_ARRAY = "ims.capability_type_sms_int_array"; + field public static final String KEY_CAPABILITY_TYPE_UT_INT_ARRAY = "ims.capability_type_ut_int_array"; + field public static final String KEY_CAPABILITY_TYPE_VIDEO_INT_ARRAY = "ims.capability_type_video_int_array"; + field public static final String KEY_CAPABILITY_TYPE_VOICE_INT_ARRAY = "ims.capability_type_voice_int_array"; field public static final String KEY_ENABLE_PRESENCE_CAPABILITY_EXCHANGE_BOOL = "ims.enable_presence_capability_exchange_bool"; field public static final String KEY_ENABLE_PRESENCE_GROUP_SUBSCRIBE_BOOL = "ims.enable_presence_group_subscribe_bool"; field public static final String KEY_ENABLE_PRESENCE_PUBLISH_BOOL = "ims.enable_presence_publish_bool"; field public static final String KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL = "ims.ims_single_registration_required_bool"; + field public static final String KEY_MMTEL_REQUIRES_PROVISIONING_BUNDLE = "ims.mmtel_requires_provisioning_bundle"; field public static final String KEY_NON_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC_INT = "ims.non_rcs_capabilities_cache_expiration_sec_int"; field public static final String KEY_PREFIX = "ims."; field public static final String KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL = "ims.rcs_bulk_capability_exchange_bool"; field public static final String KEY_RCS_FEATURE_TAG_ALLOWED_STRING_ARRAY = "ims.rcs_feature_tag_allowed_string_array"; + field public static final String KEY_RCS_REQUIRES_PROVISIONING_BUNDLE = "ims.rcs_requires_provisioning_bundle"; + field public static final String KEY_USE_SIP_URI_FOR_PRESENCE_SUBSCRIBE_BOOL = "ims.use_sip_uri_for_presence_subscribe_bool"; field public static final String KEY_WIFI_OFF_DEFERRING_TIME_MILLIS_INT = "ims.wifi_off_deferring_time_millis_int"; } @@ -41052,16 +40962,16 @@ package android.telephony { ctor @Deprecated public ServiceState(android.os.Parcel); method protected void copyFrom(android.telephony.ServiceState); method public int describeContents(); - method public int getCdmaNetworkId(); - method public int getCdmaSystemId(); + method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION}) public int getCdmaNetworkId(); + method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION}) public int getCdmaSystemId(); method public int[] getCellBandwidths(); method public int getChannelNumber(); method public int getDuplexMode(); method public boolean getIsManualSelection(); method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoList(); - method public String getOperatorAlphaLong(); - method public String getOperatorAlphaShort(); - method public String getOperatorNumeric(); + method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION}) public String getOperatorAlphaLong(); + method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION}) public String getOperatorAlphaShort(); + method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION}) public String getOperatorNumeric(); method public boolean getRoaming(); method public int getState(); method public boolean isSearching(); @@ -41598,6 +41508,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean doesSwitchMultiSimConfigTriggerReboot(); method public int getActiveModemCount(); method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public java.util.List<android.telephony.CellInfo> getAllCellInfo(); + method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public long getAllowedNetworkTypesForReason(int); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getCallComposerStatus(); method @Deprecated @RequiresPermission(value=android.Manifest.permission.READ_PHONE_STATE, conditional=true) public int getCallState(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getCallStateForSubscription(); @@ -41658,6 +41569,7 @@ package android.telephony { method public int getSubscriptionId(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getSubscriptionId(@NonNull android.telecom.PhoneAccountHandle); method public int getSupportedModemCount(); + method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public long getSupportedRadioAccessFamily(); method @Nullable public String getTypeAllocationCode(); method @Nullable public String getTypeAllocationCode(int); method @NonNull @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public java.util.List<android.telephony.UiccCardInfo> getUiccCardsInfo(); @@ -41703,6 +41615,7 @@ package android.telephony { method public String sendEnvelopeWithStatus(String); method @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void sendUssdRequest(String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler); method public void sendVisualVoicemailSms(String, int, String, android.app.PendingIntent); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAllowedNetworkTypesForReason(int, long); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallComposerStatus(int); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabledForReason(int, boolean); @@ -41739,6 +41652,8 @@ package android.telephony { field public static final String ACTION_SHOW_VOICEMAIL_NOTIFICATION = "android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION"; field public static final String ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED = "android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED"; field public static final String ACTION_SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED = "android.telephony.action.SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED"; + field public static final int ALLOWED_NETWORK_TYPES_REASON_CARRIER = 2; // 0x2 + field public static final int ALLOWED_NETWORK_TYPES_REASON_USER = 0; // 0x0 field public static final int APPTYPE_CSIM = 4; // 0x4 field public static final int APPTYPE_ISIM = 5; // 0x5 field public static final int APPTYPE_RUIM = 3; // 0x3 @@ -41809,6 +41724,26 @@ package android.telephony { field public static final int NETWORK_SELECTION_MODE_MANUAL = 2; // 0x2 field public static final int NETWORK_SELECTION_MODE_UNKNOWN = 0; // 0x0 field public static final int NETWORK_TYPE_1xRTT = 7; // 0x7 + field public static final long NETWORK_TYPE_BITMASK_1xRTT = 64L; // 0x40L + field public static final long NETWORK_TYPE_BITMASK_CDMA = 8L; // 0x8L + field public static final long NETWORK_TYPE_BITMASK_EDGE = 2L; // 0x2L + field public static final long NETWORK_TYPE_BITMASK_EHRPD = 8192L; // 0x2000L + field public static final long NETWORK_TYPE_BITMASK_EVDO_0 = 16L; // 0x10L + field public static final long NETWORK_TYPE_BITMASK_EVDO_A = 32L; // 0x20L + field public static final long NETWORK_TYPE_BITMASK_EVDO_B = 2048L; // 0x800L + field public static final long NETWORK_TYPE_BITMASK_GPRS = 1L; // 0x1L + field public static final long NETWORK_TYPE_BITMASK_GSM = 32768L; // 0x8000L + field public static final long NETWORK_TYPE_BITMASK_HSDPA = 128L; // 0x80L + field public static final long NETWORK_TYPE_BITMASK_HSPA = 512L; // 0x200L + field public static final long NETWORK_TYPE_BITMASK_HSPAP = 16384L; // 0x4000L + field public static final long NETWORK_TYPE_BITMASK_HSUPA = 256L; // 0x100L + field public static final long NETWORK_TYPE_BITMASK_IWLAN = 131072L; // 0x20000L + field public static final long NETWORK_TYPE_BITMASK_LTE = 4096L; // 0x1000L + field public static final long NETWORK_TYPE_BITMASK_LTE_CA = 262144L; // 0x40000L + field public static final long NETWORK_TYPE_BITMASK_NR = 524288L; // 0x80000L + field public static final long NETWORK_TYPE_BITMASK_TD_SCDMA = 65536L; // 0x10000L + field public static final long NETWORK_TYPE_BITMASK_UMTS = 4L; // 0x4L + field public static final long NETWORK_TYPE_BITMASK_UNKNOWN = 0L; // 0x0L field public static final int NETWORK_TYPE_CDMA = 4; // 0x4 field public static final int NETWORK_TYPE_EDGE = 2; // 0x2 field public static final int NETWORK_TYPE_EHRPD = 14; // 0xe @@ -42390,6 +42325,7 @@ package android.telephony.ims { public class ImsManager { method @NonNull public android.telephony.ims.ImsMmTelManager getImsMmTelManager(int); method @NonNull public android.telephony.ims.ImsRcsManager getImsRcsManager(int); + method @NonNull public android.telephony.ims.ProvisioningManager getProvisioningManager(int); field public static final String ACTION_WFC_IMS_REGISTRATION_ERROR = "android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR"; field public static final String EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_MESSAGE"; field public static final String EXTRA_WFC_REGISTRATION_FAILURE_TITLE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_TITLE"; @@ -42640,6 +42576,23 @@ package android.telephony.ims { field public static final int REASON_UNKNOWN_TEMPORARY_ERROR = 1; // 0x1 } + public class ProvisioningManager { + method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) @WorkerThread public boolean getProvisioningStatusForCapability(int, int); + method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) @WorkerThread public boolean getRcsProvisioningStatusForCapability(int, int); + method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public boolean isProvisioningRequiredForCapability(int, int); + method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public boolean isRcsProvisioningRequiredForCapability(int, int); + method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void registerFeatureProvisioningChangedCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.FeatureProvisioningCallback) throws android.telephony.ims.ImsException; + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setProvisioningStatusForCapability(int, int, boolean); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setRcsProvisioningStatusForCapability(int, int, boolean); + method public void unregisterFeatureProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.FeatureProvisioningCallback); + } + + public static class ProvisioningManager.FeatureProvisioningCallback { + ctor public ProvisioningManager.FeatureProvisioningCallback(); + method public void onFeatureProvisioningChanged(int, int, boolean); + method public void onRcsFeatureProvisioningChanged(int, int, boolean); + } + public class RcsUceAdapter { method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isUceSettingEnabled() throws android.telephony.ims.ImsException; } @@ -42680,6 +42633,27 @@ package android.telephony.ims.feature { field public static final int CAPABILITY_TYPE_VOICE = 1; // 0x1 } + public class RcsFeature { + } + + public static class RcsFeature.RcsImsCapabilities { + field public static final int CAPABILITY_TYPE_NONE = 0; // 0x0 + field public static final int CAPABILITY_TYPE_OPTIONS_UCE = 1; // 0x1 + field public static final int CAPABILITY_TYPE_PRESENCE_UCE = 2; // 0x2 + } + +} + +package android.telephony.ims.stub { + + public class ImsRegistrationImplBase { + field public static final int REGISTRATION_TECH_CROSS_SIM = 2; // 0x2 + field public static final int REGISTRATION_TECH_IWLAN = 1; // 0x1 + field public static final int REGISTRATION_TECH_LTE = 0; // 0x0 + field public static final int REGISTRATION_TECH_NONE = -1; // 0xffffffff + field public static final int REGISTRATION_TECH_NR = 3; // 0x3 + } + } package android.telephony.mbms { diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index 9e26908111d8..a9f0d2e54b21 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -51,31 +51,6 @@ package android.app { } -package android.app.usage { - - public class NetworkStatsManager { - method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void forceUpdate(); - method public static int getCollapsedRatType(int); - method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void notifyNetworkStatus(@NonNull java.util.List<android.net.Network>, @NonNull java.util.List<android.net.NetworkStateSnapshot>, @Nullable String, @NonNull java.util.List<android.net.UnderlyingNetworkInfo>); - method @NonNull @WorkerThread public android.app.usage.NetworkStats queryDetailsForDevice(@NonNull android.net.NetworkTemplate, long, long); - method @NonNull @WorkerThread public android.app.usage.NetworkStats queryDetailsForUidTagState(@NonNull android.net.NetworkTemplate, long, long, int, int, int) throws java.lang.SecurityException; - method @NonNull @WorkerThread public android.app.usage.NetworkStats querySummary(@NonNull android.net.NetworkTemplate, long, long) throws java.lang.SecurityException; - method @NonNull @WorkerThread public android.app.usage.NetworkStats.Bucket querySummaryForDevice(@NonNull android.net.NetworkTemplate, long, long); - method @NonNull @WorkerThread public android.app.usage.NetworkStats queryTaggedSummary(@NonNull android.net.NetworkTemplate, long, long) throws java.lang.SecurityException; - method public void registerUsageCallback(@NonNull android.net.NetworkTemplate, long, @NonNull java.util.concurrent.Executor, @NonNull android.app.usage.NetworkStatsManager.UsageCallback); - method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void setDefaultGlobalAlert(long); - method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void setPollOnOpen(boolean); - method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void setStatsProviderWarningAndLimitAsync(@NonNull String, long, long); - method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void setUidForeground(int, boolean); - field public static final int NETWORK_TYPE_5G_NSA = -2; // 0xfffffffe - } - - public abstract static class NetworkStatsManager.UsageCallback { - method public void onThresholdReached(@NonNull android.net.NetworkTemplate); - } - -} - package android.content { public abstract class ContentProvider implements android.content.ComponentCallbacks2 { @@ -140,7 +115,7 @@ package android.media { method public void adjustSuggestedStreamVolumeForUid(int, int, int, @NonNull String, int, int, int); method @NonNull public java.util.List<android.bluetooth.BluetoothCodecConfig> getHwOffloadFormatsSupportedForA2dp(); method @NonNull public java.util.List<android.bluetooth.BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio(); - method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void handleBluetoothActiveDeviceChanged(@Nullable android.bluetooth.BluetoothDevice, @Nullable android.bluetooth.BluetoothDevice, @NonNull android.media.BtProfileConnectionInfo); + method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void handleBluetoothActiveDeviceChanged(@Nullable android.bluetooth.BluetoothDevice, @Nullable android.bluetooth.BluetoothDevice, @NonNull android.media.BluetoothProfileConnectionInfo); method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setA2dpSuspended(boolean); method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setBluetoothHeadsetProperties(@NonNull String, boolean, boolean); method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setHfpEnabled(boolean); @@ -150,18 +125,18 @@ package android.media { field public static final int FLAG_FROM_KEY = 4096; // 0x1000 } - public final class BtProfileConnectionInfo implements android.os.Parcelable { - method @NonNull public static android.media.BtProfileConnectionInfo a2dpInfo(boolean, int); - method @NonNull public static android.media.BtProfileConnectionInfo a2dpSinkInfo(int); + public final class BluetoothProfileConnectionInfo implements android.os.Parcelable { + method @NonNull public static android.media.BluetoothProfileConnectionInfo createA2dpInfo(boolean, int); + method @NonNull public static android.media.BluetoothProfileConnectionInfo createA2dpSinkInfo(int); + method @NonNull public static android.media.BluetoothProfileConnectionInfo createHearingAidInfo(boolean); + method @NonNull public static android.media.BluetoothProfileConnectionInfo createLeAudioInfo(boolean, boolean); method public int describeContents(); - method public boolean getIsLeOutput(); method public int getProfile(); - method public boolean getSuppressNoisyIntent(); method public int getVolume(); - method @NonNull public static android.media.BtProfileConnectionInfo hearingAidInfo(boolean); - method @NonNull public static android.media.BtProfileConnectionInfo leAudio(boolean, boolean); + method public boolean isLeOutput(); + method public boolean isSuppressNoisyIntent(); method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.media.BtProfileConnectionInfo> CREATOR; + field @NonNull public static final android.os.Parcelable.Creator<android.media.BluetoothProfileConnectionInfo> CREATOR; } public class MediaMetadataRetriever implements java.lang.AutoCloseable { @@ -218,52 +193,26 @@ package android.media.session { package android.net { - public final class EthernetNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable { - ctor public EthernetNetworkSpecifier(@NonNull String); - method public int describeContents(); - method @Nullable public String getInterfaceName(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.EthernetNetworkSpecifier> CREATOR; - } - - public final class IpSecManager { - field public static final int DIRECTION_FWD = 2; // 0x2 + public class EthernetManager { + method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void addInterfaceStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.EthernetManager.InterfaceStateListener); + method public void removeInterfaceStateListener(@NonNull android.net.EthernetManager.InterfaceStateListener); + method public void setIncludeTestInterfaces(boolean); + field public static final int ROLE_CLIENT = 1; // 0x1 + field public static final int ROLE_NONE = 0; // 0x0 + field public static final int ROLE_SERVER = 2; // 0x2 + field public static final int STATE_ABSENT = 0; // 0x0 + field public static final int STATE_LINK_DOWN = 1; // 0x1 + field public static final int STATE_LINK_UP = 2; // 0x2 } - public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable { - method public int getResourceId(); + public static interface EthernetManager.InterfaceStateListener { + method public void onInterfaceStateChanged(@NonNull String, int, int, @Nullable android.net.IpConfiguration); } public class LocalSocket implements java.io.Closeable { ctor public LocalSocket(@NonNull java.io.FileDescriptor); } - public class NetworkIdentity { - method public int getOemManaged(); - method public int getRatType(); - method @Nullable public String getSubscriberId(); - method public int getType(); - method @Nullable public String getWifiNetworkKey(); - method public boolean isDefaultNetwork(); - method public boolean isMetered(); - method public boolean isRoaming(); - } - - public static final class NetworkIdentity.Builder { - ctor public NetworkIdentity.Builder(); - method @NonNull public android.net.NetworkIdentity build(); - method @NonNull public android.net.NetworkIdentity.Builder clearRatType(); - method @NonNull public android.net.NetworkIdentity.Builder setDefaultNetwork(boolean); - method @NonNull public android.net.NetworkIdentity.Builder setMetered(boolean); - method @NonNull public android.net.NetworkIdentity.Builder setNetworkStateSnapshot(@NonNull android.net.NetworkStateSnapshot); - method @NonNull public android.net.NetworkIdentity.Builder setOemManaged(int); - method @NonNull public android.net.NetworkIdentity.Builder setRatType(int); - method @NonNull public android.net.NetworkIdentity.Builder setRoaming(boolean); - method @NonNull public android.net.NetworkIdentity.Builder setSubscriberId(@Nullable String); - method @NonNull public android.net.NetworkIdentity.Builder setType(int); - method @NonNull public android.net.NetworkIdentity.Builder setWifiNetworkKey(@Nullable String); - } - public class NetworkPolicyManager { method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public int getMultipathPreference(@NonNull android.net.Network); method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public int getRestrictBackgroundStatus(int); @@ -279,94 +228,6 @@ package android.net { method public default void onUidBlockedReasonChanged(int, int); } - public final class NetworkStateSnapshot implements android.os.Parcelable { - ctor public NetworkStateSnapshot(@NonNull android.net.Network, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, @Nullable String, int); - method public int describeContents(); - method public int getLegacyType(); - method @NonNull public android.net.LinkProperties getLinkProperties(); - method @NonNull public android.net.Network getNetwork(); - method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities(); - method @Nullable public String getSubscriberId(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkStateSnapshot> CREATOR; - } - - public class NetworkStatsCollection { - method @NonNull public java.util.Map<android.net.NetworkStatsCollection.Key,android.net.NetworkStatsHistory> getEntries(); - } - - public static final class NetworkStatsCollection.Builder { - ctor public NetworkStatsCollection.Builder(long); - method @NonNull public android.net.NetworkStatsCollection.Builder addEntry(@NonNull android.net.NetworkStatsCollection.Key, @NonNull android.net.NetworkStatsHistory); - method @NonNull public android.net.NetworkStatsCollection build(); - } - - public static class NetworkStatsCollection.Key { - ctor public NetworkStatsCollection.Key(@NonNull java.util.Set<android.net.NetworkIdentity>, int, int, int); - } - - public final class NetworkStatsHistory implements android.os.Parcelable { - method public int describeContents(); - method @NonNull public java.util.List<android.net.NetworkStatsHistory.Entry> getEntries(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkStatsHistory> CREATOR; - } - - public static final class NetworkStatsHistory.Builder { - ctor public NetworkStatsHistory.Builder(long, int); - method @NonNull public android.net.NetworkStatsHistory.Builder addEntry(@NonNull android.net.NetworkStatsHistory.Entry); - method @NonNull public android.net.NetworkStatsHistory build(); - } - - public static final class NetworkStatsHistory.Entry { - ctor public NetworkStatsHistory.Entry(long, long, long, long, long, long, long); - method public long getActiveTime(); - method public long getBucketStart(); - method public long getOperations(); - method public long getRxBytes(); - method public long getRxPackets(); - method public long getTxBytes(); - method public long getTxPackets(); - } - - public final class NetworkTemplate implements android.os.Parcelable { - method public int describeContents(); - method public int getDefaultNetworkStatus(); - method public int getMatchRule(); - method public int getMeteredness(); - method public int getOemManaged(); - method public int getRatType(); - method public int getRoaming(); - method @NonNull public java.util.Set<java.lang.String> getSubscriberIds(); - method @NonNull public java.util.Set<java.lang.String> getWifiNetworkKeys(); - method public boolean matches(@NonNull android.net.NetworkIdentity); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkTemplate> CREATOR; - field public static final int MATCH_BLUETOOTH = 8; // 0x8 - field public static final int MATCH_CARRIER = 10; // 0xa - field public static final int MATCH_ETHERNET = 5; // 0x5 - field public static final int MATCH_MOBILE = 1; // 0x1 - field public static final int MATCH_WIFI = 4; // 0x4 - field public static final int NETWORK_TYPE_ALL = -1; // 0xffffffff - field public static final int OEM_MANAGED_ALL = -1; // 0xffffffff - field public static final int OEM_MANAGED_NO = 0; // 0x0 - field public static final int OEM_MANAGED_PAID = 1; // 0x1 - field public static final int OEM_MANAGED_PRIVATE = 2; // 0x2 - field public static final int OEM_MANAGED_YES = -2; // 0xfffffffe - } - - public static final class NetworkTemplate.Builder { - ctor public NetworkTemplate.Builder(int); - method @NonNull public android.net.NetworkTemplate build(); - method @NonNull public android.net.NetworkTemplate.Builder setDefaultNetworkStatus(int); - method @NonNull public android.net.NetworkTemplate.Builder setMeteredness(int); - method @NonNull public android.net.NetworkTemplate.Builder setOemManaged(int); - method @NonNull public android.net.NetworkTemplate.Builder setRatType(int); - method @NonNull public android.net.NetworkTemplate.Builder setRoaming(int); - method @NonNull public android.net.NetworkTemplate.Builder setSubscriberIds(@NonNull java.util.Set<java.lang.String>); - method @NonNull public android.net.NetworkTemplate.Builder setWifiNetworkKeys(@NonNull java.util.Set<java.lang.String>); - } - public class NetworkWatchlistManager { method @Nullable public byte[] getWatchlistConfigHash(); } @@ -385,21 +246,6 @@ package android.net { method public static void setHttpProxyConfiguration(@Nullable android.net.ProxyInfo); } - public class TrafficStats { - method public static void attachSocketTagger(); - method public static void init(@NonNull android.content.Context); - } - - public final class UnderlyingNetworkInfo implements android.os.Parcelable { - ctor public UnderlyingNetworkInfo(int, @NonNull String, @NonNull java.util.List<java.lang.String>); - method public int describeContents(); - method @NonNull public String getInterface(); - method public int getOwnerUid(); - method @NonNull public java.util.List<java.lang.String> getUnderlyingInterfaces(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.UnderlyingNetworkInfo> CREATOR; - } - public class VpnManager { field public static final int TYPE_VPN_LEGACY = 3; // 0x3 field public static final int TYPE_VPN_NONE = -1; // 0xffffffff diff --git a/core/api/removed.txt b/core/api/removed.txt index bf8642223ef5..32a46735abea 100644 --- a/core/api/removed.txt +++ b/core/api/removed.txt @@ -260,10 +260,6 @@ package android.net { method @Deprecated public static org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache); } - public class TrafficStats { - method @Deprecated public static void setThreadStatsUidSelf(); - } - } package android.os { diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 59511510e467..9db26bd1e373 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -145,6 +145,7 @@ package android { field public static final String MANAGE_CONTENT_CAPTURE = "android.permission.MANAGE_CONTENT_CAPTURE"; field public static final String MANAGE_CONTENT_SUGGESTIONS = "android.permission.MANAGE_CONTENT_SUGGESTIONS"; field public static final String MANAGE_DEBUGGING = "android.permission.MANAGE_DEBUGGING"; + field public static final String MANAGE_ETHERNET_NETWORKS = "android.permission.MANAGE_ETHERNET_NETWORKS"; field public static final String MANAGE_FACTORY_RESET_PROTECTION = "android.permission.MANAGE_FACTORY_RESET_PROTECTION"; field public static final String MANAGE_HOTWORD_DETECTION = "android.permission.MANAGE_HOTWORD_DETECTION"; field public static final String MANAGE_IPSEC_TUNNELS = "android.permission.MANAGE_IPSEC_TUNNELS"; @@ -1851,13 +1852,6 @@ package android.app.usage { field public static final String SERVICE_INTERFACE = "android.app.usage.CacheQuotaService"; } - public class NetworkStatsManager { - method @NonNull @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public android.net.NetworkStats getMobileUidStats(); - method @NonNull @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public android.net.NetworkStats getWifiUidStats(); - method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STATS_PROVIDER, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void registerNetworkStatsProvider(@NonNull String, @NonNull android.net.netstats.provider.NetworkStatsProvider); - method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STATS_PROVIDER, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void unregisterNetworkStatsProvider(@NonNull android.net.netstats.provider.NetworkStatsProvider); - } - public static final class UsageEvents.Event { method public int getInstanceId(); method @Nullable public String getNotificationChannelId(); @@ -1995,6 +1989,7 @@ package android.content { field public static final String HDMI_CONTROL_SERVICE = "hdmi_control"; field public static final String MEDIA_TRANSCODING_SERVICE = "media_transcoding"; field public static final String MUSIC_RECOGNITION_SERVICE = "music_recognition"; + field public static final String NEARBY_SERVICE = "nearby"; field public static final String NETD_SERVICE = "netd"; field public static final String NETWORK_SCORE_SERVICE = "network_score"; field public static final String OEM_LOCK_SERVICE = "oem_lock"; @@ -2953,6 +2948,7 @@ package android.hardware.hdmi { method public void sendKeyEvent(int, boolean); method public void sendVendorCommand(int, byte[], boolean); method public void setVendorCommandListener(@NonNull android.hardware.hdmi.HdmiControlManager.VendorCommandListener); + method public void setVendorCommandListener(@NonNull android.hardware.hdmi.HdmiControlManager.VendorCommandListener, int); } public final class HdmiControlManager { @@ -7020,7 +7016,10 @@ package android.metrics { package android.net { public class EthernetManager { + method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) public void connectNetwork(@NonNull String, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.BiConsumer<android.net.Network,android.net.EthernetNetworkManagementException>); + method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) public void disconnectNetwork(@NonNull String, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.BiConsumer<android.net.Network,android.net.EthernetNetworkManagementException>); method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public android.net.EthernetManager.TetheredInterfaceRequest requestTetheredInterface(@NonNull java.util.concurrent.Executor, @NonNull android.net.EthernetManager.TetheredInterfaceCallback); + method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) public void updateConfiguration(@NonNull String, @NonNull android.net.EthernetNetworkUpdateRequest, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.BiConsumer<android.net.Network,android.net.EthernetNetworkManagementException>); } public static interface EthernetManager.TetheredInterfaceCallback { @@ -7032,21 +7031,27 @@ package android.net { method public void release(); } - public final class IpSecManager { - method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void applyTunnelModeTransform(@NonNull android.net.IpSecManager.IpSecTunnelInterface, int, @NonNull android.net.IpSecTransform) throws java.io.IOException; - method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecManager.IpSecTunnelInterface createIpSecTunnelInterface(@NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull android.net.Network) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException; + public final class EthernetNetworkManagementException extends java.lang.RuntimeException implements android.os.Parcelable { + ctor public EthernetNetworkManagementException(@NonNull String); + method public int describeContents(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.EthernetNetworkManagementException> CREATOR; } - public static final class IpSecManager.IpSecTunnelInterface implements java.lang.AutoCloseable { - method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void addAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException; - method public void close(); - method @NonNull public String getInterfaceName(); - method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void removeAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException; - method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void setUnderlyingNetwork(@NonNull android.net.Network) throws java.io.IOException; + public final class EthernetNetworkUpdateRequest implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public android.net.IpConfiguration getIpConfiguration(); + method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.EthernetNetworkUpdateRequest> CREATOR; } - public static class IpSecTransform.Builder { - method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecTransform buildTunnelModeTransform(@NonNull java.net.InetAddress, @NonNull android.net.IpSecManager.SecurityParameterIndex) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException; + public static final class EthernetNetworkUpdateRequest.Builder { + ctor public EthernetNetworkUpdateRequest.Builder(); + ctor public EthernetNetworkUpdateRequest.Builder(@NonNull android.net.EthernetNetworkUpdateRequest); + method @NonNull public android.net.EthernetNetworkUpdateRequest build(); + method @NonNull public android.net.EthernetNetworkUpdateRequest.Builder setIpConfiguration(@NonNull android.net.IpConfiguration); + method @NonNull public android.net.EthernetNetworkUpdateRequest.Builder setNetworkCapabilities(@NonNull android.net.NetworkCapabilities); } public final class MatchAllNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable { @@ -7110,48 +7115,6 @@ package android.net { field public static final String PERMISSION_MAINLINE_NETWORK_STACK = "android.permission.MAINLINE_NETWORK_STACK"; } - public final class NetworkStats implements java.lang.Iterable<android.net.NetworkStats.Entry> android.os.Parcelable { - ctor public NetworkStats(long, int); - method @NonNull public android.net.NetworkStats add(@NonNull android.net.NetworkStats); - method @NonNull public android.net.NetworkStats addEntry(@NonNull android.net.NetworkStats.Entry); - method public int describeContents(); - method @NonNull public java.util.Iterator<android.net.NetworkStats.Entry> iterator(); - method @NonNull public android.net.NetworkStats subtract(@NonNull android.net.NetworkStats); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkStats> CREATOR; - field public static final int DEFAULT_NETWORK_ALL = -1; // 0xffffffff - field public static final int DEFAULT_NETWORK_NO = 0; // 0x0 - field public static final int DEFAULT_NETWORK_YES = 1; // 0x1 - field public static final String IFACE_VT = "vt_data0"; - field public static final int METERED_ALL = -1; // 0xffffffff - field public static final int METERED_NO = 0; // 0x0 - field public static final int METERED_YES = 1; // 0x1 - field public static final int ROAMING_ALL = -1; // 0xffffffff - field public static final int ROAMING_NO = 0; // 0x0 - field public static final int ROAMING_YES = 1; // 0x1 - field public static final int SET_ALL = -1; // 0xffffffff - field public static final int SET_DEFAULT = 0; // 0x0 - field public static final int SET_FOREGROUND = 1; // 0x1 - field public static final int TAG_NONE = 0; // 0x0 - field public static final int UID_ALL = -1; // 0xffffffff - field public static final int UID_TETHERING = -5; // 0xfffffffb - } - - public static class NetworkStats.Entry { - ctor public NetworkStats.Entry(@Nullable String, int, int, int, int, int, int, long, long, long, long, long); - method public int getDefaultNetwork(); - method public int getMetered(); - method public long getOperations(); - method public int getRoaming(); - method public long getRxBytes(); - method public long getRxPackets(); - method public int getSet(); - method public int getTag(); - method public long getTxBytes(); - method public long getTxPackets(); - method public int getUid(); - } - public class RssiCurve implements android.os.Parcelable { ctor public RssiCurve(int, int, byte[]); ctor public RssiCurve(int, int, byte[], int); @@ -7183,19 +7146,6 @@ package android.net { field public final android.net.RssiCurve rssiCurve; } - public class TrafficStats { - method public static void setThreadStatsTagApp(); - method public static void setThreadStatsTagBackup(); - method public static void setThreadStatsTagDownload(); - method public static void setThreadStatsTagRestore(); - field public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_END = -113; // 0xffffff8f - field public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_START = -128; // 0xffffff80 - field public static final int TAG_NETWORK_STACK_RANGE_END = -257; // 0xfffffeff - field public static final int TAG_NETWORK_STACK_RANGE_START = -768; // 0xfffffd00 - field public static final int TAG_SYSTEM_IMPERSONATION_RANGE_END = -241; // 0xffffff0f - field public static final int TAG_SYSTEM_IMPERSONATION_RANGE_START = -256; // 0xffffff00 - } - public abstract class Uri implements java.lang.Comparable<android.net.Uri> android.os.Parcelable { method @NonNull public String toSafeString(); } @@ -7376,23 +7326,6 @@ package android.net.metrics { } -package android.net.netstats.provider { - - public abstract class NetworkStatsProvider { - ctor public NetworkStatsProvider(); - method public void notifyAlertReached(); - method public void notifyLimitReached(); - method public void notifyStatsUpdated(int, @NonNull android.net.NetworkStats, @NonNull android.net.NetworkStats); - method public void notifyWarningReached(); - method public abstract void onRequestStatsUpdate(int); - method public abstract void onSetAlert(long); - method public abstract void onSetLimit(@NonNull String, long); - method public void onSetWarningAndLimit(@NonNull String, long, long); - field public static final int QUOTA_UNLIMITED = -1; // 0xffffffff - } - -} - package android.net.sip { @Deprecated public class SipAudioCall { @@ -7828,6 +7761,7 @@ package android.os { } public static class Build.VERSION { + field @NonNull public static final java.util.Set<java.lang.String> KNOWN_CODENAMES; field @NonNull public static final String PREVIEW_SDK_FINGERPRINT; } @@ -9000,6 +8934,7 @@ package android.provider { field public static final String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS"; field public static final String ACTION_TETHER_PROVISIONING_UI = "android.settings.TETHER_PROVISIONING_UI"; field public static final String ACTION_TETHER_SETTINGS = "android.settings.TETHER_SETTINGS"; + field public static final String ACTION_TETHER_UNSUPPORTED_CARRIER_UI = "android.settings.TETHER_UNSUPPORTED_CARRIER_UI"; } public static final class Settings.Global extends android.provider.Settings.NameValueTable { @@ -10125,8 +10060,6 @@ package android.service.tracing { public class TraceReportService extends android.app.Service { ctor public TraceReportService(); - method @Nullable public android.os.IBinder onBind(@NonNull android.content.Intent); - method public boolean onMessage(@NonNull android.os.Message); method public void onReportTrace(@NonNull android.service.tracing.TraceReportService.TraceParams); } @@ -11667,7 +11600,6 @@ package android.telephony { method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int); method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getAllowedNetworkTypes(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getAllowedNetworkTypesBitmask(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getAllowedNetworkTypesForReason(int); method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.ComponentName getAndUpdateDefaultRespondViaMessageApplication(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getCallForwarding(int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CallForwardingInfoCallback); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getCallWaitingStatus(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); @@ -11710,7 +11642,6 @@ package android.telephony { method public int getSimCardState(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getSimCardState(int); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.Locale getSimLocale(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getSupportedRadioAccessFamily(); method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.telephony.RadioAccessSpecifier> getSystemSelectionChannels(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.UiccSlotInfo[] getUiccSlotsInfo(); @@ -11761,7 +11692,6 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int sendThermalMitigationRequest(@NonNull android.telephony.ThermalMitigationRequest); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setAllowedNetworkTypes(long); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAllowedNetworkTypesForReason(int, long); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallForwarding(@NonNull android.telephony.CallForwardingInfo, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallWaitingEnabled(boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCarrierDataEnabled(boolean); @@ -11811,10 +11741,8 @@ package android.telephony { field public static final String ACTION_SIM_APPLICATION_STATE_CHANGED = "android.telephony.action.SIM_APPLICATION_STATE_CHANGED"; field public static final String ACTION_SIM_CARD_STATE_CHANGED = "android.telephony.action.SIM_CARD_STATE_CHANGED"; field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED"; - field public static final int ALLOWED_NETWORK_TYPES_REASON_CARRIER = 2; // 0x2 field public static final int ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G = 3; // 0x3 field public static final int ALLOWED_NETWORK_TYPES_REASON_POWER = 1; // 0x1 - field public static final int ALLOWED_NETWORK_TYPES_REASON_USER = 0; // 0x0 field public static final int CALL_WAITING_STATUS_DISABLED = 2; // 0x2 field public static final int CALL_WAITING_STATUS_ENABLED = 1; // 0x1 field public static final int CALL_WAITING_STATUS_NOT_SUPPORTED = 4; // 0x4 @@ -11853,26 +11781,6 @@ package android.telephony { field public static final int KEY_TYPE_WLAN = 2; // 0x2 field public static final int MOBILE_DATA_POLICY_DATA_ON_NON_DEFAULT_DURING_VOICE_CALL = 1; // 0x1 field public static final int MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED = 2; // 0x2 - field public static final long NETWORK_TYPE_BITMASK_1xRTT = 64L; // 0x40L - field public static final long NETWORK_TYPE_BITMASK_CDMA = 8L; // 0x8L - field public static final long NETWORK_TYPE_BITMASK_EDGE = 2L; // 0x2L - field public static final long NETWORK_TYPE_BITMASK_EHRPD = 8192L; // 0x2000L - field public static final long NETWORK_TYPE_BITMASK_EVDO_0 = 16L; // 0x10L - field public static final long NETWORK_TYPE_BITMASK_EVDO_A = 32L; // 0x20L - field public static final long NETWORK_TYPE_BITMASK_EVDO_B = 2048L; // 0x800L - field public static final long NETWORK_TYPE_BITMASK_GPRS = 1L; // 0x1L - field public static final long NETWORK_TYPE_BITMASK_GSM = 32768L; // 0x8000L - field public static final long NETWORK_TYPE_BITMASK_HSDPA = 128L; // 0x80L - field public static final long NETWORK_TYPE_BITMASK_HSPA = 512L; // 0x200L - field public static final long NETWORK_TYPE_BITMASK_HSPAP = 16384L; // 0x4000L - field public static final long NETWORK_TYPE_BITMASK_HSUPA = 256L; // 0x100L - field public static final long NETWORK_TYPE_BITMASK_IWLAN = 131072L; // 0x20000L - field public static final long NETWORK_TYPE_BITMASK_LTE = 4096L; // 0x1000L - field public static final long NETWORK_TYPE_BITMASK_LTE_CA = 262144L; // 0x40000L - field public static final long NETWORK_TYPE_BITMASK_NR = 524288L; // 0x80000L - field public static final long NETWORK_TYPE_BITMASK_TD_SCDMA = 65536L; // 0x10000L - field public static final long NETWORK_TYPE_BITMASK_UMTS = 4L; // 0x4L - field public static final long NETWORK_TYPE_BITMASK_UNKNOWN = 0L; // 0x0L field public static final int NR_DUAL_CONNECTIVITY_DISABLE = 2; // 0x2 field public static final int NR_DUAL_CONNECTIVITY_DISABLE_IMMEDIATE = 3; // 0x3 field public static final int NR_DUAL_CONNECTIVITY_ENABLE = 1; // 0x1 @@ -12898,13 +12806,21 @@ package android.telephony.ims { public class ImsService extends android.app.Service { ctor public ImsService(); - method public android.telephony.ims.feature.MmTelFeature createMmTelFeature(int); - method public android.telephony.ims.feature.RcsFeature createRcsFeature(int); - method public void disableIms(int); - method public void enableIms(int); - method public android.telephony.ims.stub.ImsConfigImplBase getConfig(int); + method @Nullable public android.telephony.ims.feature.MmTelFeature createEmergencyOnlyMmTelFeature(int); + method @Deprecated public android.telephony.ims.feature.MmTelFeature createMmTelFeature(int); + method @Nullable public android.telephony.ims.feature.MmTelFeature createMmTelFeatureForSubscription(int, int); + method @Deprecated public android.telephony.ims.feature.RcsFeature createRcsFeature(int); + method @Nullable public android.telephony.ims.feature.RcsFeature createRcsFeatureForSubscription(int, int); + method @Deprecated public void disableIms(int); + method public void disableImsForSubscription(int, int); + method @Deprecated public void enableIms(int); + method public void enableImsForSubscription(int, int); + method @Deprecated public android.telephony.ims.stub.ImsConfigImplBase getConfig(int); + method @NonNull public android.telephony.ims.stub.ImsConfigImplBase getConfigForSubscription(int, int); + method @NonNull public java.util.concurrent.Executor getExecutor(); method public long getImsServiceCapabilities(); - method public android.telephony.ims.stub.ImsRegistrationImplBase getRegistration(int); + method @Deprecated public android.telephony.ims.stub.ImsRegistrationImplBase getRegistration(int); + method @NonNull public android.telephony.ims.stub.ImsRegistrationImplBase getRegistrationForSubscription(int, int); method @Nullable public android.telephony.ims.stub.SipTransportImplBase getSipTransport(int); method public final void onUpdateSupportedImsFeatures(android.telephony.ims.stub.ImsFeatureConfiguration) throws android.os.RemoteException; method public android.telephony.ims.stub.ImsFeatureConfiguration querySupportedImsFeatures(); @@ -13128,18 +13044,16 @@ package android.telephony.ims { public class ProvisioningManager { method @NonNull public static android.telephony.ims.ProvisioningManager createForSubscriptionId(int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public int getProvisioningIntValue(int); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean getProvisioningStatusForCapability(int, int); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public String getProvisioningStringValue(int); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean getRcsProvisioningStatusForCapability(int); + method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean getRcsProvisioningStatusForCapability(int); method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public boolean isRcsVolteSingleRegistrationCapable() throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyRcsAutoConfigurationReceived(@NonNull byte[], boolean); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerProvisioningChangedCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.Callback) throws android.telephony.ims.ImsException; method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public void registerRcsProvisioningCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.RcsProvisioningCallback) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningIntValue(int, int); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setProvisioningStatusForCapability(int, int, boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningStringValue(int, @NonNull String); method @RequiresPermission(android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void setRcsClientConfiguration(@NonNull android.telephony.ims.RcsClientConfiguration) throws android.telephony.ims.ImsException; - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setRcsProvisioningStatusForCapability(int, boolean); + method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setRcsProvisioningStatusForCapability(int, boolean); method @RequiresPermission(android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void triggerRcsReconfiguration(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback); method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public void unregisterRcsProvisioningCallback(@NonNull android.telephony.ims.ProvisioningManager.RcsProvisioningCallback); @@ -13186,6 +13100,7 @@ package android.telephony.ims { field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RcsClientConfiguration> CREATOR; field public static final String RCS_PROFILE_1_0 = "UP_1.0"; field public static final String RCS_PROFILE_2_3 = "UP_2.3"; + field public static final String RCS_PROFILE_2_4 = "UP_2.4"; } public final class RcsContactPresenceTuple implements android.os.Parcelable { @@ -13253,6 +13168,7 @@ package android.telephony.ims { method @Nullable public android.telephony.ims.RcsContactPresenceTuple getCapabilityTuple(@NonNull String); method @NonNull public java.util.List<android.telephony.ims.RcsContactPresenceTuple> getCapabilityTuples(); method @NonNull public android.net.Uri getContactUri(); + method @Nullable public android.net.Uri getEntityUri(); method @NonNull public java.util.Set<java.lang.String> getFeatureTags(); method public int getRequestResult(); method public int getSourceType(); @@ -13281,6 +13197,7 @@ package android.telephony.ims { method @NonNull public android.telephony.ims.RcsContactUceCapability.PresenceBuilder addCapabilityTuple(@NonNull android.telephony.ims.RcsContactPresenceTuple); method @NonNull public android.telephony.ims.RcsContactUceCapability.PresenceBuilder addCapabilityTuples(@NonNull java.util.List<android.telephony.ims.RcsContactPresenceTuple>); method @NonNull public android.telephony.ims.RcsContactUceCapability build(); + method @NonNull public android.telephony.ims.RcsContactUceCapability.PresenceBuilder setEntityUri(@NonNull android.net.Uri); } public class RcsUceAdapter { @@ -13522,6 +13439,7 @@ package android.telephony.ims.feature { public class MmTelFeature extends android.telephony.ims.feature.ImsFeature { ctor public MmTelFeature(); + ctor public MmTelFeature(@NonNull java.util.concurrent.Executor); method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy); method public void changeOfferedRtpHeaderExtensionTypes(@NonNull java.util.Set<android.telephony.ims.RtpHeaderExtensionType>); method @Nullable public android.telephony.ims.ImsCallProfile createCallProfile(int, int); @@ -13555,7 +13473,7 @@ package android.telephony.ims.feature { } public class RcsFeature extends android.telephony.ims.feature.ImsFeature { - ctor @Deprecated public RcsFeature(); + ctor public RcsFeature(); ctor public RcsFeature(@NonNull java.util.concurrent.Executor); method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy); method @NonNull public android.telephony.ims.stub.RcsCapabilityExchangeImplBase createCapabilityExchangeImpl(@NonNull android.telephony.ims.stub.CapabilityExchangeEventListener); @@ -13572,9 +13490,6 @@ package android.telephony.ims.feature { method public void addCapabilities(int); method public boolean isCapable(int); method public void removeCapabilities(int); - field public static final int CAPABILITY_TYPE_NONE = 0; // 0x0 - field public static final int CAPABILITY_TYPE_OPTIONS_UCE = 1; // 0x1 - field public static final int CAPABILITY_TYPE_PRESENCE_UCE = 2; // 0x2 } } @@ -13660,6 +13575,7 @@ package android.telephony.ims.stub { } public class ImsConfigImplBase { + ctor public ImsConfigImplBase(@NonNull java.util.concurrent.Executor); ctor public ImsConfigImplBase(); method public int getConfigInt(int); method public String getConfigString(int); @@ -13712,6 +13628,7 @@ package android.telephony.ims.stub { public class ImsRegistrationImplBase { ctor public ImsRegistrationImplBase(); + ctor public ImsRegistrationImplBase(@NonNull java.util.concurrent.Executor); method public final void onDeregistered(android.telephony.ims.ImsReasonInfo); method public final void onRegistered(int); method public final void onRegistered(@NonNull android.telephony.ims.ImsRegistrationAttributes); @@ -13722,11 +13639,6 @@ package android.telephony.ims.stub { method public void triggerFullNetworkRegistration(@IntRange(from=100, to=699) int, @Nullable String); method public void triggerSipDelegateDeregistration(); method public void updateSipDelegateRegistration(); - field public static final int REGISTRATION_TECH_CROSS_SIM = 2; // 0x2 - field public static final int REGISTRATION_TECH_IWLAN = 1; // 0x1 - field public static final int REGISTRATION_TECH_LTE = 0; // 0x0 - field public static final int REGISTRATION_TECH_NONE = -1; // 0xffffffff - field public static final int REGISTRATION_TECH_NR = 3; // 0x3 } public class ImsSmsImplBase { @@ -13824,6 +13736,7 @@ package android.telephony.ims.stub { } public class SipTransportImplBase { + ctor public SipTransportImplBase(); ctor public SipTransportImplBase(@NonNull java.util.concurrent.Executor); method public void createSipDelegate(int, @NonNull android.telephony.ims.DelegateRequest, @NonNull android.telephony.ims.DelegateStateCallback, @NonNull android.telephony.ims.DelegateMessageCallback); method public void destroySipDelegate(@NonNull android.telephony.ims.stub.SipDelegate, int); diff --git a/core/api/system-lint-baseline.txt b/core/api/system-lint-baseline.txt index b435acfccde8..97eda7aee535 100644 --- a/core/api/system-lint-baseline.txt +++ b/core/api/system-lint-baseline.txt @@ -1,12 +1,6 @@ // Baseline format: 1.0 ArrayReturn: android.view.contentcapture.ViewNode#getAutofillOptions(): - - -BuilderSetStyle: android.net.IpSecTransform.Builder#buildTunnelModeTransform(java.net.InetAddress, android.net.IpSecManager.SecurityParameterIndex): - Builder methods names should use setFoo() / addFoo() / clearFoo() style: method android.net.IpSecTransform.Builder.buildTunnelModeTransform(java.net.InetAddress,android.net.IpSecManager.SecurityParameterIndex) - - ExecutorRegistration: android.media.MediaPlayer#setOnRtpRxNoticeListener(android.content.Context, android.media.MediaPlayer.OnRtpRxNoticeListener, android.os.Handler): Registration methods should have overload that accepts delivery Executor: `setOnRtpRxNoticeListener` @@ -15,8 +9,6 @@ GenericException: android.app.prediction.AppPredictor#finalize(): GenericException: android.hardware.location.ContextHubClient#finalize(): -GenericException: android.net.IpSecManager.IpSecTunnelInterface#finalize(): - GenericException: android.service.autofill.augmented.FillWindow#finalize(): diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 18ceb2598766..73caa5d5f0d4 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -635,10 +635,6 @@ package android.app.prediction { package android.app.usage { - public class NetworkStatsManager { - method public void setPollForce(boolean); - } - public class StorageStatsManager { method public boolean isQuotaSupported(@NonNull java.util.UUID); method public boolean isReservedSupported(@NonNull java.util.UUID); @@ -1573,14 +1569,6 @@ package android.media.tv.tuner { package android.net { - public class EthernetManager { - method public void setIncludeTestInterfaces(boolean); - } - - public final class IpSecManager { - field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0 - } - public class NetworkPolicyManager { method public boolean getRestrictBackground(); method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidNetworkingBlocked(int, boolean); @@ -1597,13 +1585,6 @@ package android.net { method @Nullable public byte[] getWatchlistConfigHash(); } - public class TrafficStats { - method public static long getLoopbackRxBytes(); - method public static long getLoopbackRxPackets(); - method public static long getLoopbackTxBytes(); - method public static long getLoopbackTxPackets(); - } - } package android.os { @@ -1707,8 +1688,11 @@ package android.os { public final class Parcel { method public boolean allowSquashing(); + method public int getFlags(); method public int readExceptionCode(); method public void restoreAllowSquashing(boolean); + field public static final int FLAG_IS_REPLY_FROM_BLOCKING_ALLOWED_OBJECT = 1; // 0x1 + field public static final int FLAG_PROPAGATE_ALLOW_BLOCKING = 2; // 0x2 } public class ParcelFileDescriptor implements java.io.Closeable android.os.Parcelable { @@ -2193,8 +2177,8 @@ package android.security { } public class KeyStoreException extends java.lang.Exception { - ctor public KeyStoreException(int, String); method public int getErrorCode(); + method public static boolean hasFailureInfoForError(int); } } @@ -2497,7 +2481,6 @@ package android.telephony { method @NonNull public java.util.List<android.telephony.data.ApnSetting> getDevicePolicyOverrideApns(@NonNull android.content.Context); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getLine1AlphaTag(); method public android.util.Pair<java.lang.Integer,java.lang.Integer> getRadioHalVersion(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getSupportedRadioAccessFamily(); method public boolean modifyDevicePolicyOverrideApn(@NonNull android.content.Context, int, @NonNull android.telephony.data.ApnSetting); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile(); method @Deprecated public void setCarrierTestOverride(String, String, String, String, String, String, String); diff --git a/core/java/Android.bp b/core/java/Android.bp index 72a432eedaaa..27f3fc53101c 100644 --- a/core/java/Android.bp +++ b/core/java/Android.bp @@ -149,7 +149,6 @@ java_library { filegroup { name: "framework-services-net-module-wifi-shared-srcs", srcs: [ - "android/net/DhcpResults.java", "android/util/LocalLog.java", ], } @@ -165,6 +164,18 @@ filegroup { "com/android/internal/util/IndentingPrintWriter.java", "com/android/internal/util/MessageUtils.java", "com/android/internal/util/WakeupMessage.java", + // TODO: delete as soon as NetworkStatsFactory stops using + "com/android/internal/util/ProcFileReader.java", + ], +} + +// keep these files in sync with the packages/modules/Connectivity jarjar-rules.txt for +// the connectivity module. +filegroup { + name: "framework-connectivity-api-shared-srcs", + srcs: [ + "android/util/IndentingPrintWriter.java", + "com/android/internal/util/FileRotator.java", ], } diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index f9739a489453..6a0a2892cb96 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -44,7 +44,6 @@ import android.app.timezonedetector.TimeZoneDetectorImpl; import android.app.trust.TrustManager; import android.app.usage.IStorageStatsManager; import android.app.usage.IUsageStatsManager; -import android.app.usage.NetworkStatsManager; import android.app.usage.StorageStatsManager; import android.app.usage.UsageStatsManager; import android.apphibernation.AppHibernationManager; @@ -128,12 +127,9 @@ import android.net.ConnectivityFrameworkInitializer; import android.net.ConnectivityFrameworkInitializerTiramisu; import android.net.EthernetManager; import android.net.IEthernetManager; -import android.net.IIpSecService; import android.net.INetworkPolicyManager; -import android.net.INetworkStatsService; import android.net.IPacProxyManager; import android.net.IVpnManager; -import android.net.IpSecManager; import android.net.NetworkPolicyManager; import android.net.NetworkScoreManager; import android.net.NetworkWatchlistManager; @@ -420,15 +416,6 @@ public final class SystemServiceRegistry { return new VcnManager(ctx, service); }}); - registerService(Context.IPSEC_SERVICE, IpSecManager.class, - new CachedServiceFetcher<IpSecManager>() { - @Override - public IpSecManager createService(ContextImpl ctx) throws ServiceNotFoundException { - IBinder b = ServiceManager.getService(Context.IPSEC_SERVICE); - IIpSecService service = IIpSecService.Stub.asInterface(b); - return new IpSecManager(ctx, service); - }}); - registerService(Context.COUNTRY_DETECTOR, CountryDetector.class, new StaticServiceFetcher<CountryDetector>() { @Override @@ -978,17 +965,6 @@ public final class SystemServiceRegistry { return new UsageStatsManager(ctx.getOuterContext(), service); }}); - registerService(Context.NETWORK_STATS_SERVICE, NetworkStatsManager.class, - new CachedServiceFetcher<NetworkStatsManager>() { - @Override - public NetworkStatsManager createService(ContextImpl ctx) throws ServiceNotFoundException { - // TODO: Replace with an initializer in the module, see - // {@code ConnectivityFrameworkInitializer}. - final INetworkStatsService service = INetworkStatsService.Stub.asInterface( - ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE)); - return new NetworkStatsManager(ctx.getOuterContext(), service); - }}); - registerService(Context.PERSISTENT_DATA_BLOCK_SERVICE, PersistentDataBlockManager.class, new StaticServiceFetcher<PersistentDataBlockManager>() { @Override diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index 6cfa39cd2337..ab645960ee2c 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -1452,18 +1452,27 @@ public class WallpaperManager { mContext.getUserId()); if (fd != null) { FileOutputStream fos = null; - boolean ok = false; + final Bitmap tmp = BitmapFactory.decodeStream(resources.openRawResource(resid)); try { - fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd); - copyStreamToWallpaperFile(resources.openRawResource(resid), fos); - // The 'close()' is the trigger for any server-side image manipulation, - // so we must do that before waiting for completion. - fos.close(); - completion.waitForCompletion(); + // If the stream can't be decoded, treat it as an invalid input. + if (tmp != null) { + fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd); + tmp.compress(Bitmap.CompressFormat.PNG, 100, fos); + // The 'close()' is the trigger for any server-side image manipulation, + // so we must do that before waiting for completion. + fos.close(); + completion.waitForCompletion(); + } else { + throw new IllegalArgumentException( + "Resource 0x" + Integer.toHexString(resid) + " is invalid"); + } } finally { // Might be redundant but completion shouldn't wait unless the write // succeeded; this is a fallback if it threw past the close+wait. IoUtils.closeQuietly(fos); + if (tmp != null) { + tmp.recycle(); + } } } } catch (RemoteException e) { @@ -1705,13 +1714,22 @@ public class WallpaperManager { result, which, completion, mContext.getUserId()); if (fd != null) { FileOutputStream fos = null; + final Bitmap tmp = BitmapFactory.decodeStream(bitmapData); try { - fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd); - copyStreamToWallpaperFile(bitmapData, fos); - fos.close(); - completion.waitForCompletion(); + // If the stream can't be decoded, treat it as an invalid input. + if (tmp != null) { + fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd); + tmp.compress(Bitmap.CompressFormat.PNG, 100, fos); + fos.close(); + completion.waitForCompletion(); + } else { + throw new IllegalArgumentException("InputStream is invalid"); + } } finally { IoUtils.closeQuietly(fos); + if (tmp != null) { + tmp.recycle(); + } } } } catch (RemoteException e) { diff --git a/core/java/android/app/assist/OWNERS b/core/java/android/app/assist/OWNERS index 46b5ea03c545..e857c72bb28e 100644 --- a/core/java/android/app/assist/OWNERS +++ b/core/java/android/app/assist/OWNERS @@ -1,7 +1,5 @@ +augale@google.com joannechung@google.com -adamhe@google.com -tymtsai@google.com +markpun@google.com lpeter@google.com -augale@google.com -svetoslavganov@android.com -svetoslavganov@google.com +tymtsai@google.com diff --git a/core/java/android/app/contentsuggestions/OWNERS b/core/java/android/app/contentsuggestions/OWNERS index 482abb2d94e9..cf54c2a6fcbc 100644 --- a/core/java/android/app/contentsuggestions/OWNERS +++ b/core/java/android/app/contentsuggestions/OWNERS @@ -1,9 +1,7 @@ # Bug component: 643919 +augale@google.com joannechung@google.com -adamhe@google.com -tymtsai@google.com +markpun@google.com lpeter@google.com -augale@google.com -svetoslavganov@android.com -svetoslavganov@google.com +tymtsai@google.com diff --git a/core/java/android/app/time/ExternalTimeSuggestion.java b/core/java/android/app/time/ExternalTimeSuggestion.java index 8e281c07c45d..a7c0e5c79607 100644 --- a/core/java/android/app/time/ExternalTimeSuggestion.java +++ b/core/java/android/app/time/ExternalTimeSuggestion.java @@ -50,16 +50,17 @@ import java.util.Objects; * <p>The creator of an external suggestion is expected to be separate Android process, e.g. a * process integrating with the external time source via a HAL or local network. The creator must * capture the elapsed realtime reference clock, e.g. via {@link SystemClock#elapsedRealtime()}, - * when the UTC time is first obtained (usually under a wakelock). This enables Android to adjust - * for latency introduced between suggestion creation and eventual use. Adjustments for other + * when the Unix epoch time is first obtained (usually under a wakelock). This enables Android to + * adjust for latency introduced between suggestion creation and eventual use. Adjustments for other * sources of latency, i.e. those before the external time suggestion is created, must be handled by * the creator. * * <p>{@code elapsedRealtimeMillis} and {@code suggestionMillis} represent the suggested time. - * {@code suggestionMillis} is the number of milliseconds elapsed since 1/1/1970 00:00:00 UTC. - * {@code elapsedRealtimeMillis} is the value of the elapsed realtime clock when {@code - * suggestionMillis} was established. Note that the elapsed realtime clock is considered accurate - * but it is volatile, so time suggestions cannot be persisted across device resets. + * {@code suggestionMillis} is the number of milliseconds elapsed since 1/1/1970 00:00:00 UTC + * according to the Unix time scale. {@code elapsedRealtimeMillis} is the value of the elapsed + * realtime clock when {@code suggestionMillis} was established. Note that the elapsed realtime + * clock is considered accurate but it is volatile, so time suggestions cannot be persisted across + * device resets. * * <p>{@code debugInfo} contains debugging metadata associated with the suggestion. This is used to * record why the suggestion exists and how it was entered. This information exists only to aid in @@ -83,7 +84,7 @@ public final class ExternalTimeSuggestion implements Parcelable { }; @NonNull - private final TimestampedValue<Long> mUtcTime; + private final TimestampedValue<Long> mUnixEpochTime; @Nullable private ArrayList<String> mDebugInfo; @@ -92,12 +93,12 @@ public final class ExternalTimeSuggestion implements Parcelable { * ExternalTimeSuggestion} for more details. * * @param elapsedRealtimeMillis the elapsed realtime clock reference for the suggestion - * @param suggestionMillis the suggested UTC time in milliseconds since the start of the + * @param suggestionMillis the suggested time in milliseconds since the start of the * Unix epoch */ public ExternalTimeSuggestion(@ElapsedRealtimeLong long elapsedRealtimeMillis, @CurrentTimeMillisLong long suggestionMillis) { - mUtcTime = new TimestampedValue(elapsedRealtimeMillis, suggestionMillis); + mUnixEpochTime = new TimestampedValue(elapsedRealtimeMillis, suggestionMillis); } private static ExternalTimeSuggestion createFromParcel(Parcel in) { @@ -117,7 +118,7 @@ public final class ExternalTimeSuggestion implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeParcelable(mUtcTime, 0); + dest.writeParcelable(mUnixEpochTime, 0); dest.writeList(mDebugInfo); } @@ -125,8 +126,8 @@ public final class ExternalTimeSuggestion implements Parcelable { * {@hide} */ @NonNull - public TimestampedValue<Long> getUtcTime() { - return mUtcTime; + public TimestampedValue<Long> getUnixEpochTime() { + return mUnixEpochTime; } /** @@ -160,17 +161,18 @@ public final class ExternalTimeSuggestion implements Parcelable { return false; } ExternalTimeSuggestion that = (ExternalTimeSuggestion) o; - return Objects.equals(mUtcTime, that.mUtcTime); + return Objects.equals(mUnixEpochTime, that.mUnixEpochTime); } @Override public int hashCode() { - return Objects.hash(mUtcTime); + return Objects.hash(mUnixEpochTime); } @Override public String toString() { - return "ExternalTimeSuggestion{" + "mUtcTime=" + mUtcTime + ", mDebugInfo=" + mDebugInfo + return "ExternalTimeSuggestion{" + "mUnixEpochTime=" + mUnixEpochTime + + ", mDebugInfo=" + mDebugInfo + '}'; } } diff --git a/core/java/android/app/timedetector/GnssTimeSuggestion.java b/core/java/android/app/timedetector/GnssTimeSuggestion.java index 6478a2dd2aa9..34f4565fb410 100644 --- a/core/java/android/app/timedetector/GnssTimeSuggestion.java +++ b/core/java/android/app/timedetector/GnssTimeSuggestion.java @@ -31,11 +31,11 @@ import java.util.Objects; /** * A time signal from a GNSS source. * - * <p>{@code utcTime} is the suggested time. The {@code utcTime.value} is the number of milliseconds - * elapsed since 1/1/1970 00:00:00 UTC. The {@code utcTime.referenceTimeMillis} is the value of the - * elapsed realtime clock when the {@code utcTime.value} was established. - * Note that the elapsed realtime clock is considered accurate but it is volatile, so time - * suggestions cannot be persisted across device resets. + * <p>{@code unixEpochTime} is the suggested time. The {@code unixEpochTime.value} is the number of + * milliseconds elapsed since 1/1/1970 00:00:00 UTC according to the Unix time system. The {@code + * unixEpochTime.referenceTimeMillis} is the value of the elapsed realtime clock when the {@code + * unixEpochTime.value} was established. Note that the elapsed realtime clock is considered accurate + * but it is volatile, so time suggestions cannot be persisted across device resets. * * <p>{@code debugInfo} contains debugging metadata associated with the suggestion. This is used to * record why the suggestion exists and how it was entered. This information exists only to aid in @@ -57,17 +57,17 @@ public final class GnssTimeSuggestion implements Parcelable { } }; - @NonNull private final TimestampedValue<Long> mUtcTime; + @NonNull private final TimestampedValue<Long> mUnixEpochTime; @Nullable private ArrayList<String> mDebugInfo; - public GnssTimeSuggestion(@NonNull TimestampedValue<Long> utcTime) { - mUtcTime = Objects.requireNonNull(utcTime); - Objects.requireNonNull(utcTime.getValue()); + public GnssTimeSuggestion(@NonNull TimestampedValue<Long> unixEpochTime) { + mUnixEpochTime = Objects.requireNonNull(unixEpochTime); + Objects.requireNonNull(unixEpochTime.getValue()); } private static GnssTimeSuggestion createFromParcel(Parcel in) { - TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */); - GnssTimeSuggestion suggestion = new GnssTimeSuggestion(utcTime); + TimestampedValue<Long> unixEpochTime = in.readParcelable(null /* classLoader */); + GnssTimeSuggestion suggestion = new GnssTimeSuggestion(unixEpochTime); @SuppressWarnings("unchecked") ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */); suggestion.mDebugInfo = debugInfo; @@ -81,13 +81,13 @@ public final class GnssTimeSuggestion implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeParcelable(mUtcTime, 0); + dest.writeParcelable(mUnixEpochTime, 0); dest.writeList(mDebugInfo); } @NonNull - public TimestampedValue<Long> getUtcTime() { - return mUtcTime; + public TimestampedValue<Long> getUnixEpochTime() { + return mUnixEpochTime; } @NonNull @@ -117,18 +117,18 @@ public final class GnssTimeSuggestion implements Parcelable { return false; } GnssTimeSuggestion that = (GnssTimeSuggestion) o; - return Objects.equals(mUtcTime, that.mUtcTime); + return Objects.equals(mUnixEpochTime, that.mUnixEpochTime); } @Override public int hashCode() { - return Objects.hash(mUtcTime); + return Objects.hash(mUnixEpochTime); } @Override public String toString() { return "GnssTimeSuggestion{" - + "mUtcTime=" + mUtcTime + + "mUnixEpochTime=" + mUnixEpochTime + ", mDebugInfo=" + mDebugInfo + '}'; } diff --git a/core/java/android/app/timedetector/ManualTimeSuggestion.java b/core/java/android/app/timedetector/ManualTimeSuggestion.java index 299e9518e329..76db33b1c32b 100644 --- a/core/java/android/app/timedetector/ManualTimeSuggestion.java +++ b/core/java/android/app/timedetector/ManualTimeSuggestion.java @@ -31,9 +31,9 @@ import java.util.Objects; /** * A time signal from a manual (user provided) source. * - * <p>{@code utcTime} is the suggested time. The {@code utcTime.value} is the number of milliseconds - * elapsed since 1/1/1970 00:00:00 UTC. The {@code utcTime.referenceTimeMillis} is the value of the - * elapsed realtime clock when the {@code utcTime.value} was established. + * <p>{@code unixEpochTime} is the suggested time. The {@code unixEpochTime.value} is the number of + * milliseconds elapsed since 1/1/1970 00:00:00 UTC. The {@code unixEpochTime.referenceTimeMillis} + * is the value of the elapsed realtime clock when the {@code unixEpochTime.value} was established. * Note that the elapsed realtime clock is considered accurate but it is volatile, so time * suggestions cannot be persisted across device resets. * @@ -57,17 +57,17 @@ public final class ManualTimeSuggestion implements Parcelable { } }; - @NonNull private final TimestampedValue<Long> mUtcTime; + @NonNull private final TimestampedValue<Long> mUnixEpochTime; @Nullable private ArrayList<String> mDebugInfo; - public ManualTimeSuggestion(@NonNull TimestampedValue<Long> utcTime) { - mUtcTime = Objects.requireNonNull(utcTime); - Objects.requireNonNull(utcTime.getValue()); + public ManualTimeSuggestion(@NonNull TimestampedValue<Long> unixEpochTime) { + mUnixEpochTime = Objects.requireNonNull(unixEpochTime); + Objects.requireNonNull(unixEpochTime.getValue()); } private static ManualTimeSuggestion createFromParcel(Parcel in) { - TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */); - ManualTimeSuggestion suggestion = new ManualTimeSuggestion(utcTime); + TimestampedValue<Long> unixEpochTime = in.readParcelable(null /* classLoader */); + ManualTimeSuggestion suggestion = new ManualTimeSuggestion(unixEpochTime); @SuppressWarnings("unchecked") ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */); suggestion.mDebugInfo = debugInfo; @@ -81,13 +81,13 @@ public final class ManualTimeSuggestion implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeParcelable(mUtcTime, 0); + dest.writeParcelable(mUnixEpochTime, 0); dest.writeList(mDebugInfo); } @NonNull - public TimestampedValue<Long> getUtcTime() { - return mUtcTime; + public TimestampedValue<Long> getUnixEpochTime() { + return mUnixEpochTime; } @NonNull @@ -117,18 +117,18 @@ public final class ManualTimeSuggestion implements Parcelable { return false; } ManualTimeSuggestion that = (ManualTimeSuggestion) o; - return Objects.equals(mUtcTime, that.mUtcTime); + return Objects.equals(mUnixEpochTime, that.mUnixEpochTime); } @Override public int hashCode() { - return Objects.hash(mUtcTime); + return Objects.hash(mUnixEpochTime); } @Override public String toString() { return "ManualTimeSuggestion{" - + "mUtcTime=" + mUtcTime + + "mUnixEpochTime=" + mUnixEpochTime + ", mDebugInfo=" + mDebugInfo + '}'; } diff --git a/core/java/android/app/timedetector/NetworkTimeSuggestion.java b/core/java/android/app/timedetector/NetworkTimeSuggestion.java index a5259c27ec42..e22f1d6ea8be 100644 --- a/core/java/android/app/timedetector/NetworkTimeSuggestion.java +++ b/core/java/android/app/timedetector/NetworkTimeSuggestion.java @@ -31,11 +31,12 @@ import java.util.Objects; /** * A time signal from a network time source like NTP. * - * <p>{@code utcTime} contains the suggested time. The {@code utcTime.value} is the number of - * milliseconds elapsed since 1/1/1970 00:00:00 UTC. The {@code utcTime.referenceTimeMillis} is the - * value of the elapsed realtime clock when the {@code utcTime.value} was established. - * Note that the elapsed realtime clock is considered accurate but it is volatile, so time - * suggestions cannot be persisted across device resets. + * <p>{@code unixEpochTime} contains the suggested time. The {@code unixEpochTime.value} is the + * number of milliseconds elapsed since 1/1/1970 00:00:00 UTC according to the Unix time system. + * The {@code unixEpochTime.referenceTimeMillis} is the value of the elapsed realtime clock when + * the {@code unixEpochTime.value} was established. Note that the elapsed realtime clock is + * considered accurate but it is volatile, so time suggestions cannot be persisted across device + * resets. * * <p>{@code debugInfo} contains debugging metadata associated with the suggestion. This is used to * record why the suggestion exists and how it was determined. This information exists only to aid @@ -57,17 +58,17 @@ public final class NetworkTimeSuggestion implements Parcelable { } }; - @NonNull private final TimestampedValue<Long> mUtcTime; + @NonNull private final TimestampedValue<Long> mUnixEpochTime; @Nullable private ArrayList<String> mDebugInfo; - public NetworkTimeSuggestion(@NonNull TimestampedValue<Long> utcTime) { - mUtcTime = Objects.requireNonNull(utcTime); - Objects.requireNonNull(utcTime.getValue()); + public NetworkTimeSuggestion(@NonNull TimestampedValue<Long> unixEpochTime) { + mUnixEpochTime = Objects.requireNonNull(unixEpochTime); + Objects.requireNonNull(unixEpochTime.getValue()); } private static NetworkTimeSuggestion createFromParcel(Parcel in) { - TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */); - NetworkTimeSuggestion suggestion = new NetworkTimeSuggestion(utcTime); + TimestampedValue<Long> unixEpochTime = in.readParcelable(null /* classLoader */); + NetworkTimeSuggestion suggestion = new NetworkTimeSuggestion(unixEpochTime); @SuppressWarnings("unchecked") ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */); suggestion.mDebugInfo = debugInfo; @@ -81,13 +82,13 @@ public final class NetworkTimeSuggestion implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeParcelable(mUtcTime, 0); + dest.writeParcelable(mUnixEpochTime, 0); dest.writeList(mDebugInfo); } @NonNull - public TimestampedValue<Long> getUtcTime() { - return mUtcTime; + public TimestampedValue<Long> getUnixEpochTime() { + return mUnixEpochTime; } @NonNull @@ -117,18 +118,18 @@ public final class NetworkTimeSuggestion implements Parcelable { return false; } NetworkTimeSuggestion that = (NetworkTimeSuggestion) o; - return Objects.equals(mUtcTime, that.mUtcTime); + return Objects.equals(mUnixEpochTime, that.mUnixEpochTime); } @Override public int hashCode() { - return Objects.hash(mUtcTime); + return Objects.hash(mUnixEpochTime); } @Override public String toString() { return "NetworkTimeSuggestion{" - + "mUtcTime=" + mUtcTime + + "mUnixEpochTime=" + mUnixEpochTime + ", mDebugInfo=" + mDebugInfo + '}'; } diff --git a/core/java/android/app/timedetector/TelephonyTimeSuggestion.java b/core/java/android/app/timedetector/TelephonyTimeSuggestion.java index 6c3a304ed3a7..4ff75174ab57 100644 --- a/core/java/android/app/timedetector/TelephonyTimeSuggestion.java +++ b/core/java/android/app/timedetector/TelephonyTimeSuggestion.java @@ -34,12 +34,12 @@ import java.util.Objects; * <p>{@code slotIndex} identifies the suggestion source. This enables detection logic to identify * suggestions from the same source when there are several in use. * - * <p>{@code utcTime}. When not {@code null}, the {@code utcTime.value} is the number of - * milliseconds elapsed since 1/1/1970 00:00:00 UTC. The {@code utcTime.referenceTimeMillis} is the - * value of the elapsed realtime clock when the {@code utcTime.value} was established. + * <p>{@code unixEpochTime}. When not {@code null}, the {@code unixEpochTime.value} is the number of + * milliseconds elapsed since 1/1/1970 00:00:00 UTC. The {@code unixEpochTime.referenceTimeMillis} + * is the value of the elapsed realtime clock when the {@code unixEpochTime.value} was established. * Note that the elapsed realtime clock is considered accurate but it is volatile, so time - * suggestions cannot be persisted across device resets. {@code utcTime} can be {@code null} to - * indicate that the telephony source has entered an "un-opinionated" state and any previous + * suggestions cannot be persisted across device resets. {@code unixEpochTime} can be {@code null} + * to indicate that the telephony source has entered an "un-opinionated" state and any previous * suggestion from the source is being withdrawn. * * <p>{@code debugInfo} contains debugging metadata associated with the suggestion. This is used to @@ -65,19 +65,20 @@ public final class TelephonyTimeSuggestion implements Parcelable { }; private final int mSlotIndex; - @Nullable private final TimestampedValue<Long> mUtcTime; + @Nullable private final TimestampedValue<Long> mUnixEpochTime; @Nullable private ArrayList<String> mDebugInfo; private TelephonyTimeSuggestion(Builder builder) { mSlotIndex = builder.mSlotIndex; - mUtcTime = builder.mUtcTime; + mUnixEpochTime = builder.mUnixEpochTime; mDebugInfo = builder.mDebugInfo != null ? new ArrayList<>(builder.mDebugInfo) : null; } private static TelephonyTimeSuggestion createFromParcel(Parcel in) { int slotIndex = in.readInt(); + TimestampedValue<Long> unixEpochTime = in.readParcelable(null /* classLoader */); TelephonyTimeSuggestion suggestion = new TelephonyTimeSuggestion.Builder(slotIndex) - .setUtcTime(in.readParcelable(null /* classLoader */)) + .setUnixEpochTime(unixEpochTime) .build(); @SuppressWarnings("unchecked") ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */); @@ -95,7 +96,7 @@ public final class TelephonyTimeSuggestion implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mSlotIndex); - dest.writeParcelable(mUtcTime, 0); + dest.writeParcelable(mUnixEpochTime, 0); dest.writeList(mDebugInfo); } @@ -111,11 +112,11 @@ public final class TelephonyTimeSuggestion implements Parcelable { /** * Returns the suggested time or {@code null} if there isn't one. * - * <p>See {@link TelephonyTimeSuggestion} for more information about {@code utcTime}. + * <p>See {@link TelephonyTimeSuggestion} for more information about {@code unixEpochTime}. */ @Nullable - public TimestampedValue<Long> getUtcTime() { - return mUtcTime; + public TimestampedValue<Long> getUnixEpochTime() { + return mUnixEpochTime; } /** @@ -163,19 +164,19 @@ public final class TelephonyTimeSuggestion implements Parcelable { } TelephonyTimeSuggestion that = (TelephonyTimeSuggestion) o; return mSlotIndex == that.mSlotIndex - && Objects.equals(mUtcTime, that.mUtcTime); + && Objects.equals(mUnixEpochTime, that.mUnixEpochTime); } @Override public int hashCode() { - return Objects.hash(mSlotIndex, mUtcTime); + return Objects.hash(mSlotIndex, mUnixEpochTime); } @Override public String toString() { return "TelephonyTimeSuggestion{" + "mSlotIndex='" + mSlotIndex + '\'' - + ", mUtcTime=" + mUtcTime + + ", mUnixEpochTime=" + mUnixEpochTime + ", mDebugInfo=" + mDebugInfo + '}'; } @@ -187,7 +188,7 @@ public final class TelephonyTimeSuggestion implements Parcelable { */ public static final class Builder { private final int mSlotIndex; - @Nullable private TimestampedValue<Long> mUtcTime; + @Nullable private TimestampedValue<Long> mUnixEpochTime; @Nullable private List<String> mDebugInfo; /** @@ -202,16 +203,16 @@ public final class TelephonyTimeSuggestion implements Parcelable { /** * Returns the builder for call chaining. * - * <p>See {@link TelephonyTimeSuggestion} for more information about {@code utcTime}. + * <p>See {@link TelephonyTimeSuggestion} for more information about {@code unixEpochTime}. */ @NonNull - public Builder setUtcTime(@Nullable TimestampedValue<Long> utcTime) { - if (utcTime != null) { - // utcTime can be null, but the value it holds cannot. - Objects.requireNonNull(utcTime.getValue()); + public Builder setUnixEpochTime(@Nullable TimestampedValue<Long> unixEpochTime) { + if (unixEpochTime != null) { + // unixEpochTime can be null, but the value it holds cannot. + Objects.requireNonNull(unixEpochTime.getValue()); } - mUtcTime = utcTime; + mUnixEpochTime = unixEpochTime; return this; } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 98e124d7e8f4..7cb093421417 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3434,7 +3434,7 @@ public abstract class Context { public abstract boolean stopServiceAsUser(Intent service, UserHandle user); /** - * Connect to an application service, creating it if needed. This defines + * Connects to an application service, creating it if needed. This defines * a dependency between your application and the service. The given * <var>conn</var> will receive the service object when it is created and be * told if it dies and restarts. The service will be considered required @@ -3449,11 +3449,8 @@ public abstract class Context { * will be invoked instead of * {@link ServiceConnection#onServiceConnected(ComponentName, IBinder) onServiceConnected()}. * - * <p>This method will throw {@link SecurityException} if the calling app does not - * have permission to bind to the given service. - * - * <p class="note">Note: this method <em>cannot be called from a - * {@link BroadcastReceiver} component</em>. A pattern you can use to + * <p class="note"><b>Note:</b> This method <em>cannot</em> be called from a + * {@link BroadcastReceiver} component. A pattern you can use to * communicate from a BroadcastReceiver to a Service is to call * {@link #startService} with the arguments containing the command to be * sent, with the service calling its @@ -3468,43 +3465,49 @@ public abstract class Context { * specify an explicit component name. * @param conn Receives information as the service is started and stopped. * This must be a valid ServiceConnection object; it must not be null. - * @param flags Operation options for the binding. May be 0, - * {@link #BIND_AUTO_CREATE}, {@link #BIND_DEBUG_UNBIND}, - * {@link #BIND_NOT_FOREGROUND}, {@link #BIND_ABOVE_CLIENT}, - * {@link #BIND_ALLOW_OOM_MANAGEMENT}, {@link #BIND_WAIVE_PRIORITY}. - * {@link #BIND_IMPORTANT}, {@link #BIND_ADJUST_WITH_ACTIVITY}, - * {@link #BIND_NOT_PERCEPTIBLE}, or {@link #BIND_INCLUDE_CAPABILITIES}. + * @param flags Operation options for the binding. Can be: + * <ul> + * <li>0 + * <li>{@link #BIND_AUTO_CREATE} + * <li>{@link #BIND_DEBUG_UNBIND} + * <li>{@link #BIND_NOT_FOREGROUND} + * <li>{@link #BIND_ABOVE_CLIENT} + * <li>{@link #BIND_ALLOW_OOM_MANAGEMENT} + * <li>{@link #BIND_WAIVE_PRIORITY} + * <li>{@link #BIND_IMPORTANT} + * <li>{@link #BIND_ADJUST_WITH_ACTIVITY} + * <li>{@link #BIND_NOT_PERCEPTIBLE} + * <li>{@link #BIND_INCLUDE_CAPABILITIES} + * </ul> + * * @return {@code true} if the system is in the process of bringing up a - * service that your client has permission to bind to; {@code false} - * if the system couldn't find the service or if your client doesn't - * have permission to bind to it. If this value is {@code true}, you - * should later call {@link #unbindService} to release the - * connection. + * service that your client has permission to bind to; {@code false} + * if the system couldn't find the service or if your client doesn't + * have permission to bind to it. Regardless of the return value, you + * should later call {@link #unbindService} to release the connection. * - * @throws SecurityException If the caller does not have permission to access the service - * or the service can not be found. + * @throws SecurityException If the caller does not have permission to + * access the service or the service cannot be found. Call + * {@link #unbindService} to release the connection when this exception + * is thrown. * * @see #unbindService * @see #startService - * @see #BIND_AUTO_CREATE - * @see #BIND_DEBUG_UNBIND - * @see #BIND_NOT_FOREGROUND - * @see #BIND_ABOVE_CLIENT - * @see #BIND_ALLOW_OOM_MANAGEMENT - * @see #BIND_WAIVE_PRIORITY - * @see #BIND_IMPORTANT - * @see #BIND_ADJUST_WITH_ACTIVITY - * @see #BIND_NOT_PERCEPTIBLE - * @see #BIND_INCLUDE_CAPABILITIES */ public abstract boolean bindService(@RequiresPermission Intent service, @NonNull ServiceConnection conn, @BindServiceFlags int flags); /** - * Same as {@link #bindService(Intent, ServiceConnection, int)} with executor to control - * ServiceConnection callbacks. + * Same as {@link #bindService(Intent, ServiceConnection, int) + * bindService(Intent, ServiceConnection, int)} with executor to control ServiceConnection + * callbacks. + * * @param executor Callbacks on ServiceConnection will be called on executor. Must use same * instance for the same instance of ServiceConnection. + * + * @return The result of the binding as described in + * {@link #bindService(Intent, ServiceConnection, int) + * bindService(Intent, ServiceConnection, int)}. */ public boolean bindService(@RequiresPermission @NonNull Intent service, @BindServiceFlags int flags, @NonNull @CallbackExecutor Executor executor, @@ -3530,12 +3533,13 @@ public abstract class Context { * @param instanceName Unique identifier for the service instance. Each unique * name here will result in a different service instance being created. Identifiers * must only contain ASCII letters, digits, underscores, and periods. - * @return Returns success of binding as per {@link #bindService}. * @param executor Callbacks on ServiceConnection will be called on executor. * Must use same instance for the same instance of ServiceConnection. * @param conn Receives information as the service is started and stopped. * This must be a valid ServiceConnection object; it must not be null. * + * @return Returns success of binding as per {@link #bindService}. + * * @throws SecurityException If the caller does not have permission to access the service * @throws IllegalArgumentException If the instanceName is invalid. * @@ -3550,8 +3554,7 @@ public abstract class Context { } /** - * Binds to a service in the given {@code user} in the same manner as - * {@link #bindService(Intent, ServiceConnection, int)}. + * Binds to a service in the given {@code user} in the same manner as {@link #bindService}. * * <p>If the given {@code user} is in the same profile group and the target package is the * same as the caller, {@code android.Manifest.permission.INTERACT_ACROSS_PROFILES} is @@ -5778,6 +5781,17 @@ public abstract class Context { public static final String DISPLAY_HASH_SERVICE = "display_hash"; /** + * Use with {@link #getSystemService(String)} to retrieve a + * {@link android.nearby.NearbyManager} to discover nearby devices. + * + * @see #getSystemService(String) + * @see android.nearby.NearbyManager + * @hide + */ + @SystemApi + public static final String NEARBY_SERVICE = "nearby"; + + /** * Determine whether the given permission is allowed for a particular * process and user ID running in the system. * diff --git a/core/java/android/content/ServiceConnection.java b/core/java/android/content/ServiceConnection.java index 21398f6e6473..660a7f0acbba 100644 --- a/core/java/android/content/ServiceConnection.java +++ b/core/java/android/content/ServiceConnection.java @@ -63,8 +63,12 @@ public interface ServiceConnection { * happen, for example, if the application hosting the service it is bound to * has been updated. * - * @param name The concrete component name of the service whose - * connection is dead. + * <p class="note"><b>Note:</b> The app that requested the binding must call + * {@link Context#unbindService(ServiceConnection)} to release the tracking + * resources associated with this ServiceConnection even if this callback was + * invoked following {@link Context#bindService Context.bindService() bindService()}. + * + * @param name The concrete component name of the service whose connection is dead. */ default void onBindingDied(ComponentName name) { } @@ -72,10 +76,10 @@ public interface ServiceConnection { /** * Called when the service being bound has returned {@code null} from its * {@link android.app.Service#onBind(Intent) onBind()} method. This indicates - * that the attempting service binding represented by this ServiceConnection + * that the attempted service binding represented by this ServiceConnection * will never become usable. * - * <p class="note">The app which requested the binding must still call + * <p class="note"><b>Note:</b> The app that requested the binding must still call * {@link Context#unbindService(ServiceConnection)} to release the tracking * resources associated with this ServiceConnection even if this callback was * invoked following {@link Context#bindService Context.bindService() bindService()}. diff --git a/core/java/android/hardware/OWNERS b/core/java/android/hardware/OWNERS index 4143bfcb9c0a..ce5cf674b5be 100644 --- a/core/java/android/hardware/OWNERS +++ b/core/java/android/hardware/OWNERS @@ -1,3 +1,9 @@ +# Generic +etalvala@google.com +jreck@google.com +michaelwr@google.com +sumir@google.com + # Camera per-file *Camera*=cychen@google.com,epeev@google.com,etalvala@google.com,shuzhenwang@google.com,zhijunhe@google.com,jchowdhary@google.com diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java index e3ff0891cc95..ee62170dbfd5 100644 --- a/core/java/android/hardware/SensorManager.java +++ b/core/java/android/hardware/SensorManager.java @@ -638,7 +638,7 @@ public abstract class SensorManager { /** * Unregisters a listener for the sensors with which it is registered. * - * <p class="note"></p> + * <p class="note"> * Note: Don't use this method with a one shot trigger sensor such as * {@link Sensor#TYPE_SIGNIFICANT_MOTION}. * Use {@link #cancelTriggerSensor(TriggerEventListener, Sensor)} instead. diff --git a/core/java/android/hardware/hdmi/HdmiClient.java b/core/java/android/hardware/hdmi/HdmiClient.java index 0c21746ea412..066de11d0623 100644 --- a/core/java/android/hardware/hdmi/HdmiClient.java +++ b/core/java/android/hardware/hdmi/HdmiClient.java @@ -17,6 +17,8 @@ import android.util.Log; public abstract class HdmiClient { private static final String TAG = "HdmiClient"; + private static final int UNKNOWN_VENDOR_ID = 0xFFFFFF; + /* package */ final IHdmiControlService mService; private IHdmiVendorCommandListener mIHdmiVendorCommandListener; @@ -94,11 +96,25 @@ public abstract class HdmiClient { } /** - * Sets a listener used to receive incoming vendor-specific command. + * Sets a listener used to receive incoming vendor-specific command. This listener will only + * receive {@code <Vendor Command>} but will not receive any {@code <Vendor Command with ID>} + * messages. * * @param listener listener object */ public void setVendorCommandListener(@NonNull VendorCommandListener listener) { + // Set the vendor ID to INVALID_VENDOR_ID. + setVendorCommandListener(listener, UNKNOWN_VENDOR_ID); + } + + /** + * Sets a listener used to receive incoming vendor-specific command. + * + * @param listener listener object + * @param vendorId The listener is interested in {@code <Vendor Command with ID>} received with + * this vendorId and all {@code <Vendor Command>} messages. + */ + public void setVendorCommandListener(@NonNull VendorCommandListener listener, int vendorId) { if (listener == null) { throw new IllegalArgumentException("listener cannot be null"); } @@ -107,7 +123,7 @@ public abstract class HdmiClient { } try { IHdmiVendorCommandListener wrappedListener = getListenerWrapper(listener); - mService.addVendorCommandListener(wrappedListener, getDeviceType()); + mService.addVendorCommandListener(wrappedListener, vendorId); mIHdmiVendorCommandListener = wrappedListener; } catch (RemoteException e) { Log.e(TAG, "failed to set vendor command listener: ", e); diff --git a/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java b/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java index 9a9e945a91cf..45b0689a90d4 100644 --- a/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java +++ b/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java @@ -221,8 +221,8 @@ public final class HdmiControlServiceWrapper { } @Override - public void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) { - HdmiControlServiceWrapper.this.addVendorCommandListener(listener, deviceType); + public void addVendorCommandListener(IHdmiVendorCommandListener listener, int vendorId) { + HdmiControlServiceWrapper.this.addVendorCommandListener(listener, vendorId); } @Override @@ -471,7 +471,7 @@ public final class HdmiControlServiceWrapper { boolean hasVendorId) {} /** @hide */ - public void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) {} + public void addVendorCommandListener(IHdmiVendorCommandListener listener, int vendorId) {} /** @hide */ public void sendStandby(int deviceType, int deviceId) {} diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl index 7f0e53ea2e68..48177e1726c4 100644 --- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl +++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl @@ -76,7 +76,7 @@ interface IHdmiControlService { void askRemoteDeviceToBecomeActiveSource(int physicalAddress); void sendVendorCommand(int deviceType, int targetAddress, in byte[] params, boolean hasVendorId); - void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType); + void addVendorCommandListener(IHdmiVendorCommandListener listener, int vendorId); void sendStandby(int deviceType, int deviceId); void setHdmiRecordListener(IHdmiRecordListener callback); void startOneTouchRecord(int recorderAddress, in byte[] recordSource); diff --git a/core/java/android/net/DhcpResults.aidl b/core/java/android/net/DhcpResults.aidl deleted file mode 100644 index f4db3c366d1e..000000000000 --- a/core/java/android/net/DhcpResults.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2012, 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 android.net; - -parcelable DhcpResults; diff --git a/core/java/android/net/DhcpResults.java b/core/java/android/net/DhcpResults.java deleted file mode 100644 index 82ba156b08d0..000000000000 --- a/core/java/android/net/DhcpResults.java +++ /dev/null @@ -1,330 +0,0 @@ -/* - * Copyright (C) 2012 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 android.net; - -import android.annotation.Nullable; -import android.compat.annotation.UnsupportedAppUsage; -import android.os.Build; -import android.os.Parcel; -import android.os.Parcelable; -import android.text.TextUtils; -import android.util.Log; - -import com.android.net.module.util.InetAddressUtils; - -import java.net.Inet4Address; -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -/** - * A simple object for retrieving the results of a DHCP request. - * Optimized (attempted) for that jni interface - * TODO: remove this class and replace with other existing constructs - * @hide - */ -public final class DhcpResults implements Parcelable { - private static final String TAG = "DhcpResults"; - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public LinkAddress ipAddress; - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public InetAddress gateway; - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public final ArrayList<InetAddress> dnsServers = new ArrayList<>(); - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public String domains; - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public Inet4Address serverAddress; - - /** Vendor specific information (from RFC 2132). */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public String vendorInfo; - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public int leaseDuration; - - /** Link MTU option. 0 means unset. */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public int mtu; - - public String serverHostName; - - @Nullable - public String captivePortalApiUrl; - - public DhcpResults() { - super(); - } - - /** - * Create a {@link StaticIpConfiguration} based on the DhcpResults. - */ - public StaticIpConfiguration toStaticIpConfiguration() { - return new StaticIpConfiguration.Builder() - .setIpAddress(ipAddress) - .setGateway(gateway) - .setDnsServers(dnsServers) - .setDomains(domains) - .build(); - } - - public DhcpResults(StaticIpConfiguration source) { - if (source != null) { - ipAddress = source.getIpAddress(); - gateway = source.getGateway(); - dnsServers.addAll(source.getDnsServers()); - domains = source.getDomains(); - } - } - - /** copy constructor */ - public DhcpResults(DhcpResults source) { - this(source == null ? null : source.toStaticIpConfiguration()); - if (source != null) { - serverAddress = source.serverAddress; - vendorInfo = source.vendorInfo; - leaseDuration = source.leaseDuration; - mtu = source.mtu; - serverHostName = source.serverHostName; - captivePortalApiUrl = source.captivePortalApiUrl; - } - } - - /** - * @see StaticIpConfiguration#getRoutes(String) - * @hide - */ - public List<RouteInfo> getRoutes(String iface) { - return toStaticIpConfiguration().getRoutes(iface); - } - - /** - * Test if this DHCP lease includes vendor hint that network link is - * metered, and sensitive to heavy data transfers. - */ - public boolean hasMeteredHint() { - if (vendorInfo != null) { - return vendorInfo.contains("ANDROID_METERED"); - } else { - return false; - } - } - - public void clear() { - ipAddress = null; - gateway = null; - dnsServers.clear(); - domains = null; - serverAddress = null; - vendorInfo = null; - leaseDuration = 0; - mtu = 0; - serverHostName = null; - captivePortalApiUrl = null; - } - - @Override - public String toString() { - StringBuffer str = new StringBuffer(super.toString()); - - str.append(" DHCP server ").append(serverAddress); - str.append(" Vendor info ").append(vendorInfo); - str.append(" lease ").append(leaseDuration).append(" seconds"); - if (mtu != 0) str.append(" MTU ").append(mtu); - str.append(" Servername ").append(serverHostName); - if (captivePortalApiUrl != null) { - str.append(" CaptivePortalApiUrl ").append(captivePortalApiUrl); - } - - return str.toString(); - } - - @Override - public boolean equals(@Nullable Object obj) { - if (this == obj) return true; - - if (!(obj instanceof DhcpResults)) return false; - - DhcpResults target = (DhcpResults)obj; - - return toStaticIpConfiguration().equals(target.toStaticIpConfiguration()) - && Objects.equals(serverAddress, target.serverAddress) - && Objects.equals(vendorInfo, target.vendorInfo) - && Objects.equals(serverHostName, target.serverHostName) - && leaseDuration == target.leaseDuration - && mtu == target.mtu - && Objects.equals(captivePortalApiUrl, target.captivePortalApiUrl); - } - - /** - * Implement the Parcelable interface - */ - public static final @android.annotation.NonNull Creator<DhcpResults> CREATOR = - new Creator<DhcpResults>() { - public DhcpResults createFromParcel(Parcel in) { - return readFromParcel(in); - } - - public DhcpResults[] newArray(int size) { - return new DhcpResults[size]; - } - }; - - /** Implement the Parcelable interface */ - public void writeToParcel(Parcel dest, int flags) { - toStaticIpConfiguration().writeToParcel(dest, flags); - dest.writeInt(leaseDuration); - dest.writeInt(mtu); - InetAddressUtils.parcelInetAddress(dest, serverAddress, flags); - dest.writeString(vendorInfo); - dest.writeString(serverHostName); - dest.writeString(captivePortalApiUrl); - } - - @Override - public int describeContents() { - return 0; - } - - private static DhcpResults readFromParcel(Parcel in) { - final StaticIpConfiguration s = StaticIpConfiguration.CREATOR.createFromParcel(in); - final DhcpResults dhcpResults = new DhcpResults(s); - dhcpResults.leaseDuration = in.readInt(); - dhcpResults.mtu = in.readInt(); - dhcpResults.serverAddress = (Inet4Address) InetAddressUtils.unparcelInetAddress(in); - dhcpResults.vendorInfo = in.readString(); - dhcpResults.serverHostName = in.readString(); - dhcpResults.captivePortalApiUrl = in.readString(); - return dhcpResults; - } - - // Utils for jni population - false on success - // Not part of the superclass because they're only used by the JNI iterface to the DHCP daemon. - public boolean setIpAddress(String addrString, int prefixLength) { - try { - Inet4Address addr = (Inet4Address) InetAddresses.parseNumericAddress(addrString); - ipAddress = new LinkAddress(addr, prefixLength); - } catch (IllegalArgumentException|ClassCastException e) { - Log.e(TAG, "setIpAddress failed with addrString " + addrString + "/" + prefixLength); - return true; - } - return false; - } - - public boolean setGateway(String addrString) { - try { - gateway = InetAddresses.parseNumericAddress(addrString); - } catch (IllegalArgumentException e) { - Log.e(TAG, "setGateway failed with addrString " + addrString); - return true; - } - return false; - } - - public boolean addDns(String addrString) { - if (TextUtils.isEmpty(addrString) == false) { - try { - dnsServers.add(InetAddresses.parseNumericAddress(addrString)); - } catch (IllegalArgumentException e) { - Log.e(TAG, "addDns failed with addrString " + addrString); - return true; - } - } - return false; - } - - public LinkAddress getIpAddress() { - return ipAddress; - } - - public void setIpAddress(LinkAddress ipAddress) { - this.ipAddress = ipAddress; - } - - public InetAddress getGateway() { - return gateway; - } - - public void setGateway(InetAddress gateway) { - this.gateway = gateway; - } - - public List<InetAddress> getDnsServers() { - return dnsServers; - } - - /** - * Add a DNS server to this configuration. - */ - public void addDnsServer(InetAddress server) { - dnsServers.add(server); - } - - public String getDomains() { - return domains; - } - - public void setDomains(String domains) { - this.domains = domains; - } - - public Inet4Address getServerAddress() { - return serverAddress; - } - - public void setServerAddress(Inet4Address addr) { - serverAddress = addr; - } - - public int getLeaseDuration() { - return leaseDuration; - } - - public void setLeaseDuration(int duration) { - leaseDuration = duration; - } - - public String getVendorInfo() { - return vendorInfo; - } - - public void setVendorInfo(String info) { - vendorInfo = info; - } - - public int getMtu() { - return mtu; - } - - public void setMtu(int mtu) { - this.mtu = mtu; - } - - public String getCaptivePortalApiUrl() { - return captivePortalApiUrl; - } - - public void setCaptivePortalApiUrl(String url) { - captivePortalApiUrl = url; - } -} diff --git a/core/java/android/net/IVpnManager.aidl b/core/java/android/net/IVpnManager.aidl index 271efe41a9ef..070efa363cc0 100644 --- a/core/java/android/net/IVpnManager.aidl +++ b/core/java/android/net/IVpnManager.aidl @@ -38,7 +38,7 @@ interface IVpnManager { /** VpnManager APIs */ boolean provisionVpnProfile(in VpnProfile profile, String packageName); void deleteVpnProfile(String packageName); - void startVpnProfile(String packageName); + String startVpnProfile(String packageName); void stopVpnProfile(String packageName); /** Always-on VPN APIs */ diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java index 036607be2b5d..0fd3e034291b 100644 --- a/core/java/android/net/Ikev2VpnProfile.java +++ b/core/java/android/net/Ikev2VpnProfile.java @@ -159,8 +159,9 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { boolean isMetered, int maxMtu, boolean restrictToTestNetworks, - boolean excludeLocalRoutes) { - super(type, excludeLocalRoutes); + boolean excludeLocalRoutes, + boolean requiresInternetValidation) { + super(type, excludeLocalRoutes, requiresInternetValidation); checkNotNull(serverAddr, MISSING_PARAM_MSG_TMPL, "Server address"); checkNotNull(userIdentity, MISSING_PARAM_MSG_TMPL, "User Identity"); @@ -181,7 +182,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { mAllowedAlgorithms = Collections.unmodifiableList(new ArrayList<>(allowedAlgorithms)); if (excludeLocalRoutes && !isBypassable) { throw new IllegalArgumentException( - "Vpn should be byassable if excludeLocalRoutes is set"); + "Vpn must be bypassable if excludeLocalRoutes is set"); } mIsBypassable = isBypassable; @@ -238,7 +239,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { * that provides Authentication, and one that provides Encryption. Authenticated Encryption with * Associated Data (AEAD) algorithms are counted as providing Authentication and Encryption. * - * @param allowedAlgorithms The list to be validated + * @param algorithmNames The list to be validated */ private static void validateAllowedAlgorithms(@NonNull List<String> algorithmNames) { // First, make sure no insecure algorithms were proposed. @@ -400,7 +401,9 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { mIsBypassable, mIsMetered, mMaxMtu, - mIsRestrictedToTestNetworks); + mIsRestrictedToTestNetworks, + mExcludeLocalRoutes, + mRequiresInternetValidation); } @Override @@ -425,7 +428,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { && mIsMetered == other.mIsMetered && mMaxMtu == other.mMaxMtu && mIsRestrictedToTestNetworks == other.mIsRestrictedToTestNetworks - && mExcludeLocalRoutes == other.mExcludeLocalRoutes; + && mExcludeLocalRoutes == other.mExcludeLocalRoutes + && mRequiresInternetValidation == other.mRequiresInternetValidation; } /** @@ -439,7 +443,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { @NonNull public VpnProfile toVpnProfile() throws IOException, GeneralSecurityException { final VpnProfile profile = new VpnProfile("" /* Key; value unused by IKEv2VpnProfile(s) */, - mIsRestrictedToTestNetworks, mExcludeLocalRoutes); + mIsRestrictedToTestNetworks, mExcludeLocalRoutes, mRequiresInternetValidation); profile.type = mType; profile.server = mServerAddr; profile.ipsecIdentifier = mUserIdentity; @@ -543,7 +547,9 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { if (profile.excludeLocalRoutes && !profile.isBypassable) { Log.w(TAG, "ExcludeLocalRoutes should only be set in the bypassable VPN"); } - builder.setExcludeLocalRoutes(profile.excludeLocalRoutes && profile.isBypassable); + + builder.setLocalRoutesExcluded(profile.excludeLocalRoutes && profile.isBypassable); + builder.setRequiresInternetValidation(profile.requiresInternetValidation); return builder.build(); } @@ -776,6 +782,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { @Nullable private ProxyInfo mProxyInfo; @NonNull private List<String> mAllowedAlgorithms = DEFAULT_ALGORITHMS; + private boolean mRequiresInternetValidation = false; private boolean mIsBypassable = false; private boolean mIsMetered = true; private int mMaxMtu = PlatformVpnProfile.MAX_MTU_DEFAULT; @@ -988,6 +995,30 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { } /** + * Request that this VPN undergoes Internet validation. + * + * If this is true, the platform will perform basic validation checks for Internet + * connectivity over this VPN. If and when they succeed, the VPN network capabilities will + * reflect this by gaining the {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} + * capability. + * + * If this is false, the platform assumes the VPN either is always capable of reaching the + * Internet or intends not to. In this case, the VPN network capabilities will + * always gain the {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} capability + * immediately after it connects, whether it can reach public Internet destinations or not. + * + * @param requiresInternetValidation {@code true} if the framework should attempt to + * validate this VPN for Internet connectivity. Defaults + * to {@code false}. + */ + @NonNull + @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) + public Builder setRequiresInternetValidation(boolean requiresInternetValidation) { + mRequiresInternetValidation = requiresInternetValidation; + return this; + } + + /** * Marks the VPN network as metered. * * <p>A VPN network is classified as metered when the user is sensitive to heavy data usage @@ -1074,7 +1105,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { */ @NonNull @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) - public Builder setExcludeLocalRoutes(boolean excludeLocalRoutes) { + public Builder setLocalRoutesExcluded(boolean excludeLocalRoutes) { mExcludeLocalRoutes = excludeLocalRoutes; return this; } @@ -1103,7 +1134,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { mIsMetered, mMaxMtu, mIsRestrictedToTestNetworks, - mExcludeLocalRoutes); + mExcludeLocalRoutes, + mRequiresInternetValidation); } } } diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java index ab1f5420fb3f..4b35b0d773d5 100644 --- a/core/java/android/net/NetworkPolicy.java +++ b/core/java/android/net/NetworkPolicy.java @@ -338,7 +338,9 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> { out.writeInt(TEMPLATE_BACKUP_VERSION_LATEST); out.writeInt(template.getMatchRule()); - BackupUtils.writeString(out, template.getSubscriberIds().iterator().next()); + final Set<String> subscriberIds = template.getSubscriberIds(); + BackupUtils.writeString(out, subscriberIds.isEmpty() + ? null : subscriberIds.iterator().next()); BackupUtils.writeString(out, template.getWifiNetworkKeys().isEmpty() ? null : template.getWifiNetworkKeys().iterator().next()); out.writeInt(template.getMeteredness()); diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java index c936bfa05118..0e39f425c0fa 100644 --- a/core/java/android/net/NetworkPolicyManager.java +++ b/core/java/android/net/NetworkPolicyManager.java @@ -167,6 +167,8 @@ public class NetworkPolicyManager { public static final String FIREWALL_CHAIN_NAME_POWERSAVE = "powersave"; /** @hide */ public static final String FIREWALL_CHAIN_NAME_RESTRICTED = "restricted"; + /** @hide */ + public static final String FIREWALL_CHAIN_NAME_LOW_POWER_STANDBY = "low_power_standby"; private static final boolean ALLOW_PLATFORM_APP_POLICY = true; diff --git a/core/java/android/net/PlatformVpnProfile.java b/core/java/android/net/PlatformVpnProfile.java index 3c45799e10f2..6b6f1cad2cd8 100644 --- a/core/java/android/net/PlatformVpnProfile.java +++ b/core/java/android/net/PlatformVpnProfile.java @@ -16,10 +16,6 @@ package android.net; -import static android.net.PlatformVpnProfile.TYPE_IKEV2_IPSEC_PSK; -import static android.net.PlatformVpnProfile.TYPE_IKEV2_IPSEC_RSA; -import static android.net.PlatformVpnProfile.TYPE_IKEV2_IPSEC_USER_PASS; - import android.annotation.IntDef; import android.annotation.NonNull; @@ -67,11 +63,15 @@ public abstract class PlatformVpnProfile { /** @hide */ protected final boolean mExcludeLocalRoutes; + /** @hide */ + protected final boolean mRequiresInternetValidation; /** @hide */ - PlatformVpnProfile(@PlatformVpnType int type, boolean excludeLocalRoutes) { + PlatformVpnProfile(@PlatformVpnType int type, boolean excludeLocalRoutes, + boolean requiresValidation) { mType = type; mExcludeLocalRoutes = excludeLocalRoutes; + mRequiresInternetValidation = requiresValidation; } /** Returns the profile integer type. */ @@ -80,14 +80,30 @@ public abstract class PlatformVpnProfile { return mType; } - /** - * Returns if the local traffic is exempted from the VPN. + * Returns whether the local traffic is exempted from the VPN. */ - public final boolean getExcludeLocalRoutes() { + public final boolean areLocalRoutesExcluded() { return mExcludeLocalRoutes; } + /** + * Returns whether this VPN should undergo Internet validation. + * + * If this is true, the platform will perform basic validation checks for Internet + * connectivity over this VPN. If and when they succeed, the VPN network capabilities will + * reflect this by gaining the {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} + * capability. + * + * If this is false, the platform assumes the VPN either is always capable of reaching the + * Internet or intends not to. In this case, the VPN network capabilities will + * always gain the {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} capability + * immediately after it connects, whether it can reach public Internet destinations or not. + */ + public final boolean isInternetValidationRequired() { + return mRequiresInternetValidation; + } + /** Returns a type string describing the VPN profile type */ @NonNull public final String getTypeString() { diff --git a/core/java/android/net/VpnManager.java b/core/java/android/net/VpnManager.java index 319382691925..c51444cd31b6 100644 --- a/core/java/android/net/VpnManager.java +++ b/core/java/android/net/VpnManager.java @@ -24,6 +24,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SdkConstant; import android.annotation.SystemApi; import android.annotation.UserIdInt; import android.app.Activity; @@ -52,7 +53,7 @@ import java.util.List; * app (unlike VpnService). * * <p>VPN apps using supported protocols should preferentially use this API over the {@link - * VpnService} API for ease-of-development and reduced maintainance burden. This also give the user + * VpnService} API for ease-of-development and reduced maintenance burden. This also give the user * the guarantee that VPN network traffic is not subjected to on-device packet interception. * * @see Ikev2VpnProfile @@ -97,139 +98,175 @@ public class VpnManager { public static final String NOTIFICATION_CHANNEL_VPN = "VPN"; /** - * Action sent in the intent when an error occurred. + * Action sent in {@link android.content.Intent}s to VpnManager clients when an event occurred. * - * @hide + * This action will have a category of either {@link #CATEGORY_EVENT_IKE_ERROR}, + * {@link #CATEGORY_EVENT_NETWORK_ERROR}, or {@link #CATEGORY_EVENT_DEACTIVATED_BY_USER}, + * that the app can use to filter events it's interested in reacting to. + * + * It will also contain the following extras : + * <ul> + * <li>{@link #EXTRA_SESSION_KEY}, a {@code String} for the session key, as returned by + * {@link #startProvisionedVpnProfileSession}. + * <li>{@link #EXTRA_TIMESTAMP_MILLIS}, a long for the timestamp at which the error occurred, + * in milliseconds since the epoch, as returned by + * {@link java.lang.System#currentTimeMillis}. + * <li>{@link #EXTRA_UNDERLYING_NETWORK}, a {@link Network} containing the underlying + * network at the time the error occurred, or null if none. Note that this network + * may have disconnected already. + * <li>{@link #EXTRA_UNDERLYING_NETWORK_CAPABILITIES}, a {@link NetworkCapabilities} for + * the underlying network at the time the error occurred. + * <li>{@link #EXTRA_UNDERLYING_LINK_PROPERTIES}, a {@link LinkProperties} for the underlying + * network at the time the error occurred. + * </ul> + * When this event is an error, either {@link #CATEGORY_EVENT_IKE_ERROR} or + * {@link #CATEGORY_EVENT_NETWORK_ERROR}, the following extras will be populated : + * <ul> + * <li>{@link #EXTRA_ERROR_CLASS}, an {@code int} for the class of error, either + * {@link #ERROR_CLASS_RECOVERABLE} or {@link #ERROR_CLASS_NOT_RECOVERABLE}. + * <li>{@link #EXTRA_ERROR_CODE}, an {@code int} error code specific to the error. See + * {@link #EXTRA_ERROR_CODE} for details. + * </ul> */ - public static final String ACTION_VPN_MANAGER_ERROR = "android.net.action.VPN_MANAGER_ERROR"; + @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION) + public static final String ACTION_VPN_MANAGER_EVENT = "android.net.action.VPN_MANAGER_EVENT"; /** - * An IKE protocol error. Codes are the codes from IkeProtocolException, RFC 7296. + * An IKE protocol error occurred. * - * @hide + * Codes (in {@link #EXTRA_ERROR_CODE}) are the codes from + * {@link android.net.ipsec.ike.exceptions.IkeProtocolException}, as defined by IANA in + * "IKEv2 Notify Message Types - Error Types". */ - public static final String CATEGORY_ERROR_IKE = "android.net.category.ERROR_IKE"; + @SdkConstant(SdkConstant.SdkConstantType.INTENT_CATEGORY) + public static final String CATEGORY_EVENT_IKE_ERROR = "android.net.category.EVENT_IKE_ERROR"; /** - * User deactivated the VPN, either by turning it off or selecting a different VPN provider. - * The error code is always 0. + * A network error occurred. * - * @hide + * Error codes (in {@link #EXTRA_ERROR_CODE}) are ERROR_CODE_NETWORK_*. */ - public static final String CATEGORY_ERROR_USER_DEACTIVATED = - "android.net.category.ERROR_USER_DEACTIVATED"; + @SdkConstant(SdkConstant.SdkConstantType.INTENT_CATEGORY) + public static final String CATEGORY_EVENT_NETWORK_ERROR = + "android.net.category.EVENT_NETWORK_ERROR"; /** - * Network error. Error codes are ERROR_CODE_NETWORK_*. + * The user deactivated the VPN. * - * @hide + * This can happen either when the user turns the VPN off explicitly, or when they select + * a different VPN provider. */ - public static final String CATEGORY_ERROR_NETWORK = "android.net.category.ERROR_NETWORK"; + @SdkConstant(SdkConstant.SdkConstantType.INTENT_CATEGORY) + public static final String CATEGORY_EVENT_DEACTIVATED_BY_USER = + "android.net.category.EVENT_DEACTIVATED_BY_USER"; /** - * The key of the session that experienced this error, as returned by - * startProvisionedVpnProfileSession. + * The key of the session that experienced this event, as a {@code String}. * - * @hide + * This is the same key that was returned by {@link #startProvisionedVpnProfileSession}. */ public static final String EXTRA_SESSION_KEY = "android.net.extra.SESSION_KEY"; /** - * Extra for the Network object that was the underlying network at the time of the failure, or - * null if none. + * The network that was underlying the VPN when the event occurred, as a {@link Network}. * - * @hide + * This extra will be null if there was no underlying network at the time of the event. */ public static final String EXTRA_UNDERLYING_NETWORK = "android.net.extra.UNDERLYING_NETWORK"; /** - * The NetworkCapabilities of the underlying network. + * The {@link NetworkCapabilities} of the underlying network when the event occurred. * - * @hide + * This extra will be null if there was no underlying network at the time of the event. */ public static final String EXTRA_UNDERLYING_NETWORK_CAPABILITIES = "android.net.extra.UNDERLYING_NETWORK_CAPABILITIES"; /** - * The LinkProperties of the underlying network. + * The {@link LinkProperties} of the underlying network when the event occurred. * - * @hide + * This extra will be null if there was no underlying network at the time of the event. */ public static final String EXTRA_UNDERLYING_LINK_PROPERTIES = "android.net.extra.UNDERLYING_LINK_PROPERTIES"; /** - * A long timestamp with SystemClock.elapsedRealtime base for when the event happened. + * A {@code long} timestamp containing the time at which the event occurred. * - * @hide + * This is a number of milliseconds since the epoch, suitable to be compared with + * {@link java.lang.System#currentTimeMillis}. */ - public static final String EXTRA_TIMESTAMP = "android.net.extra.TIMESTAMP"; + public static final String EXTRA_TIMESTAMP_MILLIS = "android.net.extra.TIMESTAMP_MILLIS"; /** - * Extra for the error type. This is ERROR_NOT_RECOVERABLE or ERROR_RECOVERABLE. + * Extra for the error class, as an {@code int}. * - * @hide + * This is always either {@link #ERROR_CLASS_NOT_RECOVERABLE} or + * {@link #ERROR_CLASS_RECOVERABLE}. This extra is only populated for error categories. */ - public static final String EXTRA_ERROR_TYPE = "android.net.extra.ERROR_TYPE"; + public static final String EXTRA_ERROR_CLASS = "android.net.extra.ERROR_CLASS"; /** - * Extra for the error code. The value will be 0 for CATEGORY_ERROR_USER_DEACTIVATED, one of - * ERROR_CODE_NETWORK_* for ERROR_CATEGORY_NETWORK or one of values defined in - * IkeProtocolException#ErrorType for CATEGORY_ERROR_IKE. + * Extra for an error code, as an {@code int}. * - * @hide + * <ul> + * <li>For {@link #CATEGORY_EVENT_NETWORK_ERROR}, this is one of the + * {@code ERROR_CODE_NETWORK_*} constants. + * <li>For {@link #CATEGORY_EVENT_IKE_ERROR}, this is one of values defined in + * {@link android.net.ipsec.ike.exceptions.IkeProtocolException}.ERROR_TYPE_*. + * </ul> + * For non-error categories, this extra is not populated. */ public static final String EXTRA_ERROR_CODE = "android.net.extra.ERROR_CODE"; /** - * This error is fatal, e.g. the VPN was disabled or configuration error. The stack will not - * retry connection. + * {@link #EXTRA_ERROR_CLASS} coding for a non-recoverable error. * - * @hide + * This error is fatal, e.g. configuration error. The stack will not retry connection. */ - public static final int ERROR_NOT_RECOVERABLE = 1; + public static final int ERROR_CLASS_NOT_RECOVERABLE = 1; /** - * The stack experienced an error but will retry with exponential backoff, e.g. network timeout. + * {@link #EXTRA_ERROR_CLASS} coding for a recoverable error. * - * @hide + * The stack experienced an error but will retry with exponential backoff, e.g. network timeout. */ - public static final int ERROR_RECOVERABLE = 2; + public static final int ERROR_CLASS_RECOVERABLE = 2; /** - * An error code to indicate that there was an UnknownHostException. + * An {@link #EXTRA_ERROR_CODE} for {@link #CATEGORY_EVENT_NETWORK_ERROR} to indicate that the + * network host isn't known. * - * @hide + * This happens when domain name resolution could not resolve an IP address for the + * specified host. {@see java.net.UnknownHostException} */ public static final int ERROR_CODE_NETWORK_UNKNOWN_HOST = 0; /** - * An error code to indicate that there is a SocketTimeoutException. - * - * @hide - */ - public static final int ERROR_CODE_NETWORK_TIMEOUT = 1; - - /** - * An error code to indicate that the connection is refused. + * An {@link #EXTRA_ERROR_CODE} for {@link #CATEGORY_EVENT_NETWORK_ERROR} indicating a timeout. * - * @hide + * For Ikev2 VPNs, this happens typically after a retransmission failure. + * {@see android.net.ipsec.ike.exceptions.IkeTimeoutException} */ - public static final int ERROR_CODE_NETWORK_CONNECT = 2; + public static final int ERROR_CODE_NETWORK_PROTOCOL_TIMEOUT = 1; /** - * An error code to indicate the connection was reset. (e.g. SocketException) + * An {@link #EXTRA_ERROR_CODE} for {@link #CATEGORY_EVENT_NETWORK_ERROR} indicating that + * network connectivity was lost. * - * @hide + * The most common reason for this error is that the underlying network was disconnected, + * {@see android.net.ipsec.ike.exceptions.IkeNetworkLostException}. */ - public static final int ERROR_CODE_NETWORK_CONNECTION_RESET = 3; + public static final int ERROR_CODE_NETWORK_LOST = 2; /** - * An error code to indicate that there is an IOException. + * An {@link #EXTRA_ERROR_CODE} for {@link #CATEGORY_EVENT_NETWORK_ERROR} indicating an + * input/output error. * - * @hide + * This code happens when reading or writing to sockets on the underlying networks was + * terminated by an I/O error. {@see IOException}. */ - public static final int ERROR_CODE_NETWORK_IO = 4; + public static final int ERROR_CODE_NETWORK_IO = 3; /** @hide */ @IntDef(value = {TYPE_VPN_NONE, TYPE_VPN_SERVICE, TYPE_VPN_PLATFORM, TYPE_VPN_LEGACY, @@ -317,17 +354,32 @@ public class VpnManager { /** * Request the startup of a previously provisioned VPN. * + * @return A unique key corresponding to this session. * @throws SecurityException exception if user or device settings prevent this VPN from being - * setup, or if user consent has not been granted + * setup, or if user consent has not been granted */ - public void startProvisionedVpnProfile() { + @NonNull + public String startProvisionedVpnProfileSession() { try { - mService.startVpnProfile(mContext.getOpPackageName()); + return mService.startVpnProfile(mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } + /** + * Request the startup of a previously provisioned VPN. + * + * @throws SecurityException exception if user or device settings prevent this VPN from being + * setup, or if user consent has not been granted + * @deprecated This method is replaced by startProvisionedVpnProfileSession which returns a + * session key for the caller to diagnose the errors. + */ + @Deprecated + public void startProvisionedVpnProfile() { + startProvisionedVpnProfileSession(); + } + /** Tear down the VPN provided by the calling app (if any) */ public void stopProvisionedVpnProfile() { try { diff --git a/core/java/android/net/netstats/NetworkStatsDataMigrationUtils.java b/core/java/android/net/netstats/NetworkStatsDataMigrationUtils.java index 9772bde94ac9..2dd3aaa1f55a 100644 --- a/core/java/android/net/netstats/NetworkStatsDataMigrationUtils.java +++ b/core/java/android/net/netstats/NetworkStatsDataMigrationUtils.java @@ -24,6 +24,7 @@ import static android.net.ConnectivityManager.TYPE_MOBILE_MMS; import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL; import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.TAG_NONE; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import android.annotation.NonNull; import android.annotation.SystemApi; @@ -108,6 +109,7 @@ public class NetworkStatsDataMigrationUtils { static final int VERSION_ADD_METERED = 4; static final int VERSION_ADD_DEFAULT_NETWORK = 5; static final int VERSION_ADD_OEM_MANAGED_NETWORK = 6; + static final int VERSION_ADD_SUB_ID = 7; } /** @@ -448,6 +450,13 @@ public class NetworkStatsDataMigrationUtils { oemNetCapabilities = NetworkTemplate.OEM_MANAGED_NO; } + final int subId; + if (version >= IdentitySetVersion.VERSION_ADD_SUB_ID) { + subId = in.readInt(); + } else { + subId = INVALID_SUBSCRIPTION_ID; + } + // Legacy files might contain TYPE_MOBILE_* types which were deprecated in later // releases. For backward compatibility, record them as TYPE_MOBILE instead. final int collapsedLegacyType = getCollapsedLegacyType(type); @@ -457,7 +466,8 @@ public class NetworkStatsDataMigrationUtils { .setWifiNetworkKey(networkId) .setRoaming(roaming).setMetered(metered) .setDefaultNetwork(defaultNetwork) - .setOemManaged(oemNetCapabilities); + .setOemManaged(oemNetCapabilities) + .setSubId(subId); if (type == TYPE_MOBILE && ratType != NetworkTemplate.NETWORK_TYPE_ALL) { builder.setRatType(ratType); } @@ -501,10 +511,10 @@ public class NetworkStatsDataMigrationUtils { * This is copied from {@code NetworkStatsCollection#readLegacyUid}. * See {@code NetworkStatsService#maybeUpgradeLegacyStatsLocked}. * - * @param taggedData whether to read tagged data. For legacy uid files, the tagged - * data was stored in the same binary file with non-tagged data. - * But in later releases, these data should be kept in different - * recorders. + * @param taggedData whether to read only tagged data (true) or only non-tagged data + * (false). For legacy uid files, the tagged data was stored in + * the same binary file with non-tagged data. But in later releases, + * these data should be kept in different recorders. * @hide */ @VisibleForTesting diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java index 0a9fe90f2524..2b34d8639235 100644 --- a/core/java/android/nfc/cardemulation/CardEmulation.java +++ b/core/java/android/nfc/cardemulation/CardEmulation.java @@ -25,6 +25,7 @@ import android.app.Activity; import android.app.ActivityThread; import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.nfc.INfcCardEmulation; @@ -62,7 +63,9 @@ public final class CardEmulation { * replace the current default service with the service * identified with the ComponentName specified in * {@link #EXTRA_SERVICE_COMPONENT}, for the category - * specified in {@link #EXTRA_CATEGORY} + * specified in {@link #EXTRA_CATEGORY}. There is an optional + * extra field using {@link Intent#EXTRA_USER} to specify + * the {@link UserHandle} of the user that owns the app. */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_CHANGE_DEFAULT = @@ -84,13 +87,6 @@ public final class CardEmulation { public static final String EXTRA_SERVICE_COMPONENT = "component"; /** - * The caller userId extra for {@link #ACTION_CHANGE_DEFAULT}. - * - * @see #ACTION_CHANGE_DEFAULT - */ - public static final String EXTRA_USERID = "android.nfc.cardemulation.extra.USERID"; - - /** * Category used for NFC payment services. */ public static final String CATEGORY_PAYMENT = "payment"; diff --git a/apex/media/aidl/private/android/media/Controller2Link.aidl b/core/java/android/os/BadTypeParcelableException.java index 64edafcb11fc..2ca3bd2adca1 100644 --- a/apex/media/aidl/private/android/media/Controller2Link.aidl +++ b/core/java/android/os/BadTypeParcelableException.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 The Android Open Source Project + * Copyright (C) 2022 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. @@ -14,6 +14,17 @@ * limitations under the License. */ -package android.media; +package android.os; -parcelable Controller2Link; +/** Used by Parcel to signal that the type on the payload was not expected by the caller. */ +class BadTypeParcelableException extends BadParcelableException { + BadTypeParcelableException(String msg) { + super(msg); + } + BadTypeParcelableException(Exception cause) { + super(cause); + } + BadTypeParcelableException(String msg, Throwable cause) { + super(msg, cause); + } +} diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java index ad3de25fecc2..e5dab0539a8e 100644 --- a/core/java/android/os/BaseBundle.java +++ b/core/java/android/os/BaseBundle.java @@ -16,6 +16,8 @@ package android.os; +import static java.util.Objects.requireNonNull; + import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; @@ -31,7 +33,7 @@ import com.android.internal.util.IndentingPrintWriter; import java.io.Serializable; import java.util.ArrayList; import java.util.Set; -import java.util.function.Supplier; +import java.util.function.BiFunction; /** * A mapping from String keys to values of various types. In most cases, you @@ -252,11 +254,10 @@ public class BaseBundle { if (size == 0) { return null; } - Object o = getValueAt(0); try { - return (String) o; - } catch (ClassCastException e) { - typeWarning("getPairValue()", o, "String", e); + return getValueAt(0, String.class); + } catch (ClassCastException | BadTypeParcelableException e) { + typeWarning("getPairValue()", "String", e); return null; } } @@ -309,7 +310,7 @@ public class BaseBundle { } for (int i = 0, n = mMap.size(); i < n; i++) { // Triggers deserialization of i-th item, if needed - getValueAt(i); + getValueAt(i, /* clazz */ null); } } } @@ -321,26 +322,59 @@ public class BaseBundle { * This call should always be made after {@link #unparcel()} or inside a lock after making sure * {@code mMap} is not null. * + * @deprecated Use {@link #getValue(String, Class, Class[])}. This method should only be used in + * other deprecated APIs. + * * @hide */ + @Deprecated + @Nullable final Object getValue(String key) { + return getValue(key, /* clazz */ null); + } + + /** Same as {@link #getValue(String, Class, Class[])} with no item types. */ + @Nullable + final <T> T getValue(String key, @Nullable Class<T> clazz) { + // Avoids allocating Class[0] array + return getValue(key, clazz, (Class<?>[]) null); + } + + /** + * Returns the value for key {@code key} for expected return type {@code clazz} (or pass {@code + * null} for no type check). + * + * For {@code itemTypes}, see {@link Parcel#readValue(int, ClassLoader, Class, Class[])}. + * + * This call should always be made after {@link #unparcel()} or inside a lock after making sure + * {@code mMap} is not null. + * + * @hide + */ + @Nullable + final <T> T getValue(String key, @Nullable Class<T> clazz, @Nullable Class<?>... itemTypes) { int i = mMap.indexOfKey(key); - return (i >= 0) ? getValueAt(i) : null; + return (i >= 0) ? getValueAt(i, clazz, itemTypes) : null; } /** - * Returns the value for a certain position in the array map. + * Returns the value for a certain position in the array map for expected return type {@code + * clazz} (or pass {@code null} for no type check). + * + * For {@code itemTypes}, see {@link Parcel#readValue(int, ClassLoader, Class, Class[])}. * * This call should always be made after {@link #unparcel()} or inside a lock after making sure * {@code mMap} is not null. * * @hide */ - final Object getValueAt(int i) { + @SuppressWarnings("unchecked") + @Nullable + final <T> T getValueAt(int i, @Nullable Class<T> clazz, @Nullable Class<?>... itemTypes) { Object object = mMap.valueAt(i); - if (object instanceof Supplier<?>) { + if (object instanceof BiFunction<?, ?, ?>) { try { - object = ((Supplier<?>) object).get(); + object = ((BiFunction<Class<?>, Class<?>[], ?>) object).apply(clazz, itemTypes); } catch (BadParcelableException e) { if (sShouldDefuse) { Log.w(TAG, "Failed to parse item " + mMap.keyAt(i) + ", returning null.", e); @@ -351,7 +385,7 @@ public class BaseBundle { } mMap.setValueAt(i, object); } - return object; + return (clazz != null) ? clazz.cast(object) : (T) object; } private void initializeFromParcelLocked(@NonNull Parcel parcelledData, boolean recycleParcel, @@ -528,7 +562,7 @@ public class BaseBundle { } else { // Following semantic above of failing in case we get a serialized value vs a // deserialized one, we'll compare the map. If a certain element hasn't been - // deserialized yet, it's a Supplier (or more specifically a LazyValue, but let's + // deserialized yet, it's a function object (or more specifically a LazyValue, but let's // pretend we don't know that here :P), we'll use that element's equality comparison as // map naturally does. That will takes care of comparing the payload if needed (see // Parcel.readLazyValue() for details). @@ -602,7 +636,11 @@ public class BaseBundle { * * @param key a String key * @return an Object, or null + * + * @deprecated Use the type-safe specific APIs depending on the type of the item to be + * retrieved, eg. {@link #getString(String)}. */ + @Deprecated @Nullable public Object get(String key) { unparcel(); @@ -610,6 +648,32 @@ public class BaseBundle { } /** + * Returns the object of type {@code clazz} for the given {@code key}, or {@code null} if: + * <ul> + * <li>No mapping of the desired type exists for the given key. + * <li>A {@code null} value is explicitly associated with the key. + * <li>The object is not of type {@code clazz}. + * </ul> + * + * <p>Use the more specific APIs where possible, especially in the case of containers such as + * lists, since those APIs allow you to specify the type of the items. + * + * @param key String key + * @param clazz The type of the object expected + * @return an Object, or null + */ + @Nullable + <T> T get(@Nullable String key, @NonNull Class<T> clazz) { + unparcel(); + try { + return getValue(key, requireNonNull(clazz)); + } catch (ClassCastException | BadTypeParcelableException e) { + typeWarning(key, clazz.getCanonicalName(), e); + return null; + } + } + + /** * Removes any entry with the given key from the mapping of this Bundle. * * @param key a String key @@ -982,15 +1046,19 @@ public class BaseBundle { } // Log a message if the value was non-null but not of the expected type - void typeWarning(String key, Object value, String className, - Object defaultValue, ClassCastException e) { + void typeWarning(String key, @Nullable Object value, String className, + Object defaultValue, RuntimeException e) { StringBuilder sb = new StringBuilder(); sb.append("Key "); sb.append(key); sb.append(" expected "); sb.append(className); - sb.append(" but value was a "); - sb.append(value.getClass().getName()); + if (value != null) { + sb.append(" but value was a "); + sb.append(value.getClass().getName()); + } else { + sb.append(" but value was of a different type"); + } sb.append(". The default value "); sb.append(defaultValue); sb.append(" was returned."); @@ -998,11 +1066,14 @@ public class BaseBundle { Log.w(TAG, "Attempt to cast generated internal exception:", e); } - void typeWarning(String key, Object value, String className, - ClassCastException e) { + void typeWarning(String key, @Nullable Object value, String className, RuntimeException e) { typeWarning(key, value, className, "<null>", e); } + void typeWarning(String key, String className, RuntimeException e) { + typeWarning(key, /* value */ null, className, "<null>", e); + } + /** * Returns the value associated with the given key, or defaultValue if * no mapping of the desired type exists for the given key. @@ -1342,7 +1413,11 @@ public class BaseBundle { * * @param key a String, or null * @return a Serializable value, or null + * + * @deprecated Use {@link #getSerializable(String, Class)}. This method should only be used in + * other deprecated APIs. */ + @Deprecated @Nullable Serializable getSerializable(@Nullable String key) { unparcel(); @@ -1359,6 +1434,36 @@ public class BaseBundle { } /** + * Returns the value associated with the given key, or {@code null} if: + * <ul> + * <li>No mapping of the desired type exists for the given key. + * <li>A {@code null} value is explicitly associated with the key. + * <li>The object is not of type {@code clazz}. + * </ul> + * + * @param key a String, or null + * @param clazz The expected class of the returned type + * @return a Serializable value, or null + */ + @Nullable + <T extends Serializable> T getSerializable(@Nullable String key, @NonNull Class<T> clazz) { + return get(key, clazz); + } + + + @SuppressWarnings("unchecked") + @Nullable + <T> ArrayList<T> getArrayList(@Nullable String key, @NonNull Class<? extends T> clazz) { + unparcel(); + try { + return getValue(key, ArrayList.class, requireNonNull(clazz)); + } catch (ClassCastException | BadTypeParcelableException e) { + typeWarning(key, "ArrayList<" + clazz.getCanonicalName() + ">", e); + return null; + } + } + + /** * Returns the value associated with the given key, or null if * no mapping of the desired type exists for the given key or a null * value is explicitly associated with the key. @@ -1368,17 +1473,7 @@ public class BaseBundle { */ @Nullable ArrayList<Integer> getIntegerArrayList(@Nullable String key) { - unparcel(); - Object o = getValue(key); - if (o == null) { - return null; - } - try { - return (ArrayList<Integer>) o; - } catch (ClassCastException e) { - typeWarning(key, o, "ArrayList<Integer>", e); - return null; - } + return getArrayList(key, Integer.class); } /** @@ -1391,17 +1486,7 @@ public class BaseBundle { */ @Nullable ArrayList<String> getStringArrayList(@Nullable String key) { - unparcel(); - Object o = getValue(key); - if (o == null) { - return null; - } - try { - return (ArrayList<String>) o; - } catch (ClassCastException e) { - typeWarning(key, o, "ArrayList<String>", e); - return null; - } + return getArrayList(key, String.class); } /** @@ -1414,17 +1499,7 @@ public class BaseBundle { */ @Nullable ArrayList<CharSequence> getCharSequenceArrayList(@Nullable String key) { - unparcel(); - Object o = getValue(key); - if (o == null) { - return null; - } - try { - return (ArrayList<CharSequence>) o; - } catch (ClassCastException e) { - typeWarning(key, o, "ArrayList<CharSequence>", e); - return null; - } + return getArrayList(key, CharSequence.class); } /** diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java index 2a2cbb996751..71c63ffd841c 100644 --- a/core/java/android/os/BinderProxy.java +++ b/core/java/android/os/BinderProxy.java @@ -516,12 +516,15 @@ public final class BinderProxy implements IBinder { public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { Binder.checkParcel(this, code, data, "Unreasonably large binder buffer"); - if (mWarnOnBlocking && ((flags & FLAG_ONEWAY) == 0) + boolean warnOnBlocking = mWarnOnBlocking; // Cache it to reduce volatile access. + + if (warnOnBlocking && ((flags & FLAG_ONEWAY) == 0) && Binder.sWarnOnBlockingOnCurrentThread.get()) { // For now, avoid spamming the log by disabling after we've logged // about this interface at least once mWarnOnBlocking = false; + warnOnBlocking = false; if (Build.IS_USERDEBUG) { // Log this as a WTF on userdebug builds. @@ -568,7 +571,13 @@ public final class BinderProxy implements IBinder { } try { - return transactNative(code, data, reply, flags); + final boolean result = transactNative(code, data, reply, flags); + + if (reply != null && !warnOnBlocking) { + reply.addFlags(Parcel.FLAG_IS_REPLY_FROM_BLOCKING_ALLOWED_OBJECT); + } + + return result; } finally { AppOpsManager.resumeNotedAppOpsCollection(prevCollection); diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index e519ff3a3739..03492aa56631 100755 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -31,6 +31,7 @@ import android.sysprop.DeviceProperties; import android.sysprop.SocProperties; import android.sysprop.TelephonyProperties; import android.text.TextUtils; +import android.util.ArraySet; import android.util.Slog; import android.view.View; @@ -39,6 +40,7 @@ import dalvik.system.VMRuntime; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.Set; import java.util.stream.Collectors; /** @@ -283,13 +285,20 @@ public class Build { public static final String RELEASE = getString("ro.build.version.release"); /** - * The version string we show to the user; may be {@link #RELEASE} or - * {@link #CODENAME} if not a final release build. + * The version string. May be {@link #RELEASE} or {@link #CODENAME} if + * not a final release build. */ @NonNull public static final String RELEASE_OR_CODENAME = getString( "ro.build.version.release_or_codename"); /** + * The version string we show to the user; may be {@link #RELEASE} or + * a descriptive string if not a final release build. + */ + @NonNull public static final String RELEASE_OR_PREVIEW_DISPLAY = getString( + "ro.build.version.release_or_preview_display"); + + /** * The base OS build the product is based on. */ public static final String BASE_OS = SystemProperties.get("ro.build.version.base_os", ""); @@ -396,6 +405,22 @@ public class Build { */ public static final String CODENAME = getString("ro.build.version.codename"); + /** + * All known codenames starting from {@link VERSION_CODES.Q}. + * + * <p>This includes in development codenames as well, i.e. if {@link #CODENAME} is not "REL" + * then the value of that is present in this set. + * + * <p>If a particular string is not present in this set, then it is either not a codename + * or a codename for a future release. For example, during Android R development, "Tiramisu" + * was not a known codename. + * + * @hide + */ + @SystemApi + @NonNull public static final Set<String> KNOWN_CODENAMES = + new ArraySet<>(getStringList("ro.build.version.known_codenames", ",")); + private static final String[] ALL_CODENAMES = getStringList("ro.build.version.all_codenames", ","); @@ -1024,7 +1049,7 @@ public class Build { * will also enable {@link StrictMode.ThreadPolicy.Builder#detectUnbufferedIo}.</li> * <li>{@link android.provider.DocumentsContract}'s various methods will throw failure * exceptions back to the caller instead of returning null. - * <li>{@link View#hasFocusable View.hasFocusable} now includes auto-focusable views.</li> + * <li>{@link View#hasFocusable() View.hasFocusable} now includes auto-focusable views.</li> * <li>{@link android.view.SurfaceView} will no longer always change the underlying * Surface object when something about it changes; apps need to look at the current * state of the object to determine which things they are interested in have changed.</li> @@ -1132,6 +1157,14 @@ public class Build { public static final int S = 31; /** + * S V2. + * + * Once more unto the breach, dear friends, once more. + * + */ + public static final int S_V2 = 32; + + /** * Tiramisu. */ public static final int TIRAMISU = CUR_DEVELOPMENT; diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java index b2bbfd6c163d..a19b51b7811b 100644 --- a/core/java/android/os/Bundle.java +++ b/core/java/android/os/Bundle.java @@ -16,7 +16,11 @@ package android.os; +import static java.util.Objects.requireNonNull; + +import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SuppressLint; import android.compat.annotation.UnsupportedAppUsage; import android.util.ArrayMap; import android.util.Size; @@ -873,7 +877,7 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { @Nullable public Bundle getBundle(@Nullable String key) { unparcel(); - Object o = getValue(key); + Object o = mMap.get(key); if (o == null) { return null; } @@ -896,7 +900,11 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { * * @param key a String, or {@code null} * @return a Parcelable value, or {@code null} + * + * @deprecated Use the type-safer {@link #getParcelable(String, Class)} starting from Android + * {@link Build.VERSION_CODES#TIRAMISU}. */ + @Deprecated @Nullable public <T extends Parcelable> T getParcelable(@Nullable String key) { unparcel(); @@ -913,6 +921,31 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { } /** + * Returns the value associated with the given key or {@code null} if: + * <ul> + * <li>No mapping of the desired type exists for the given key. + * <li>A {@code null} value is explicitly associated with the key. + * <li>The object is not of type {@code clazz}. + * </ul> + * + * <p><b>Note: </b> if the expected value is not a class provided by the Android platform, + * you must call {@link #setClassLoader(ClassLoader)} with the proper {@link ClassLoader} first. + * Otherwise, this method might throw an exception or return {@code null}. + * + * @param key a String, or {@code null} + * @param clazz The type of the object expected + * @return a Parcelable value, or {@code null} + */ + @SuppressWarnings("unchecked") + @Nullable + public <T> T getParcelable(@Nullable String key, @NonNull Class<T> clazz) { + // The reason for not using <T extends Parcelable> is because the caller could provide a + // super class to restrict the children that doesn't implement Parcelable itself while the + // children do, more details at b/210800751 (same reasoning applies here). + return get(key, clazz); + } + + /** * Returns the value associated with the given key, or {@code null} if * no mapping of the desired type exists for the given key or a null * value is explicitly associated with the key. @@ -923,7 +956,11 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { * * @param key a String, or {@code null} * @return a Parcelable[] value, or {@code null} + * + * @deprecated Use the type-safer {@link #getParcelableArray(String, Class)} starting from + * Android {@link Build.VERSION_CODES#TIRAMISU}. */ + @Deprecated @Nullable public Parcelable[] getParcelableArray(@Nullable String key) { unparcel(); @@ -940,6 +977,39 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { } /** + * Returns the value associated with the given key, or {@code null} if: + * <ul> + * <li>No mapping of the desired type exists for the given key. + * <li>A {@code null} value is explicitly associated with the key. + * <li>The object is not of type {@code clazz}. + * </ul> + * + * <p><b>Note: </b> if the expected value is not a class provided by the Android platform, + * you must call {@link #setClassLoader(ClassLoader)} with the proper {@link ClassLoader} first. + * Otherwise, this method might throw an exception or return {@code null}. + * + * @param key a String, or {@code null} + * @param clazz The type of the items inside the array + * @return a Parcelable[] value, or {@code null} + */ + @SuppressLint({"ArrayReturn", "NullableCollection"}) + @SuppressWarnings("unchecked") + @Nullable + public <T> T[] getParcelableArray(@Nullable String key, @NonNull Class<T> clazz) { + // The reason for not using <T extends Parcelable> is because the caller could provide a + // super class to restrict the children that doesn't implement Parcelable itself while the + // children do, more details at b/210800751 (same reasoning applies here). + unparcel(); + try { + // In Java 12, we can pass clazz.arrayType() instead of Parcelable[] and later casting. + return (T[]) getValue(key, Parcelable[].class, requireNonNull(clazz)); + } catch (ClassCastException | BadTypeParcelableException e) { + typeWarning(key, clazz.getCanonicalName() + "[]", e); + return null; + } + } + + /** * Returns the value associated with the given key, or {@code null} if * no mapping of the desired type exists for the given key or a {@code null} * value is explicitly associated with the key. @@ -950,7 +1020,11 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { * * @param key a String, or {@code null} * @return an ArrayList<T> value, or {@code null} + * + * @deprecated Use the type-safer {@link #getParcelable(String, Class)} starting from Android + * {@link Build.VERSION_CODES#TIRAMISU}. */ + @Deprecated @Nullable public <T extends Parcelable> ArrayList<T> getParcelableArrayList(@Nullable String key) { unparcel(); @@ -967,14 +1041,44 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { } /** + * Returns the value associated with the given key, or {@code null} if: + * <ul> + * <li>No mapping of the desired type exists for the given key. + * <li>A {@code null} value is explicitly associated with the key. + * <li>The object is not of type {@code clazz}. + * </ul> + * + * <p><b>Note: </b> if the expected value is not a class provided by the Android platform, + * you must call {@link #setClassLoader(ClassLoader)} with the proper {@link ClassLoader} first. + * Otherwise, this method might throw an exception or return {@code null}. + * + * @param key a String, or {@code null} + * @param clazz The type of the items inside the array list + * @return an ArrayList<T> value, or {@code null} + */ + @SuppressLint("NullableCollection") + @SuppressWarnings("unchecked") + @Nullable + public <T> ArrayList<T> getParcelableArrayList(@Nullable String key, + @NonNull Class<? extends T> clazz) { + // The reason for not using <T extends Parcelable> is because the caller could provide a + // super class to restrict the children that doesn't implement Parcelable itself while the + // children do, more details at b/210800751 (same reasoning applies here). + return getArrayList(key, clazz); + } + + /** * Returns the value associated with the given key, or null if * no mapping of the desired type exists for the given key or a null * value is explicitly associated with the key. * * @param key a String, or null - * * @return a SparseArray of T values, or null + * + * @deprecated Use the type-safer {@link #getSparseParcelableArray(String, Class)} starting from + * Android {@link Build.VERSION_CODES#TIRAMISU}. */ + @Deprecated @Nullable public <T extends Parcelable> SparseArray<T> getSparseParcelableArray(@Nullable String key) { unparcel(); @@ -991,13 +1095,44 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { } /** + * Returns the value associated with the given key, or {@code null} if: + * <ul> + * <li>No mapping of the desired type exists for the given key. + * <li>A {@code null} value is explicitly associated with the key. + * <li>The object is not of type {@code clazz}. + * </ul> + * + * @param key a String, or null + * @return a SparseArray of T values, or null + */ + @SuppressWarnings("unchecked") + @Nullable + public <T> SparseArray<T> getSparseParcelableArray(@Nullable String key, + @NonNull Class<? extends T> clazz) { + // The reason for not using <T extends Parcelable> is because the caller could provide a + // super class to restrict the children that doesn't implement Parcelable itself while the + // children do, more details at b/210800751 (same reasoning applies here). + unparcel(); + try { + return (SparseArray<T>) getValue(key, SparseArray.class, requireNonNull(clazz)); + } catch (ClassCastException | BadTypeParcelableException e) { + typeWarning(key, "SparseArray<" + clazz.getCanonicalName() + ">", e); + return null; + } + } + + /** * Returns the value associated with the given key, or null if * no mapping of the desired type exists for the given key or a null * value is explicitly associated with the key. * * @param key a String, or null * @return a Serializable value, or null + * + * @deprecated Use the type-safer {@link #getSerializable(String, Class)} starting from Android + * {@link Build.VERSION_CODES#TIRAMISU}. */ + @Deprecated @Override @Nullable public Serializable getSerializable(@Nullable String key) { @@ -1005,6 +1140,24 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { } /** + * Returns the value associated with the given key, or {@code null} if: + * <ul> + * <li>No mapping of the desired type exists for the given key. + * <li>A {@code null} value is explicitly associated with the key. + * <li>The object is not of type {@code clazz}. + * </ul> + * + * @param key a String, or null + * @param clazz The expected class of the returned type + * @return a Serializable value, or null + */ + @Nullable + public <T extends Serializable> T getSerializable(@Nullable String key, + @NonNull Class<T> clazz) { + return super.getSerializable(key, requireNonNull(clazz)); + } + + /** * Returns the value associated with the given key, or null if * no mapping of the desired type exists for the given key or a null * value is explicitly associated with the key. diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index 2ed0bad69460..2f2f65bbe9d2 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -101,6 +101,7 @@ public class Environment { private static final File DIR_ANDROID_EXPAND = getDirectory(ENV_ANDROID_EXPAND, "/mnt/expand"); private static final File DIR_ANDROID_STORAGE = getDirectory(ENV_ANDROID_STORAGE, "/storage"); private static final File DIR_DOWNLOAD_CACHE = getDirectory(ENV_DOWNLOAD_CACHE, "/cache"); + private static final File DIR_METADATA = new File("/metadata"); private static final File DIR_OEM_ROOT = getDirectory(ENV_OEM_ROOT, "/oem"); private static final File DIR_ODM_ROOT = getDirectory(ENV_ODM_ROOT, "/odm"); private static final File DIR_VENDOR_ROOT = getDirectory(ENV_VENDOR_ROOT, "/vendor"); @@ -1102,6 +1103,15 @@ public class Environment { } /** + * Return the metadata directory. + * + * @hide + */ + public static @NonNull File getMetadataDirectory() { + return DIR_METADATA; + } + + /** * Unknown storage state, such as when a path isn't backed by known storage * media. * diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS index 5d9f2189df1b..8e5ed8f6e578 100644 --- a/core/java/android/os/OWNERS +++ b/core/java/android/os/OWNERS @@ -52,6 +52,9 @@ per-file *Power* = file:/services/core/java/com/android/server/power/OWNERS per-file *Telephony* = file:/telephony/OWNERS per-file *Zygote* = file:/ZYGOTE_OWNERS +# Time +per-file *Clock* = file:/services/core/java/com/android/server/timezonedetector/OWNERS + # RecoverySystem per-file *Recovery* = file:/services/core/java/com/android/server/recoverysystem/OWNERS diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 09eac79c991e..9b03172a45d6 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -16,8 +16,11 @@ package android.os; +import static com.android.internal.util.Preconditions.checkArgument; + import static java.util.Objects.requireNonNull; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; @@ -53,6 +56,8 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamClass; import java.io.Serializable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -62,6 +67,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.IntFunction; import java.util.function.Supplier; @@ -195,7 +201,7 @@ import java.util.function.Supplier; * The methods to use are {@link #writeFileDescriptor(FileDescriptor)}, * {@link #readFileDescriptor()}. * - * <h3>Untyped Containers</h3> + * <h3>Parcelable Containers</h3> * * <p>A final class of methods are for writing and reading standard Java * containers of arbitrary types. These all revolve around the @@ -207,6 +213,19 @@ import java.util.function.Supplier; * {@link #writeMap(Map)}, {@link #readMap(Map, ClassLoader)}, * {@link #writeSparseArray(SparseArray)}, * {@link #readSparseArray(ClassLoader)}. + * + * <h3>Restricted Parcelable Containers</h3> + * + * <p>A final class of methods are for reading standard Java containers of restricted types. + * These methods replace methods for reading containers of arbitrary types from previous section + * starting from Android {@link Build.VERSION_CODES#TIRAMISU}. The pairing writing methods are + * still the same from previous section. + * These methods accepts additional {@code clazz} parameters as the required types. + * The Restricted Parcelable container methods are {@link #readArray(ClassLoader, Class)}, + * {@link #readList(List, ClassLoader, Class)}, + * {@link #readArrayList(ClassLoader, Class)}, + * {@link #readMap(Map, ClassLoader, Class, Class)}, + * {@link #readSparseArray(ClassLoader, Class)}. */ public final class Parcel { @@ -229,6 +248,25 @@ public final class Parcel { private RuntimeException mStack; + /** @hide */ + @TestApi + public static final int FLAG_IS_REPLY_FROM_BLOCKING_ALLOWED_OBJECT = 1 << 0; + + /** @hide */ + @TestApi + public static final int FLAG_PROPAGATE_ALLOW_BLOCKING = 1 << 1; + + /** @hide */ + @IntDef(flag = true, prefix = { "FLAG_" }, value = { + FLAG_IS_REPLY_FROM_BLOCKING_ALLOWED_OBJECT, + FLAG_PROPAGATE_ALLOW_BLOCKING, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ParcelFlags {} + + @ParcelFlags + private int mFlags; + /** * Whether or not to parcel the stack trace of an exception. This has a performance * impact, so should only be included in specific processes and only on debug builds. @@ -265,26 +303,26 @@ public final class Parcel { private static final int VAL_NULL = -1; private static final int VAL_STRING = 0; private static final int VAL_INTEGER = 1; - private static final int VAL_MAP = 2; + private static final int VAL_MAP = 2; // length-prefixed private static final int VAL_BUNDLE = 3; - private static final int VAL_PARCELABLE = 4; + private static final int VAL_PARCELABLE = 4; // length-prefixed private static final int VAL_SHORT = 5; private static final int VAL_LONG = 6; private static final int VAL_FLOAT = 7; private static final int VAL_DOUBLE = 8; private static final int VAL_BOOLEAN = 9; private static final int VAL_CHARSEQUENCE = 10; - private static final int VAL_LIST = 11; - private static final int VAL_SPARSEARRAY = 12; + private static final int VAL_LIST = 11; // length-prefixed + private static final int VAL_SPARSEARRAY = 12; // length-prefixed private static final int VAL_BYTEARRAY = 13; private static final int VAL_STRINGARRAY = 14; private static final int VAL_IBINDER = 15; - private static final int VAL_PARCELABLEARRAY = 16; - private static final int VAL_OBJECTARRAY = 17; + private static final int VAL_PARCELABLEARRAY = 16; // length-prefixed + private static final int VAL_OBJECTARRAY = 17; // length-prefixed private static final int VAL_INTARRAY = 18; private static final int VAL_LONGARRAY = 19; private static final int VAL_BYTE = 20; - private static final int VAL_SERIALIZABLE = 21; + private static final int VAL_SERIALIZABLE = 21; // length-prefixed private static final int VAL_SPARSEBOOLEANARRAY = 22; private static final int VAL_BOOLEANARRAY = 23; private static final int VAL_CHARSEQUENCEARRAY = 24; @@ -585,6 +623,40 @@ public final class Parcel { nativeMarkForBinder(mNativePtr, binder); } + /** @hide */ + @ParcelFlags + @TestApi + public int getFlags() { + return mFlags; + } + + /** @hide */ + public void setFlags(@ParcelFlags int flags) { + mFlags = flags; + } + + /** @hide */ + public void addFlags(@ParcelFlags int flags) { + mFlags |= flags; + } + + /** @hide */ + private boolean hasFlags(@ParcelFlags int flags) { + return (mFlags & flags) == flags; + } + + /** + * This method is used by the AIDL compiler for system components. Not intended to be + * used by non-system apps. + */ + // Note: Ideally this method should be @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES), + // but we need to make this method public due to the way the aidl compiler is compiled. + // We don't really need to protect it; even if 3p / non-system apps, nothing would happen. + // This would only work when used on a reply parcel by a binder object that's allowed-blocking. + public void setPropagateAllowBlocking() { + addFlags(FLAG_PROPAGATE_ALLOW_BLOCKING); + } + /** * Returns the total amount of data contained in the parcel. */ @@ -2079,6 +2151,102 @@ public final class Parcel { } /** + * Flatten a homogeneous multi-dimensional array with fixed-size. This delegates to other + * APIs to write a one-dimensional array. Use {@link #readFixedArray(Object)} or + * {@link #createFixedArray(Class, int[])} with the same dimensions to unmarshal. + * + * @param val The array to be written. + * @param parcelableFlags Contextual flags as per + * {@link Parcelable#writeToParcel(Parcel, int) Parcelable.writeToParcel()}. + * Used only if val is an array of Parcelable objects. + * @param dimensions an array of int representing length of each dimension. The array should be + * sized with the exact size of dimensions. + * + * @see #readFixedArray + * @see #createFixedArray + * @see #writeBooleanArray + * @see #writeByteArray + * @see #writeCharArray + * @see #writeIntArray + * @see #writeLongArray + * @see #writeFloatArray + * @see #writeDoubleArray + * @see #writeBinderArray + * @see #writeInterfaceArray + * @see #writeTypedArray + * @throws BadParcelableException If the array's component type is not supported or if its + * size doesn't match with the given dimensions. + */ + public <T> void writeFixedArray(@Nullable T val, int parcelableFlags, + @NonNull int... dimensions) { + if (val == null) { + writeInt(-1); + return; + } + writeFixedArrayInternal(val, parcelableFlags, /*index=*/0, dimensions); + } + + private <T> void writeFixedArrayInternal(T val, int parcelableFlags, int index, + int[] dimensions) { + if (index >= dimensions.length) { + throw new BadParcelableException("Array has more dimensions than expected: " + + dimensions.length); + } + + int length = dimensions[index]; + + // val should be an array of length N + if (val == null) { + throw new BadParcelableException("Non-null array shouldn't have a null array."); + } + if (!val.getClass().isArray()) { + throw new BadParcelableException("Not an array: " + val); + } + if (Array.getLength(val) != length) { + throw new BadParcelableException("bad length: expected " + length + ", but got " + + Array.getLength(val)); + } + + // Delegates to other writers if this is a one-dimensional array. + // Otherwise, write component arrays with recursive calls. + + final Class<?> componentType = val.getClass().getComponentType(); + if (!componentType.isArray() && index + 1 != dimensions.length) { + throw new BadParcelableException("Array has fewer dimensions than expected: " + + dimensions.length); + } + if (componentType == boolean.class) { + writeBooleanArray((boolean[]) val); + } else if (componentType == byte.class) { + writeByteArray((byte[]) val); + } else if (componentType == char.class) { + writeCharArray((char[]) val); + } else if (componentType == int.class) { + writeIntArray((int[]) val); + } else if (componentType == long.class) { + writeLongArray((long[]) val); + } else if (componentType == float.class) { + writeFloatArray((float[]) val); + } else if (componentType == double.class) { + writeDoubleArray((double[]) val); + } else if (componentType == IBinder.class) { + writeBinderArray((IBinder[]) val); + } else if (IInterface.class.isAssignableFrom(componentType)) { + writeInterfaceArray((IInterface[]) val); + } else if (Parcelable.class.isAssignableFrom(componentType)) { + writeTypedArray((Parcelable[]) val, parcelableFlags); + } else if (componentType.isArray()) { + writeInt(length); + for (int i = 0; i < length; i++) { + writeFixedArrayInternal(Array.get(val, i), parcelableFlags, index + 1, + dimensions); + } + } else { + throw new BadParcelableException("unknown type for fixed-size array: " + componentType); + } + } + + /** * Flatten a generic object in to a parcel. The given Object value may * currently be one of the following types: * @@ -2940,7 +3108,15 @@ public final class Parcel { * Read an object from the parcel at the current dataPosition(). */ public final IBinder readStrongBinder() { - return nativeReadStrongBinder(mNativePtr); + final IBinder result = nativeReadStrongBinder(mNativePtr); + + // If it's a reply from a method with @PropagateAllowBlocking, then inherit allow-blocking + // from the object that returned it. + if (result != null && hasFlags( + FLAG_IS_REPLY_FROM_BLOCKING_ALLOWED_OBJECT | FLAG_PROPAGATE_ALLOW_BLOCKING)) { + Binder.allowBlocking(result); + } + return result; } /** @@ -3010,8 +3186,7 @@ public final class Parcel { */ @Deprecated public final void readMap(@NonNull Map outVal, @Nullable ClassLoader loader) { - int n = readInt(); - readMapInternal(outVal, n, loader, /* clazzKey */ null, /* clazzValue */ null); + readMapInternal(outVal, loader, /* clazzKey */ null, /* clazzValue */ null); } /** @@ -3026,8 +3201,7 @@ public final class Parcel { @NonNull Class<V> clazzValue) { Objects.requireNonNull(clazzKey); Objects.requireNonNull(clazzValue); - int n = readInt(); - readMapInternal(outVal, n, loader, clazzKey, clazzValue); + readMapInternal(outVal, loader, clazzKey, clazzValue); } /** @@ -3076,13 +3250,7 @@ public final class Parcel { @Deprecated @Nullable public HashMap readHashMap(@Nullable ClassLoader loader) { - int n = readInt(); - if (n < 0) { - return null; - } - HashMap m = new HashMap(n); - readMapInternal(m, n, loader, /* clazzKey */ null, /* clazzValue */ null); - return m; + return readHashMapInternal(loader, /* clazzKey */ null, /* clazzValue */ null); } /** @@ -3098,13 +3266,7 @@ public final class Parcel { @NonNull Class<? extends K> clazzKey, @NonNull Class<? extends V> clazzValue) { Objects.requireNonNull(clazzKey); Objects.requireNonNull(clazzValue); - int n = readInt(); - if (n < 0) { - return null; - } - HashMap<K, V> map = new HashMap<>(n); - readMapInternal(map, n, loader, clazzKey, clazzValue); - return map; + return readHashMapInternal(loader, clazzKey, clazzValue); } /** @@ -3683,7 +3845,7 @@ public final class Parcel { */ @NonNull public <T> List<T> readParcelableList(@NonNull List<T> list, - @Nullable ClassLoader cl, @NonNull Class<T> clazz) { + @Nullable ClassLoader cl, @NonNull Class<? extends T> clazz) { Objects.requireNonNull(list); Objects.requireNonNull(clazz); return readParcelableListInternal(list, cl, clazz); @@ -3694,7 +3856,7 @@ public final class Parcel { */ @NonNull private <T> List<T> readParcelableListInternal(@NonNull List<T> list, - @Nullable ClassLoader cl, @Nullable Class<T> clazz) { + @Nullable ClassLoader cl, @Nullable Class<? extends T> clazz) { final int n = readInt(); if (n == -1) { list.clear(); @@ -3781,6 +3943,317 @@ public final class Parcel { } /** + * Read a new multi-dimensional array from a parcel. If you want to read Parcelable or + * IInterface values, use {@link #readFixedArray(Object, Parcelable.Creator)} or + * {@link #readFixedArray(Object, Function)}. + * @param val the destination array to hold the read values. + * + * @see #writeTypedArray + * @see #readBooleanArray + * @see #readByteArray + * @see #readCharArray + * @see #readIntArray + * @see #readLongArray + * @see #readFloatArray + * @see #readDoubleArray + * @see #readBinderArray + * @see #readInterfaceArray + * @see #readTypedArray + */ + public <T> void readFixedArray(@NonNull T val) { + Class<?> componentType = val.getClass().getComponentType(); + if (componentType == boolean.class) { + readBooleanArray((boolean[]) val); + } else if (componentType == byte.class) { + readByteArray((byte[]) val); + } else if (componentType == char.class) { + readCharArray((char[]) val); + } else if (componentType == int.class) { + readIntArray((int[]) val); + } else if (componentType == long.class) { + readLongArray((long[]) val); + } else if (componentType == float.class) { + readFloatArray((float[]) val); + } else if (componentType == double.class) { + readDoubleArray((double[]) val); + } else if (componentType == IBinder.class) { + readBinderArray((IBinder[]) val); + } else if (componentType.isArray()) { + int length = readInt(); + if (length != Array.getLength(val)) { + throw new BadParcelableException("Bad length: expected " + Array.getLength(val) + + ", but got " + length); + } + for (int i = 0; i < length; i++) { + readFixedArray(Array.get(val, i)); + } + } else { + throw new BadParcelableException("Unknown type for fixed-size array: " + componentType); + } + } + + /** + * Read a new multi-dimensional array of typed interfaces from a parcel. + * If you want to read Parcelable values, use + * {@link #readFixedArray(Object, Parcelable.Creator)}. For values of other types, use + * {@link #readFixedArray(Object)}. + * @param val the destination array to hold the read values. + */ + public <T, S extends IInterface> void readFixedArray(@NonNull T val, + @NonNull Function<IBinder, S> asInterface) { + Class<?> componentType = val.getClass().getComponentType(); + if (IInterface.class.isAssignableFrom(componentType)) { + readInterfaceArray((S[]) val, asInterface); + } else if (componentType.isArray()) { + int length = readInt(); + if (length != Array.getLength(val)) { + throw new BadParcelableException("Bad length: expected " + Array.getLength(val) + + ", but got " + length); + } + for (int i = 0; i < length; i++) { + readFixedArray(Array.get(val, i), asInterface); + } + } else { + throw new BadParcelableException("Unknown type for fixed-size array: " + componentType); + } + } + + /** + * Read a new multi-dimensional array of typed parcelables from a parcel. + * If you want to read IInterface values, use + * {@link #readFixedArray(Object, Function)}. For values of other types, use + * {@link #readFixedArray(Object)}. + * @param val the destination array to hold the read values. + */ + public <T, S extends Parcelable> void readFixedArray(@NonNull T val, + @NonNull Parcelable.Creator<S> c) { + Class<?> componentType = val.getClass().getComponentType(); + if (Parcelable.class.isAssignableFrom(componentType)) { + readTypedArray((S[]) val, c); + } else if (componentType.isArray()) { + int length = readInt(); + if (length != Array.getLength(val)) { + throw new BadParcelableException("Bad length: expected " + Array.getLength(val) + + ", but got " + length); + } + for (int i = 0; i < length; i++) { + readFixedArray(Array.get(val, i), c); + } + } else { + throw new BadParcelableException("Unknown type for fixed-size array: " + componentType); + } + } + + private void ensureClassHasExpectedDimensions(@NonNull Class<?> cls, int numDimension) { + if (numDimension <= 0) { + throw new BadParcelableException("Fixed-size array should have dimensions."); + } + + for (int i = 0; i < numDimension; i++) { + if (!cls.isArray()) { + throw new BadParcelableException("Array has fewer dimensions than expected: " + + numDimension); + } + cls = cls.getComponentType(); + } + if (cls.isArray()) { + throw new BadParcelableException("Array has more dimensions than expected: " + + numDimension); + } + } + + /** + * Read and return a new multi-dimensional array from a parcel. Returns null if the + * previously written array object is null. If you want to read Parcelable or + * IInterface values, use {@link #createFixedArray(Class, Parcelable.Creator, int[])} or + * {@link #createFixedArray(Class, Function, int[])}. + * @param cls the Class object for the target array type. (e.g. int[][].class) + * @param dimensions an array of int representing length of each dimension. + * + * @see #writeTypedArray + * @see #createBooleanArray + * @see #createByteArray + * @see #createCharArray + * @see #createIntArray + * @see #createLongArray + * @see #createFloatArray + * @see #createDoubleArray + * @see #createBinderArray + * @see #createInterfaceArray + * @see #createTypedArray + */ + @Nullable + public <T> T createFixedArray(@NonNull Class<T> cls, @NonNull int... dimensions) { + // Check if type matches with dimensions + // If type is one-dimensional array, delegate to other creators + // Otherwise, create an multi-dimensional array at once and then fill it with readFixedArray + + ensureClassHasExpectedDimensions(cls, dimensions.length); + + T val = null; + final Class<?> componentType = cls.getComponentType(); + if (componentType == boolean.class) { + val = (T) createBooleanArray(); + } else if (componentType == byte.class) { + val = (T) createByteArray(); + } else if (componentType == char.class) { + val = (T) createCharArray(); + } else if (componentType == int.class) { + val = (T) createIntArray(); + } else if (componentType == long.class) { + val = (T) createLongArray(); + } else if (componentType == float.class) { + val = (T) createFloatArray(); + } else if (componentType == double.class) { + val = (T) createDoubleArray(); + } else if (componentType == IBinder.class) { + val = (T) createBinderArray(); + } else if (componentType.isArray()) { + int length = readInt(); + if (length < 0) { + return null; + } + if (length != dimensions[0]) { + throw new BadParcelableException("Bad length: expected " + dimensions[0] + + ", but got " + length); + } + + // Create a multi-dimensional array with an innermost component type and dimensions + Class<?> innermost = componentType.getComponentType(); + while (innermost.isArray()) { + innermost = innermost.getComponentType(); + } + val = (T) Array.newInstance(innermost, dimensions); + for (int i = 0; i < length; i++) { + readFixedArray(Array.get(val, i)); + } + return val; + } else { + throw new BadParcelableException("Unknown type for fixed-size array: " + componentType); + } + + // Check if val is null (which is OK) or has the expected size. + // This check doesn't have to be multi-dimensional because multi-dimensional arrays + // are created with expected dimensions. + if (val != null && Array.getLength(val) != dimensions[0]) { + throw new BadParcelableException("Bad length: expected " + dimensions[0] + ", but got " + + Array.getLength(val)); + } + return val; + } + + /** + * Read and return a new multi-dimensional array of typed interfaces from a parcel. + * Returns null if the previously written array object is null. If you want to read + * Parcelable values, use {@link #createFixedArray(Class, Parcelable.Creator, int[])}. + * For values of other types use {@link #createFixedArray(Class, int[])}. + * @param cls the Class object for the target array type. (e.g. IFoo[][].class) + * @param dimensions an array of int representing length of each dimension. + */ + @Nullable + public <T, S extends IInterface> T createFixedArray(@NonNull Class<T> cls, + @NonNull Function<IBinder, S> asInterface, @NonNull int... dimensions) { + // Check if type matches with dimensions + // If type is one-dimensional array, delegate to other creators + // Otherwise, create an multi-dimensional array at once and then fill it with readFixedArray + + ensureClassHasExpectedDimensions(cls, dimensions.length); + + T val = null; + final Class<?> componentType = cls.getComponentType(); + if (IInterface.class.isAssignableFrom(componentType)) { + val = (T) createInterfaceArray(n -> (S[]) Array.newInstance(componentType, n), + asInterface); + } else if (componentType.isArray()) { + int length = readInt(); + if (length < 0) { + return null; + } + if (length != dimensions[0]) { + throw new BadParcelableException("Bad length: expected " + dimensions[0] + + ", but got " + length); + } + + // Create a multi-dimensional array with an innermost component type and dimensions + Class<?> innermost = componentType.getComponentType(); + while (innermost.isArray()) { + innermost = innermost.getComponentType(); + } + val = (T) Array.newInstance(innermost, dimensions); + for (int i = 0; i < length; i++) { + readFixedArray(Array.get(val, i), asInterface); + } + return val; + } else { + throw new BadParcelableException("Unknown type for fixed-size array: " + componentType); + } + + // Check if val is null (which is OK) or has the expected size. + // This check doesn't have to be multi-dimensional because multi-dimensional arrays + // are created with expected dimensions. + if (val != null && Array.getLength(val) != dimensions[0]) { + throw new BadParcelableException("Bad length: expected " + dimensions[0] + ", but got " + + Array.getLength(val)); + } + return val; + } + + /** + * Read and return a new multi-dimensional array of typed parcelables from a parcel. + * Returns null if the previously written array object is null. If you want to read + * IInterface values, use {@link #createFixedArray(Class, Function, int[])}. + * For values of other types use {@link #createFixedArray(Class, int[])}. + * @param cls the Class object for the target array type. (e.g. Foo[][].class) + * @param dimensions an array of int representing length of each dimension. + */ + @Nullable + public <T, S extends Parcelable> T createFixedArray(@NonNull Class<T> cls, + @NonNull Parcelable.Creator<S> c, @NonNull int... dimensions) { + // Check if type matches with dimensions + // If type is one-dimensional array, delegate to other creators + // Otherwise, create an multi-dimensional array at once and then fill it with readFixedArray + + ensureClassHasExpectedDimensions(cls, dimensions.length); + + T val = null; + final Class<?> componentType = cls.getComponentType(); + if (Parcelable.class.isAssignableFrom(componentType)) { + val = (T) createTypedArray(c); + } else if (componentType.isArray()) { + int length = readInt(); + if (length < 0) { + return null; + } + if (length != dimensions[0]) { + throw new BadParcelableException("Bad length: expected " + dimensions[0] + + ", but got " + length); + } + + // Create a multi-dimensional array with an innermost component type and dimensions + Class<?> innermost = componentType.getComponentType(); + while (innermost.isArray()) { + innermost = innermost.getComponentType(); + } + val = (T) Array.newInstance(innermost, dimensions); + for (int i = 0; i < length; i++) { + readFixedArray(Array.get(val, i), c); + } + return val; + } else { + throw new BadParcelableException("Unknown type for fixed-size array: " + componentType); + } + + // Check if val is null (which is OK) or has the expected size. + // This check doesn't have to be multi-dimensional because multi-dimensional arrays + // are created with expected dimensions. + if (val != null && Array.getLength(val) != dimensions[0]) { + throw new BadParcelableException("Bad length: expected " + dimensions[0] + ", but got " + + Array.getLength(val)); + } + return val; + } + + /** * Write a heterogeneous array of Parcelable objects into the Parcel. * Each object in the array is written along with its class name, so * that the correct class can later be instantiated. As a result, this @@ -3818,16 +4291,17 @@ public final class Parcel { /** - * @param clazz The type of the object expected or {@code null} for performing no checks. + * @see #readValue(int, ClassLoader, Class, Class[]) */ @Nullable - private <T> T readValue(@Nullable ClassLoader loader, @Nullable Class<T> clazz) { + private <T> T readValue(@Nullable ClassLoader loader, @Nullable Class<T> clazz, + @Nullable Class<?>... itemTypes) { int type = readInt(); final T object; if (isLengthPrefixed(type)) { int length = readInt(); int start = dataPosition(); - object = readValue(type, loader, clazz); + object = readValue(type, loader, clazz, itemTypes); int actual = dataPosition() - start; if (actual != length) { Slog.wtfStack(TAG, @@ -3835,24 +4309,26 @@ public final class Parcel { + " consumed " + actual + " bytes, but " + length + " expected."); } } else { - object = readValue(type, loader, clazz); + object = readValue(type, loader, clazz, itemTypes); } return object; } /** - * This will return a {@link Supplier} for length-prefixed types that deserializes the object - * when {@link Supplier#get()} is called, for other types it will return the object itself. + * This will return a {@link BiFunction} for length-prefixed types that deserializes the object + * when {@link BiFunction#apply} is called (the arguments correspond to the ones of {@link + * #readValue(int, ClassLoader, Class, Class[])} after the class loader), for other types it + * will return the object itself. * - * <p>After calling {@link Supplier#get()} the parcel cursor will not change. Note that you + * <p>After calling {@link BiFunction#apply} the parcel cursor will not change. Note that you * shouldn't recycle the parcel, not at least until all objects have been retrieved. No * synchronization attempts are made. * - * </p>The supplier returned implements {@link #equals(Object)} and {@link #hashCode()}. Two - * suppliers are equal if either of the following is true: + * </p>The function returned implements {@link #equals(Object)} and {@link #hashCode()}. Two + * function objects are equal if either of the following is true: * <ul> - * <li>{@link Supplier#get()} has been called on both and both objects returned are equal. - * <li>{@link Supplier#get()} hasn't been called on either one and everything below is true: + * <li>{@link BiFunction#apply} has been called on both and both objects returned are equal. + * <li>{@link BiFunction#apply} hasn't been called on either one and everything below is true: * <ul> * <li>The {@code loader} parameters used to retrieve each are equal. * <li>They both have the same type. @@ -3879,7 +4355,7 @@ public final class Parcel { } - private static final class LazyValue implements Supplier<Object> { + private static final class LazyValue implements BiFunction<Class<?>, Class<?>[], Object> { /** * | 4B | 4B | * mSource = Parcel{... | type | length | object | ...} @@ -3911,7 +4387,7 @@ public final class Parcel { } @Override - public Object get() { + public Object apply(@Nullable Class<?> clazz, @Nullable Class<?>[] itemTypes) { Parcel source = mSource; if (source != null) { synchronized (source) { @@ -3920,7 +4396,7 @@ public final class Parcel { int restore = source.dataPosition(); try { source.setDataPosition(mPosition); - mObject = source.readValue(mLoader); + mObject = source.readValue(mLoader, clazz, itemTypes); } finally { source.setDataPosition(restore); } @@ -4000,14 +4476,25 @@ public final class Parcel { } } + /** Same as {@link #readValue(ClassLoader, Class, Class[])} without any item types. */ + private <T> T readValue(int type, @Nullable ClassLoader loader, @Nullable Class<T> clazz) { + // Avoids allocating Class[0] array + return readValue(type, loader, clazz, (Class<?>[]) null); + } + /** * Reads a value from the parcel of type {@code type}. Does NOT read the int representing the * type first. + * * @param clazz The type of the object expected or {@code null} for performing no checks. + * @param itemTypes If the value is a container, these represent the item types (eg. for a list + * it's the item type, for a map, it's the key type, followed by the value + * type). */ @SuppressWarnings("unchecked") @Nullable - private <T> T readValue(int type, @Nullable ClassLoader loader, @Nullable Class<T> clazz) { + private <T> T readValue(int type, @Nullable ClassLoader loader, @Nullable Class<T> clazz, + @Nullable Class<?>... itemTypes) { final Object object; switch (type) { case VAL_NULL: @@ -4023,7 +4510,11 @@ public final class Parcel { break; case VAL_MAP: - object = readHashMap(loader); + checkTypeToUnparcel(clazz, HashMap.class); + Class<?> keyType = ArrayUtils.getOrNull(itemTypes, 0); + Class<?> valueType = ArrayUtils.getOrNull(itemTypes, 1); + checkArgument((keyType == null) == (valueType == null)); + object = readHashMapInternal(loader, keyType, valueType); break; case VAL_PARCELABLE: @@ -4054,10 +4545,12 @@ public final class Parcel { object = readCharSequence(); break; - case VAL_LIST: - object = readArrayList(loader); + case VAL_LIST: { + checkTypeToUnparcel(clazz, ArrayList.class); + Class<?> itemType = ArrayUtils.getOrNull(itemTypes, 0); + object = readArrayListInternal(loader, itemType); break; - + } case VAL_BOOLEANARRAY: object = createBooleanArray(); break; @@ -4078,10 +4571,12 @@ public final class Parcel { object = readStrongBinder(); break; - case VAL_OBJECTARRAY: - object = readArray(loader); + case VAL_OBJECTARRAY: { + Class<?> itemType = ArrayUtils.getOrNull(itemTypes, 0); + checkArrayTypeToUnparcel(clazz, (itemType != null) ? itemType : Object.class); + object = readArrayInternal(loader, itemType); break; - + } case VAL_INTARRAY: object = createIntArray(); break; @@ -4098,14 +4593,18 @@ public final class Parcel { object = readSerializableInternal(loader, clazz); break; - case VAL_PARCELABLEARRAY: - object = readParcelableArray(loader); + case VAL_PARCELABLEARRAY: { + Class<?> itemType = ArrayUtils.getOrNull(itemTypes, 0); + checkArrayTypeToUnparcel(clazz, (itemType != null) ? itemType : Parcelable.class); + object = readParcelableArrayInternal(loader, itemType); break; - - case VAL_SPARSEARRAY: - object = readSparseArray(loader); + } + case VAL_SPARSEARRAY: { + checkTypeToUnparcel(clazz, SparseArray.class); + Class<?> itemType = ArrayUtils.getOrNull(itemTypes, 0); + object = readSparseArrayInternal(loader, itemType); break; - + } case VAL_SPARSEBOOLEANARRAY: object = readSparseBooleanArray(); break; @@ -4153,7 +4652,7 @@ public final class Parcel { + " at offset " + off); } if (object != null && clazz != null && !clazz.isInstance(object)) { - throw new BadParcelableException("Unparcelled object " + object + throw new BadTypeParcelableException("Unparcelled object " + object + " is not an instance of required class " + clazz.getName() + " provided in the parameter"); } @@ -4180,6 +4679,38 @@ public final class Parcel { } /** + * Checks that an array of type T[], where T is {@code componentTypeToUnparcel}, is a subtype of + * {@code requiredArrayType}. + */ + private void checkArrayTypeToUnparcel(@Nullable Class<?> requiredArrayType, + Class<?> componentTypeToUnparcel) { + if (requiredArrayType != null) { + // In Java 12, we could use componentTypeToUnparcel.arrayType() for the check + Class<?> requiredComponentType = requiredArrayType.getComponentType(); + if (requiredComponentType == null) { + throw new BadTypeParcelableException( + "About to unparcel an array but type " + + requiredArrayType.getCanonicalName() + + " required by caller is not an array."); + } + checkTypeToUnparcel(requiredComponentType, componentTypeToUnparcel); + } + } + + /** + * Checks that {@code typeToUnparcel} is a subtype of {@code requiredType}, if {@code + * requiredType} is not {@code null}. + */ + private void checkTypeToUnparcel(@Nullable Class<?> requiredType, Class<?> typeToUnparcel) { + if (requiredType != null && !requiredType.isAssignableFrom(typeToUnparcel)) { + throw new BadTypeParcelableException( + "About to unparcel a " + typeToUnparcel.getCanonicalName() + + ", which is not a subtype of type " + requiredType.getCanonicalName() + + " required by caller."); + } + } + + /** * Read and return a new Parcelable from the parcel. The given class loader * will be used to load any enclosed Parcelables. If it is null, the default * class loader will be used. @@ -4309,7 +4840,7 @@ public final class Parcel { if (clazz != null) { Class<?> parcelableClass = creator.getClass().getEnclosingClass(); if (!clazz.isAssignableFrom(parcelableClass)) { - throw new BadParcelableException("Parcelable creator " + name + " is not " + throw new BadTypeParcelableException("Parcelable creator " + name + " is not " + "a subclass of required class " + clazz.getName() + " provided in the parameter"); } @@ -4332,7 +4863,7 @@ public final class Parcel { } if (clazz != null) { if (!clazz.isAssignableFrom(parcelableClass)) { - throw new BadParcelableException("Parcelable creator " + name + " is not " + throw new BadTypeParcelableException("Parcelable creator " + name + " is not " + "a subclass of required class " + clazz.getName() + " provided in the parameter"); } @@ -4393,15 +4924,7 @@ public final class Parcel { @Deprecated @Nullable public Parcelable[] readParcelableArray(@Nullable ClassLoader loader) { - int N = readInt(); - if (N < 0) { - return null; - } - Parcelable[] p = new Parcelable[N]; - for (int i = 0; i < N; i++) { - p[i] = readParcelable(loader); - } - return p; + return readParcelableArrayInternal(loader, /* clazz */ null); } /** @@ -4413,14 +4936,20 @@ public final class Parcel { * trying to instantiate an element. */ @SuppressLint({"ArrayReturn", "NullableCollection"}) - @SuppressWarnings("unchecked") @Nullable public <T> T[] readParcelableArray(@Nullable ClassLoader loader, @NonNull Class<T> clazz) { + return readParcelableArrayInternal(loader, requireNonNull(clazz)); + } + + @SuppressWarnings("unchecked") + @Nullable + private <T> T[] readParcelableArrayInternal(@Nullable ClassLoader loader, + @Nullable Class<T> clazz) { int n = readInt(); if (n < 0) { return null; } - T[] p = (T[]) Array.newInstance(clazz, n); + T[] p = (T[]) ((clazz == null) ? new Parcelable[n] : Array.newInstance(clazz, n)); for (int i = 0; i < n; i++) { p[i] = readParcelableInternal(loader, clazz); } @@ -4483,7 +5012,7 @@ public final class Parcel { // the class the same way as ObjectInputStream, using the provided classloader. Class<?> cl = Class.forName(name, false, loader); if (!clazz.isAssignableFrom(cl)) { - throw new BadParcelableException("Serializable object " + throw new BadTypeParcelableException("Serializable object " + cl.getName() + " is not a subclass of required class " + clazz.getName() + " provided in the parameter"); } @@ -4508,7 +5037,7 @@ public final class Parcel { // the deserialized object, as we cannot resolve the class the same way as // ObjectInputStream. if (!clazz.isAssignableFrom(object.getClass())) { - throw new BadParcelableException("Serializable object " + throw new BadTypeParcelableException("Serializable object " + object.getClass().getName() + " is not a subclass of required class " + clazz.getName() + " provided in the parameter"); } @@ -4581,6 +5110,7 @@ public final class Parcel { } private void freeBuffer() { + mFlags = 0; resetSqaushingState(); if (mOwnsNativeParcelObject) { nativeFreeBuffer(mNativePtr); @@ -4617,7 +5147,26 @@ public final class Parcel { readMapInternal(outVal, n, loader, /* clazzKey */null, /* clazzValue */null); } - /* package */ <K, V> void readMapInternal(@NonNull Map<? super K, ? super V> outVal, int n, + @Nullable + private <K, V> HashMap<K, V> readHashMapInternal(@Nullable ClassLoader loader, + @NonNull Class<? extends K> clazzKey, @NonNull Class<? extends V> clazzValue) { + int n = readInt(); + if (n < 0) { + return null; + } + HashMap<K, V> map = new HashMap<>(n); + readMapInternal(map, n, loader, clazzKey, clazzValue); + return map; + } + + private <K, V> void readMapInternal(@NonNull Map<? super K, ? super V> outVal, + @Nullable ClassLoader loader, @Nullable Class<K> clazzKey, + @Nullable Class<V> clazzValue) { + int n = readInt(); + readMapInternal(outVal, n, loader, clazzKey, clazzValue); + } + + private <K, V> void readMapInternal(@NonNull Map<? super K, ? super V> outVal, int n, @Nullable ClassLoader loader, @Nullable Class<K> clazzKey, @Nullable Class<V> clazzValue) { while (n > 0) { @@ -4628,7 +5177,7 @@ public final class Parcel { } } - /* package */ void readArrayMapInternal(@NonNull ArrayMap<? super String, Object> outVal, + private void readArrayMapInternal(@NonNull ArrayMap<? super String, Object> outVal, int size, @Nullable ClassLoader loader) { readArrayMap(outVal, size, /* sorted */ true, /* lazy */ false, loader); } diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java index 944b71700450..a3b836adfc8b 100644 --- a/core/java/android/os/RecoverySystem.java +++ b/core/java/android/os/RecoverySystem.java @@ -674,10 +674,12 @@ public class RecoverySystem { } try { if (!rs.allocateSpaceForUpdate(packageFile)) { + rs.clearBcb(); throw new IOException("Failed to allocate space for update " + packageFile.getAbsolutePath()); } } catch (RemoteException e) { + rs.clearBcb(); e.rethrowAsRuntimeException(); } diff --git a/core/java/android/os/image/IDynamicSystemService.aidl b/core/java/android/os/image/IDynamicSystemService.aidl index a5a40ad55853..4e69952fac2f 100644 --- a/core/java/android/os/image/IDynamicSystemService.aidl +++ b/core/java/android/os/image/IDynamicSystemService.aidl @@ -26,6 +26,7 @@ interface IDynamicSystemService * @param dsuSlot Name used to identify this installation * @return true if the call succeeds */ + @EnforcePermission("MANAGE_DYNAMIC_SYSTEM") boolean startInstallation(@utf8InCpp String dsuSlot); /** @@ -36,6 +37,7 @@ interface IDynamicSystemService * @param readOnly True if this partition is readOnly * @return true if the call succeeds */ + @EnforcePermission("MANAGE_DYNAMIC_SYSTEM") boolean createPartition(@utf8InCpp String name, long size, boolean readOnly); /** @@ -43,12 +45,14 @@ interface IDynamicSystemService * * @return true if the partition installation completes without error. */ + @EnforcePermission("MANAGE_DYNAMIC_SYSTEM") boolean closePartition(); /** * Finish a previously started installation. Installations without * a cooresponding finishInstallation() will be cleaned up during device boot. */ + @EnforcePermission("MANAGE_DYNAMIC_SYSTEM") boolean finishInstallation(); /** @@ -57,6 +61,7 @@ interface IDynamicSystemService * * @return GsiProgress */ + @EnforcePermission("MANAGE_DYNAMIC_SYSTEM") GsiProgress getInstallationProgress(); /** @@ -66,21 +71,25 @@ interface IDynamicSystemService * * @return true if the call succeeds */ + @EnforcePermission("MANAGE_DYNAMIC_SYSTEM") boolean abort(); /** * @return true if the device is running an DynamicAnroid image */ + @RequiresNoPermission boolean isInUse(); /** * @return true if the device has an DynamicSystem image installed */ + @RequiresNoPermission boolean isInstalled(); /** * @return true if the device has an DynamicSystem image enabled */ + @EnforcePermission("MANAGE_DYNAMIC_SYSTEM") boolean isEnabled(); /** @@ -88,6 +97,7 @@ interface IDynamicSystemService * * @return true if the call succeeds */ + @EnforcePermission("MANAGE_DYNAMIC_SYSTEM") boolean remove(); /** @@ -97,6 +107,7 @@ interface IDynamicSystemService * * @return true if the call succeeds */ + @EnforcePermission("MANAGE_DYNAMIC_SYSTEM") boolean setEnable(boolean enable, boolean oneShot); /** @@ -106,6 +117,7 @@ interface IDynamicSystemService * @param fd fd that points to a ashmem * @param size size of the ashmem file */ + @EnforcePermission("MANAGE_DYNAMIC_SYSTEM") boolean setAshmem(in ParcelFileDescriptor fd, long size); /** @@ -115,6 +127,7 @@ interface IDynamicSystemService * @param bytes number of bytes that can be read from stream. * @return true on success, false otherwise. */ + @EnforcePermission("MANAGE_DYNAMIC_SYSTEM") boolean submitFromAshmem(long bytes); /** @@ -124,10 +137,12 @@ interface IDynamicSystemService * @return true on success, false if partition doesn't have a * valid VBMeta block to retrieve the AVB key from. */ + @EnforcePermission("MANAGE_DYNAMIC_SYSTEM") boolean getAvbPublicKey(out AvbPublicKey dst); /** * Returns the suggested scratch partition size for overlayFS. */ + @EnforcePermission("MANAGE_DYNAMIC_SYSTEM") long suggestScratchSize(); } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index d0ef546a8122..e79cc32ac99d 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -238,6 +238,20 @@ public final class Settings { "android.settings.TETHER_PROVISIONING_UI"; /** + * Activity Action: Show a dialog activity to notify tethering is NOT supported by carrier. + * + * When {@link android.telephony.CarrierConfigManager#KEY_CARRIER_SUPPORTS_TETHERING_BOOL} + * is false, and tethering is started by Settings, this dialog activity will be started to + * tell the user that tethering is not supported by carrier. + * + * @hide + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + @SystemApi + public static final String ACTION_TETHER_UNSUPPORTED_CARRIER_UI = + "android.settings.TETHER_UNSUPPORTED_CARRIER_UI"; + + /** * Activity Action: Show settings to allow entering/exiting airplane mode. * <p> * In some cases, a matching Activity may not exist, so ensure you diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index 1b2646549dce..b79b3d8083e8 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -3584,6 +3584,23 @@ public final class Telephony { "content://telephony/carriers/enforce_managed"); /** + * The {@code content://} style URL for the perferred APN used for internet. + * + * @hide + */ + public static final Uri PREFERRED_APN_URI = Uri.parse( + "content://telephony/carriers/preferapn/subId/"); + + /** + * The {@code content://} style URL for the perferred APN set id. + * + * @hide + */ + public static final Uri PREFERRED_APN_SET_URI = Uri.parse( + "content://telephony/carriers/preferapnset/subId/"); + + + /** * The column name for ENFORCE_MANAGED_URI, indicates whether DPC-owned APNs are enforced. * @hide */ diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java index 3b4f7e241852..f90055829b89 100644 --- a/core/java/android/security/keymaster/KeymasterDefs.java +++ b/core/java/android/security/keymaster/KeymasterDefs.java @@ -317,16 +317,35 @@ public final class KeymasterDefs { ErrorCode.MISSING_MIN_MAC_LENGTH; // -58; public static final int KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH = ErrorCode.UNSUPPORTED_MIN_MAC_LENGTH; // -59; + public static final int KM_ERROR_UNSUPPORTED_KDF = ErrorCode.UNSUPPORTED_KDF; // -60 + public static final int KM_ERROR_UNSUPPORTED_EC_CURVE = ErrorCode.UNSUPPORTED_EC_CURVE; // -61 + // -62 is KEY_REQUIRES_UPGRADE and is handled by Keystore. + public static final int KM_ERROR_ATTESTATION_CHALLENGE_MISSING = + ErrorCode.ATTESTATION_CHALLENGE_MISSING; // -63 + public static final int KM_ERROR_KEYMINT_NOT_CONFIGURED = + ErrorCode.KEYMINT_NOT_CONFIGURED; // -64 + public static final int KM_ERROR_ATTESTATION_APPLICATION_ID_MISSING = + ErrorCode.ATTESTATION_APPLICATION_ID_MISSING; // -65; public static final int KM_ERROR_CANNOT_ATTEST_IDS = ErrorCode.CANNOT_ATTEST_IDS; // -66; + public static final int KM_ERROR_ROLLBACK_RESISTANCE_UNAVAILABLE = + ErrorCode.ROLLBACK_RESISTANCE_UNAVAILABLE; // -67; public static final int KM_ERROR_HARDWARE_TYPE_UNAVAILABLE = ErrorCode.HARDWARE_TYPE_UNAVAILABLE; // -68; public static final int KM_ERROR_DEVICE_LOCKED = ErrorCode.DEVICE_LOCKED; // -72; + public static final int KM_ERROR_STORAGE_KEY_UNSUPPORTED = + ErrorCode.STORAGE_KEY_UNSUPPORTED; // -77, + public static final int KM_ERROR_INCOMPATIBLE_MGF_DIGEST = + ErrorCode.INCOMPATIBLE_MGF_DIGEST; // -78, + public static final int KM_ERROR_UNSUPPORTED_MGF_DIGEST = + ErrorCode.UNSUPPORTED_MGF_DIGEST; // -79, public static final int KM_ERROR_MISSING_NOT_BEFORE = ErrorCode.MISSING_NOT_BEFORE; // -80; public static final int KM_ERROR_MISSING_NOT_AFTER = ErrorCode.MISSING_NOT_AFTER; // -80; + public static final int KM_ERROR_HARDWARE_NOT_YET_AVAILABLE = + ErrorCode.HARDWARE_NOT_YET_AVAILABLE; // -85 public static final int KM_ERROR_UNIMPLEMENTED = ErrorCode.UNIMPLEMENTED; // -100; public static final int KM_ERROR_VERSION_MISMATCH = diff --git a/core/java/android/service/autofill/OWNERS b/core/java/android/service/autofill/OWNERS index a08863276da7..9a30e826a24f 100644 --- a/core/java/android/service/autofill/OWNERS +++ b/core/java/android/service/autofill/OWNERS @@ -1,9 +1,3 @@ # Bug component: 351486 -joannechung@google.com -adamhe@google.com -tymtsai@google.com -lpeter@google.com -augale@google.com -svetoslavganov@android.com -svetoslavganov@google.com +include /core/java/android/view/autofill/OWNERS diff --git a/core/java/android/service/contentcapture/OWNERS b/core/java/android/service/contentcapture/OWNERS index 6337327cec25..24561c59bba6 100644 --- a/core/java/android/service/contentcapture/OWNERS +++ b/core/java/android/service/contentcapture/OWNERS @@ -1,9 +1,3 @@ # Bug component: 544200 -joannechung@google.com -adamhe@google.com -tymtsai@google.com -lpeter@google.com -augale@google.com -svetoslavganov@android.com -svetoslavganov@google.com +include /core/java/android/view/contentcapture/OWNERS diff --git a/core/java/android/service/contentsuggestions/OWNERS b/core/java/android/service/contentsuggestions/OWNERS index 46b5ea03c545..72fe0b1c6392 100644 --- a/core/java/android/service/contentsuggestions/OWNERS +++ b/core/java/android/service/contentsuggestions/OWNERS @@ -1,7 +1,2 @@ -joannechung@google.com -adamhe@google.com -tymtsai@google.com -lpeter@google.com -augale@google.com -svetoslavganov@android.com -svetoslavganov@google.com + +include /core/java/android/app/contentsuggestions/OWNERS diff --git a/core/java/android/service/resumeonreboot/OWNERS b/core/java/android/service/resumeonreboot/OWNERS index 3a127d5a2c12..721fbaf2d4ed 100644 --- a/core/java/android/service/resumeonreboot/OWNERS +++ b/core/java/android/service/resumeonreboot/OWNERS @@ -1,2 +1 @@ -xunchang@google.com -zhaojiac@google.com +ejyzhang@google.com
\ No newline at end of file diff --git a/core/java/android/service/textclassifier/OWNERS b/core/java/android/service/textclassifier/OWNERS index a535f5258732..c85c69ef14df 100644 --- a/core/java/android/service/textclassifier/OWNERS +++ b/core/java/android/service/textclassifier/OWNERS @@ -1,9 +1,3 @@ # Bug component: 709498 -joannechung@google.com -adamhe@google.com -tymtsai@google.com -lpeter@google.com -augale@google.com -svetoslavganov@android.com -svetoslavganov@google.com +include /core/java/android/view/textclassifier/OWNERS diff --git a/core/java/android/service/tracing/TraceReportService.java b/core/java/android/service/tracing/TraceReportService.java index 3d16a3d41ea3..6fdc8e8eb961 100644 --- a/core/java/android/service/tracing/TraceReportService.java +++ b/core/java/android/service/tracing/TraceReportService.java @@ -112,7 +112,6 @@ public class TraceReportService extends Service { } } - // Methods to override. /** * Called when a trace is reported and sent to this class. * @@ -123,15 +122,10 @@ public class TraceReportService extends Service { public void onReportTrace(@NonNull TraceParams args) { } - // Optional methods to override. - // Realistically, these methods are internal implementation details but since this class is - // a SystemApi, it's better to err on the side of flexibility just in-case we need to override - // these methods down the line. - /** * Handles binder calls from system_server. */ - public boolean onMessage(@NonNull Message msg) { + private boolean onMessage(@NonNull Message msg) { if (msg.what == MSG_REPORT_TRACE) { if (!(msg.obj instanceof TraceReportParams)) { Log.e(TAG, "Received invalid type for report trace message."); @@ -153,10 +147,12 @@ public class TraceReportService extends Service { /** * Returns an IBinder for handling binder calls from system_server. + * + * @hide */ @Nullable @Override - public IBinder onBind(@NonNull Intent intent) { + public final IBinder onBind(@NonNull Intent intent) { if (mMessenger == null) { mMessenger = new Messenger(new Handler(Looper.getMainLooper(), this::onMessage)); } diff --git a/core/java/android/service/translation/OWNERS b/core/java/android/service/translation/OWNERS index a1e663aa8ff7..440f9a840057 100644 --- a/core/java/android/service/translation/OWNERS +++ b/core/java/android/service/translation/OWNERS @@ -1,8 +1,3 @@ # Bug component: 994311 -adamhe@google.com -augale@google.com -joannechung@google.com -lpeter@google.com -svetoslavganov@google.com -tymtsai@google.com +include /core/java/android/view/translation/OWNERS diff --git a/core/java/android/service/voice/OWNERS b/core/java/android/service/voice/OWNERS index 46b5ea03c545..59a0c2e36612 100644 --- a/core/java/android/service/voice/OWNERS +++ b/core/java/android/service/voice/OWNERS @@ -1,7 +1,3 @@ -joannechung@google.com -adamhe@google.com -tymtsai@google.com -lpeter@google.com -augale@google.com -svetoslavganov@android.com -svetoslavganov@google.com +# Bug component: 533220 + +include /core/java/android/app/assist/OWNERS diff --git a/core/java/android/tracing/OWNERS b/core/java/android/tracing/OWNERS index f5de4eb05c54..7d1b48b69c9e 100644 --- a/core/java/android/tracing/OWNERS +++ b/core/java/android/tracing/OWNERS @@ -1,2 +1,2 @@ -cfijalkovich@google.com carmenjackson@google.com +include platform/external/perfetto:/OWNERS diff --git a/core/java/android/util/NtpTrustedTime.java b/core/java/android/util/NtpTrustedTime.java index 4ac3178ecb4c..40beab323576 100644 --- a/core/java/android/util/NtpTrustedTime.java +++ b/core/java/android/util/NtpTrustedTime.java @@ -81,7 +81,16 @@ public class NtpTrustedTime implements TrustedTime { /** Calculates and returns the age of this result. */ public long getAgeMillis() { - return SystemClock.elapsedRealtime() - mElapsedRealtimeMillis; + return getAgeMillis(SystemClock.elapsedRealtime()); + } + + /** + * Calculates and returns the age of this result relative to currentElapsedRealtimeMillis. + * + * @param currentElapsedRealtimeMillis - reference elapsed real time + */ + public long getAgeMillis(long currentElapsedRealtimeMillis) { + return currentElapsedRealtimeMillis - mElapsedRealtimeMillis; } @Override @@ -256,6 +265,13 @@ public class NtpTrustedTime implements TrustedTime { return mTimeResult; } + /** Clears the last received NTP. Intended for use during tests. */ + public void clearCachedTimeResult() { + synchronized (this) { + mTimeResult = null; + } + } + private static class NtpConnectionInfo { @NonNull private final String mServer; diff --git a/core/java/android/util/OWNERS b/core/java/android/util/OWNERS index 5425c214de1f..d4cf6e6e90c2 100644 --- a/core/java/android/util/OWNERS +++ b/core/java/android/util/OWNERS @@ -1,8 +1,12 @@ +per-file Dump* = file:/core/java/com/android/internal/util/dump/OWNERS per-file FeatureFlagUtils.java = sbasi@google.com per-file FeatureFlagUtils.java = tmfang@google.com -per-file FeatureFlagUtils.java = asapperstein@google.com per-file AttributeSet.java = file:/core/java/android/content/res/OWNERS per-file TypedValue.java = file:/core/java/android/content/res/OWNERS per-file PackageUtils.java = file:/core/java/android/content/pm/OWNERS + +per-file NtpTrustedTime.java = file:/services/core/java/com/android/server/timezonedetector/OWNERS +per-file TimeUtils.java = file:/services/core/java/com/android/server/timezonedetector/OWNERS +per-file TrustedTime.java = file:/services/core/java/com/android/server/timezonedetector/OWNERS diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java index c7d9b9c4ab3e..c8c1fd4eba21 100644 --- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java +++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java @@ -407,20 +407,6 @@ public class ApkSignatureSchemeV2Verifier { } } - static byte[] generateApkVerityRootHash(String apkPath) - throws IOException, SignatureNotFoundException, DigestException, - NoSuchAlgorithmException { - try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) { - SignatureInfo signatureInfo = findSignature(apk); - VerifiedSigner vSigner = verify(apk, false); - if (vSigner.verityRootHash == null) { - return null; - } - return VerityBuilder.generateApkVerityRootHash( - apk, ByteBuffer.wrap(vSigner.verityRootHash), signatureInfo); - } - } - /** * Verified APK Signature Scheme v2 signer. * diff --git a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java index b07b5223d296..15215c6c85b8 100644 --- a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java +++ b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java @@ -444,20 +444,6 @@ public class ApkSignatureSchemeV3Verifier { } } - static byte[] generateApkVerityRootHash(String apkPath) - throws NoSuchAlgorithmException, DigestException, IOException, - SignatureNotFoundException { - try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) { - SignatureInfo signatureInfo = findSignature(apk); - VerifiedSigner vSigner = verify(apk, false); - if (vSigner.verityRootHash == null) { - return null; - } - return VerityBuilder.generateApkVerityRootHash( - apk, ByteBuffer.wrap(vSigner.verityRootHash), signatureInfo); - } - } - /** * Verified APK Signature Scheme v3 signer, including the proof of rotation structure. * diff --git a/core/java/android/util/apk/ApkSignatureVerifier.java b/core/java/android/util/apk/ApkSignatureVerifier.java index 73f7543ba819..f6b85fddf441 100644 --- a/core/java/android/util/apk/ApkSignatureVerifier.java +++ b/core/java/android/util/apk/ApkSignatureVerifier.java @@ -551,27 +551,6 @@ public class ApkSignatureVerifier { } /** - * Generates the FSVerity root hash from FSVerity header, extensions and Merkle tree root hash - * in Signing Block. - * - * @return FSverity root hash - */ - public static byte[] generateApkVerityRootHash(String apkPath) - throws NoSuchAlgorithmException, DigestException, IOException { - // first try v3 - try { - return ApkSignatureSchemeV3Verifier.generateApkVerityRootHash(apkPath); - } catch (SignatureNotFoundException e) { - // try older version - } - try { - return ApkSignatureSchemeV2Verifier.generateApkVerityRootHash(apkPath); - } catch (SignatureNotFoundException e) { - return null; - } - } - - /** * Extended signing details. * @hide for internal use only. */ diff --git a/core/java/android/util/apk/VerityBuilder.java b/core/java/android/util/apk/VerityBuilder.java index c7c465d30dad..adf53c213f8c 100644 --- a/core/java/android/util/apk/VerityBuilder.java +++ b/core/java/android/util/apk/VerityBuilder.java @@ -143,25 +143,6 @@ public abstract class VerityBuilder { return generateFsVerityTreeInternal(apk, salt, levelOffset, tree); } } - /** - * Calculates the apk-verity root hash for integrity measurement. This needs to be consistent - * to what kernel returns. - */ - @NonNull - static byte[] generateApkVerityRootHash(@NonNull RandomAccessFile apk, - @NonNull ByteBuffer apkDigest, @NonNull SignatureInfo signatureInfo) - throws NoSuchAlgorithmException, DigestException, IOException { - assertSigningBlockAlignedAndHasFullPages(signatureInfo); - - ByteBuffer footer = ByteBuffer.allocate(CHUNK_SIZE_BYTES).order(ByteOrder.LITTLE_ENDIAN); - generateApkVerityFooter(apk, signatureInfo, footer); - footer.flip(); - - MessageDigest md = MessageDigest.getInstance(JCA_DIGEST_ALGORITHM); - md.update(footer); - md.update(apkDigest); - return md.digest(); - } /** * Generates the apk-verity header and hash tree to be used by kernel for the given apk. This diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS index c74e42850365..b166fa626034 100644 --- a/core/java/android/view/OWNERS +++ b/core/java/android/view/OWNERS @@ -11,6 +11,9 @@ jjaggi@google.com roosa@google.com jreck@google.com +# Autofill +per-file ViewStructure.java = file:/core/java/android/service/autofill/OWNERS + # Display per-file Display*.java = file:/services/core/java/com/android/server/display/OWNERS per-file Display*.aidl = file:/services/core/java/com/android/server/display/OWNERS diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 00f4eb83bdaa..5b0bc4ad1aec 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -3128,7 +3128,8 @@ public interface WindowManager extends ViewManager { /** * The window is allowed to extend into the {@link DisplayCutout} area, only if the - * {@link DisplayCutout} is fully contained within a system bar. Otherwise, the window is + * {@link DisplayCutout} is fully contained within a system bar or the {@link DisplayCutout} + * is not deeper than 16 dp, but this depends on the OEM choice. Otherwise, the window is * laid out such that it does not overlap with the {@link DisplayCutout} area. * * <p> @@ -3143,6 +3144,13 @@ public interface WindowManager extends ViewManager { * The usual precautions for not overlapping with the status and navigation bar are * sufficient for ensuring that no important content overlaps with the DisplayCutout. * + * <p> + * Note: OEMs can have an option to allow the window to always extend into the + * {@link DisplayCutout} area, no matter the cutout flag set, when the {@link DisplayCutout} + * is on the different side from system bars, only if the {@link DisplayCutout} overlaps at + * most 16dp with the windows. + * In such case, OEMs must provide an opt-in/out affordance for users. + * * @see DisplayCutout * @see WindowInsets * @see #layoutInDisplayCutoutMode @@ -3155,8 +3163,16 @@ public interface WindowManager extends ViewManager { * The window is always allowed to extend into the {@link DisplayCutout} areas on the short * edges of the screen. * + * <p> * The window will never extend into a {@link DisplayCutout} area on the long edges of the - * screen. + * screen, unless the {@link DisplayCutout} is not deeper than 16 dp, but this depends on + * the OEM choice. + * + * <p> + * Note: OEMs can have an option to allow the window to extend into the + * {@link DisplayCutout} area on the long edge side, only if the cutout overlaps at most + * 16dp with the windows. In such case, OEMs must provide an opt-in/out affordance for + * users. * * <p> * The window must make sure that no important content overlaps with the diff --git a/core/java/android/view/autofill/OWNERS b/core/java/android/view/autofill/OWNERS index a08863276da7..108c42cdde2a 100644 --- a/core/java/android/view/autofill/OWNERS +++ b/core/java/android/view/autofill/OWNERS @@ -1,9 +1,7 @@ # Bug component: 351486 +augale@google.com joannechung@google.com -adamhe@google.com -tymtsai@google.com +markpun@google.com lpeter@google.com -augale@google.com -svetoslavganov@android.com -svetoslavganov@google.com +tymtsai@google.com diff --git a/core/java/android/view/contentcapture/OWNERS b/core/java/android/view/contentcapture/OWNERS index 6337327cec25..1a5cb1e4ca4a 100644 --- a/core/java/android/view/contentcapture/OWNERS +++ b/core/java/android/view/contentcapture/OWNERS @@ -1,9 +1,7 @@ # Bug component: 544200 +augale@google.com joannechung@google.com -adamhe@google.com -tymtsai@google.com +markpun@google.com lpeter@google.com -augale@google.com -svetoslavganov@android.com -svetoslavganov@google.com +tymtsai@google.com diff --git a/core/java/android/view/inputmethod/OWNERS b/core/java/android/view/inputmethod/OWNERS index d7db7c741364..9fa7e8f11364 100644 --- a/core/java/android/view/inputmethod/OWNERS +++ b/core/java/android/view/inputmethod/OWNERS @@ -3,4 +3,4 @@ set noparent include /services/core/java/com/android/server/inputmethod/OWNERS -per-file *InlineSuggestion* = file:/core/java/android/service/autofill/OWNERS +per-file *InlineSuggestion* = file:/core/java/android/view/autofill/OWNERS diff --git a/core/java/android/view/textclassifier/OWNERS b/core/java/android/view/textclassifier/OWNERS index 4bcdeea472e3..a205be2f39d0 100644 --- a/core/java/android/view/textclassifier/OWNERS +++ b/core/java/android/view/textclassifier/OWNERS @@ -2,8 +2,6 @@ mns@google.com toki@google.com -svetoslavganov@android.com -svetoslavganov@google.com augale@google.com joannechung@google.com tonymak@google.com diff --git a/core/java/android/view/textclassifier/logging/OWNERS b/core/java/android/view/textclassifier/logging/OWNERS deleted file mode 100644 index ac80d9f4cdd0..000000000000 --- a/core/java/android/view/textclassifier/logging/OWNERS +++ /dev/null @@ -1,8 +0,0 @@ -# Bug component: 709498 - -mns@google.com -toki@google.com -svetoslavganov@android.com -svetoslavganov@google.com -augale@google.com -joannechung@google.com diff --git a/core/java/android/view/translation/OWNERS b/core/java/android/view/translation/OWNERS index a1e663aa8ff7..b772ad3f7cab 100644 --- a/core/java/android/view/translation/OWNERS +++ b/core/java/android/view/translation/OWNERS @@ -1,8 +1,7 @@ # Bug component: 994311 -adamhe@google.com augale@google.com joannechung@google.com +markpun@google.com lpeter@google.com -svetoslavganov@google.com tymtsai@google.com diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java index 2d1f17a420fa..a0ec48bc6beb 100644 --- a/core/java/android/widget/SelectionActionModeHelper.java +++ b/core/java/android/widget/SelectionActionModeHelper.java @@ -297,12 +297,12 @@ public final class SelectionActionModeHelper { } else { mTextClassification = null; } - final SelectionModifierCursorController controller = mEditor.getSelectionController(); - if (controller != null - && (mTextView.isTextSelectable() || mTextView.isTextEditable())) { - controller.show(); - } if (mEditor.startActionModeInternal(actionMode)) { + final SelectionModifierCursorController controller = mEditor.getSelectionController(); + if (controller != null + && (mTextView.isTextSelectable() || mTextView.isTextEditable())) { + controller.show(); + } if (result != null) { switch (actionMode) { case Editor.TextActionMode.SELECTION: diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index f5c1bcf2de42..9791da5f41eb 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -4347,7 +4347,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * pixel" units. This size is adjusted based on the current density and * user font size preference. * - * <p>Note: if this TextView has the auto-size feature enabled than this function is no-op. + * <p>Note: if this TextView has the auto-size feature enabled, then this function is no-op. * * @param size The scaled pixel size. * @@ -4362,7 +4362,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * Set the default text size to a given unit and value. See {@link * TypedValue} for the possible dimension units. * - * <p>Note: if this TextView has the auto-size feature enabled than this function is no-op. + * <p>Note: if this TextView has the auto-size feature enabled, then this function is no-op. * * @param unit The desired dimension unit. * @param size The desired size in the given units. @@ -12521,7 +12521,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener /** * Called when a context menu option for the text view is selected. Currently * this will be one of {@link android.R.id#selectAll}, {@link android.R.id#cut}, - * {@link android.R.id#copy}, {@link android.R.id#paste} or {@link android.R.id#shareText}. + * {@link android.R.id#copy}, {@link android.R.id#paste}, + * {@link android.R.id#pasteAsPlainText} (starting at API level 23) or + * {@link android.R.id#shareText}. * * @return true if the context menu item action was performed. */ @@ -12712,6 +12714,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * method. The default actions can also be removed from the menu using * {@link android.view.Menu#removeItem(int)} and passing {@link android.R.id#selectAll}, * {@link android.R.id#cut}, {@link android.R.id#copy}, {@link android.R.id#paste}, + * {@link android.R.id#pasteAsPlainText} (starting at API level 23), * {@link android.R.id#replaceText} or {@link android.R.id#shareText} ids as parameters. * * <p>Returning false from @@ -12750,7 +12753,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * {@link android.view.ActionMode.Callback#onPrepareActionMode(android.view.ActionMode, * android.view.Menu)} method. The default actions can also be removed from the menu using * {@link android.view.Menu#removeItem(int)} and passing {@link android.R.id#selectAll}, - * {@link android.R.id#paste} or {@link android.R.id#replaceText} ids as parameters.</p> + * {@link android.R.id#paste}, {@link android.R.id#pasteAsPlainText} (starting at API + * level 23) or {@link android.R.id#replaceText} ids as parameters.</p> * * <p>Returning false from * {@link android.view.ActionMode.Callback#onCreateActionMode(android.view.ActionMode, diff --git a/core/java/android/widget/inline/OWNERS b/core/java/android/widget/inline/OWNERS new file mode 100644 index 000000000000..9a30e826a24f --- /dev/null +++ b/core/java/android/widget/inline/OWNERS @@ -0,0 +1,3 @@ +# Bug component: 351486 + +include /core/java/android/view/autofill/OWNERS diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java index 2ae56f808972..f174498c0d0d 100644 --- a/core/java/com/android/internal/net/VpnConfig.java +++ b/core/java/com/android/internal/net/VpnConfig.java @@ -105,6 +105,7 @@ public class VpnConfig implements Parcelable { public boolean allowIPv4; public boolean allowIPv6; public boolean isMetered = true; + public boolean requiresInternetValidation = false; public Network[] underlyingNetworks; public ProxyInfo proxyInfo; @@ -131,6 +132,7 @@ public class VpnConfig implements Parcelable { allowIPv4 = other.allowIPv4; allowIPv6 = other.allowIPv6; isMetered = other.isMetered; + requiresInternetValidation = other.requiresInternetValidation; underlyingNetworks = other.underlyingNetworks != null ? Arrays.copyOf( other.underlyingNetworks, other.underlyingNetworks.length) : null; proxyInfo = other.proxyInfo; @@ -189,6 +191,7 @@ public class VpnConfig implements Parcelable { out.writeInt(allowIPv4 ? 1 : 0); out.writeInt(allowIPv6 ? 1 : 0); out.writeInt(isMetered ? 1 : 0); + out.writeInt(requiresInternetValidation ? 1 : 0); out.writeTypedArray(underlyingNetworks, flags); out.writeParcelable(proxyInfo, flags); } @@ -216,6 +219,7 @@ public class VpnConfig implements Parcelable { config.allowIPv4 = in.readInt() != 0; config.allowIPv6 = in.readInt() != 0; config.isMetered = in.readInt() != 0; + config.requiresInternetValidation = in.readInt() != 0; config.underlyingNetworks = in.createTypedArray(Network.CREATOR); config.proxyInfo = in.readParcelable(null); return config; @@ -248,6 +252,8 @@ public class VpnConfig implements Parcelable { .append(", allowBypass=").append(allowBypass) .append(", allowIPv4=").append(allowIPv4) .append(", allowIPv6=").append(allowIPv6) + .append(", isMetered=").append(isMetered) + .append(", requiresInternetValidation").append(requiresInternetValidation) .append(", underlyingNetworks=").append(Arrays.toString(underlyingNetworks)) .append(", proxyInfo=").append(proxyInfo) .append("}") diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java index d8dc1436128e..bd3e898a631c 100644 --- a/core/java/com/android/internal/net/VpnProfile.java +++ b/core/java/com/android/internal/net/VpnProfile.java @@ -144,23 +144,26 @@ public final class VpnProfile implements Cloneable, Parcelable { public final boolean isRestrictedToTestNetworks; // 24 public final boolean excludeLocalRoutes; // 25 + public final boolean requiresInternetValidation; // 26 // Helper fields. @UnsupportedAppUsage public transient boolean saveLogin = false; public VpnProfile(String key) { - this(key, false, false); + this(key, false, false, false); } public VpnProfile(String key, boolean isRestrictedToTestNetworks) { - this(key, isRestrictedToTestNetworks, false); + this(key, isRestrictedToTestNetworks, false, false); } - public VpnProfile(String key, boolean isRestrictedToTestNetworks, boolean excludeLocalRoutes) { + public VpnProfile(String key, boolean isRestrictedToTestNetworks, boolean excludeLocalRoutes, + boolean requiresInternetValidation) { this.key = key; this.isRestrictedToTestNetworks = isRestrictedToTestNetworks; this.excludeLocalRoutes = excludeLocalRoutes; + this.requiresInternetValidation = requiresInternetValidation; } @UnsupportedAppUsage @@ -191,6 +194,7 @@ public final class VpnProfile implements Cloneable, Parcelable { areAuthParamsInline = in.readBoolean(); isRestrictedToTestNetworks = in.readBoolean(); excludeLocalRoutes = in.readBoolean(); + requiresInternetValidation = in.readBoolean(); } /** @@ -239,6 +243,7 @@ public final class VpnProfile implements Cloneable, Parcelable { out.writeBoolean(areAuthParamsInline); out.writeBoolean(isRestrictedToTestNetworks); out.writeBoolean(excludeLocalRoutes); + out.writeBoolean(requiresInternetValidation); } /** @@ -258,9 +263,11 @@ public final class VpnProfile implements Cloneable, Parcelable { // 14-19: Standard profile, with option for serverCert, proxy // 24: Standard profile with serverCert, proxy and platform-VPN parameters // 25: Standard profile with platform-VPN parameters and isRestrictedToTestNetworks - // 26: Standard profile with platform-VPN parameters and excludeLocalRoutes - if ((values.length < 14 || values.length > 19) - && values.length != 24 && values.length != 25 && values.length != 26) { + // 26: ...and excludeLocalRoutes + // (26 can only be found on dogfood devices) + // 27: ...and requiresInternetValidation + if ((values.length < 14 || (values.length > 19 && values.length < 24) + || values.length > 27)) { return null; } @@ -278,8 +285,15 @@ public final class VpnProfile implements Cloneable, Parcelable { excludeLocalRoutes = false; } + final boolean requiresInternetValidation; + if (values.length >= 27) { + requiresInternetValidation = Boolean.parseBoolean(values[26]); + } else { + requiresInternetValidation = false; + } + VpnProfile profile = new VpnProfile(key, isRestrictedToTestNetworks, - excludeLocalRoutes); + excludeLocalRoutes, requiresInternetValidation); profile.name = values[0]; profile.type = Integer.parseInt(values[1]); if (profile.type < 0 || profile.type > TYPE_MAX) { @@ -390,6 +404,7 @@ public final class VpnProfile implements Cloneable, Parcelable { builder.append(VALUE_DELIMITER).append(isRestrictedToTestNetworks); builder.append(VALUE_DELIMITER).append(excludeLocalRoutes); + builder.append(VALUE_DELIMITER).append(requiresInternetValidation); return builder.toString().getBytes(StandardCharsets.UTF_8); } @@ -471,7 +486,7 @@ public final class VpnProfile implements Cloneable, Parcelable { key, type, server, username, password, dnsServers, searchDomains, routes, mppe, l2tpSecret, ipsecIdentifier, ipsecSecret, ipsecUserCert, ipsecCaCert, ipsecServerCert, proxy, mAllowedAlgorithms, isBypassable, isMetered, maxMtu, areAuthParamsInline, - isRestrictedToTestNetworks, excludeLocalRoutes); + isRestrictedToTestNetworks, excludeLocalRoutes, requiresInternetValidation); } /** Checks VPN profiles for interior equality. */ @@ -505,11 +520,12 @@ public final class VpnProfile implements Cloneable, Parcelable { && maxMtu == other.maxMtu && areAuthParamsInline == other.areAuthParamsInline && isRestrictedToTestNetworks == other.isRestrictedToTestNetworks - && excludeLocalRoutes == other.excludeLocalRoutes; + && excludeLocalRoutes == other.excludeLocalRoutes + && requiresInternetValidation == other.requiresInternetValidation; } @NonNull - public static final Creator<VpnProfile> CREATOR = new Creator<VpnProfile>() { + public static final Creator<VpnProfile> CREATOR = new Creator<>() { @Override public VpnProfile createFromParcel(Parcel in) { return new VpnProfile(in); diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 58a0622ba53b..a234743b9cc0 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -12003,59 +12003,57 @@ public class BatteryStatsImpl extends BatteryStats { long totalRxPackets = 0; long totalTxPackets = 0; if (delta != null) { - NetworkStats.Entry entry = new NetworkStats.Entry(); - final int size = delta.size(); - for (int i = 0; i < size; i++) { - entry = delta.getValues(i, entry); - if (entry.rxPackets == 0 && entry.txPackets == 0) { + for (NetworkStats.Entry entry : delta) { + if (entry.getRxPackets() == 0 && entry.getTxPackets() == 0) { continue; } if (DEBUG_ENERGY) { - Slog.d(TAG, "Mobile uid " + entry.uid + ": delta rx=" + entry.rxBytes - + " tx=" + entry.txBytes + " rxPackets=" + entry.rxPackets - + " txPackets=" + entry.txPackets); + Slog.d(TAG, "Mobile uid " + entry.getUid() + ": delta rx=" + + entry.getRxBytes() + " tx=" + entry.getTxBytes() + + " rxPackets=" + entry.getRxPackets() + + " txPackets=" + entry.getTxPackets()); } - totalRxPackets += entry.rxPackets; - totalTxPackets += entry.txPackets; + totalRxPackets += entry.getRxPackets(); + totalTxPackets += entry.getTxPackets(); - final Uid u = getUidStatsLocked(mapUid(entry.uid), elapsedRealtimeMs, uptimeMs); - u.noteNetworkActivityLocked(NETWORK_MOBILE_RX_DATA, entry.rxBytes, - entry.rxPackets); - u.noteNetworkActivityLocked(NETWORK_MOBILE_TX_DATA, entry.txBytes, - entry.txPackets); - if (entry.set == NetworkStats.SET_DEFAULT) { // Background transfers + final Uid u = getUidStatsLocked( + mapUid(entry.getUid()), elapsedRealtimeMs, uptimeMs); + u.noteNetworkActivityLocked(NETWORK_MOBILE_RX_DATA, entry.getRxBytes(), + entry.getRxPackets()); + u.noteNetworkActivityLocked(NETWORK_MOBILE_TX_DATA, entry.getTxBytes(), + entry.getTxPackets()); + if (entry.getSet() == NetworkStats.SET_DEFAULT) { // Background transfers u.noteNetworkActivityLocked(NETWORK_MOBILE_BG_RX_DATA, - entry.rxBytes, entry.rxPackets); + entry.getRxBytes(), entry.getRxPackets()); u.noteNetworkActivityLocked(NETWORK_MOBILE_BG_TX_DATA, - entry.txBytes, entry.txPackets); + entry.getTxBytes(), entry.getTxPackets()); } mNetworkByteActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked( - entry.rxBytes); + entry.getRxBytes()); mNetworkByteActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked( - entry.txBytes); + entry.getTxBytes()); mNetworkPacketActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked( - entry.rxPackets); + entry.getRxPackets()); mNetworkPacketActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked( - entry.txPackets); + entry.getTxPackets()); } // Now distribute proportional blame to the apps that did networking. long totalPackets = totalRxPackets + totalTxPackets; if (totalPackets > 0) { - for (int i = 0; i < size; i++) { - entry = delta.getValues(i, entry); - if (entry.rxPackets == 0 && entry.txPackets == 0) { + for (NetworkStats.Entry entry : delta) { + if (entry.getRxPackets() == 0 && entry.getTxPackets() == 0) { continue; } - final Uid u = getUidStatsLocked(mapUid(entry.uid), + final Uid u = getUidStatsLocked(mapUid(entry.getUid()), elapsedRealtimeMs, uptimeMs); // Distribute total radio active time in to this app. - final long appPackets = entry.rxPackets + entry.txPackets; + final long appPackets = entry.getRxPackets() + entry.getTxPackets(); final long appRadioTimeUs = (totalAppRadioTimeUs * appPackets) / totalPackets; u.noteMobileRadioActiveTimeLocked(appRadioTimeUs); @@ -12076,16 +12074,16 @@ public class BatteryStatsImpl extends BatteryStats { if (deltaInfo != null) { ControllerActivityCounterImpl activityCounter = u.getOrCreateModemControllerActivityLocked(); - if (totalRxPackets > 0 && entry.rxPackets > 0) { - final long rxMs = (entry.rxPackets + if (totalRxPackets > 0 && entry.getRxPackets() > 0) { + final long rxMs = (entry.getRxPackets() * deltaInfo.getReceiveTimeMillis()) / totalRxPackets; activityCounter.getRxTimeCounter().addCountLocked(rxMs); } - if (totalTxPackets > 0 && entry.txPackets > 0) { + if (totalTxPackets > 0 && entry.getTxPackets() > 0) { for (int lvl = 0; lvl < ModemActivityInfo.getNumTxPowerLevels(); lvl++) { - long txMs = entry.txPackets + long txMs = entry.getTxPackets() * deltaInfo.getTransmitDurationMillisAtPowerLevel(lvl); txMs /= totalTxPackets; activityCounter.getTxTimeCounters()[lvl].addCountLocked(txMs); diff --git a/core/java/com/android/internal/os/SystemServerClassLoaderFactory.java b/core/java/com/android/internal/os/SystemServerClassLoaderFactory.java index 615e4b793752..a03bac45d14f 100644 --- a/core/java/com/android/internal/os/SystemServerClassLoaderFactory.java +++ b/core/java/com/android/internal/os/SystemServerClassLoaderFactory.java @@ -29,22 +29,66 @@ public final class SystemServerClassLoaderFactory { private static final ArrayMap<String, PathClassLoader> sLoadedPaths = new ArrayMap<>(); /** - * Creates and caches a ClassLoader for the jar at the given path, or returns a cached - * ClassLoader if it exists. + * Creates and caches a ClassLoader for the jar at the given path. + * + * This method should only be called by ZygoteInit to prefetch jars. For other users, use + * {@link getOrCreateClassLoader} instead. * * The parent class loader should always be the system server class loader. Changing it has * implications that require discussion with the mainline team. * * @hide for internal use only */ - public static PathClassLoader getOrCreateClassLoader(String path, ClassLoader parent) { - PathClassLoader pathClassLoader = sLoadedPaths.get(path); - if (pathClassLoader == null) { - pathClassLoader = (PathClassLoader) ClassLoaderFactory.createClassLoader( - path, /*librarySearchPath=*/null, /*libraryPermittedPath=*/null, parent, - Build.VERSION.SDK_INT, /*isNamespaceShared=*/true , /*classLoaderName=*/null); - sLoadedPaths.put(path, pathClassLoader); + /* package */ static PathClassLoader createClassLoader(String path, ClassLoader parent) { + if (sLoadedPaths.containsKey(path)) { + throw new IllegalStateException("A ClassLoader for " + path + " already exists"); } + PathClassLoader pathClassLoader = (PathClassLoader) ClassLoaderFactory.createClassLoader( + path, /*librarySearchPath=*/null, /*libraryPermittedPath=*/null, parent, + Build.VERSION.SDK_INT, /*isNamespaceShared=*/true , /*classLoaderName=*/null); + sLoadedPaths.put(path, pathClassLoader); return pathClassLoader; } + + /** + * Returns a cached ClassLoader to be used at runtime for the jar at the given path. Or, creates + * one if it is not prefetched and is allowed to be created at runtime. + * + * The parent class loader should always be the system server class loader. Changing it has + * implications that require discussion with the mainline team. + * + * @hide for internal use only + */ + public static PathClassLoader getOrCreateClassLoader( + String path, ClassLoader parent, boolean isTestOnly) { + PathClassLoader pathClassLoader = sLoadedPaths.get(path); + if (pathClassLoader != null) { + return pathClassLoader; + } + if (!allowClassLoaderCreation(path, isTestOnly)) { + throw new RuntimeException("Creating a ClassLoader from " + path + " is not allowed. " + + "Please make sure that the jar is listed in " + + "`PRODUCT_APEX_STANDALONE_SYSTEM_SERVER_JARS` in the Makefile and added as a " + + "`standalone_contents` of a `systemserverclasspath_fragment` in " + + "`Android.bp`."); + } + return createClassLoader(path, parent); + } + + /** + * Returns whether a class loader for the jar is allowed to be created at runtime. + */ + private static boolean allowClassLoaderCreation(String path, boolean isTestOnly) { + // Currently, we only enforce prefetching for APEX jars. + if (!path.startsWith("/apex/")) { + return true; + } + // APEXes for testing only are okay to ignore. + if (isTestOnly) { + return true; + } + return false; + } + + } diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index 611f644ffc7d..e5e6949851b9 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -586,7 +586,7 @@ public class ZygoteInit { } for (String jar : envStr.split(":")) { try { - SystemServerClassLoaderFactory.getOrCreateClassLoader( + SystemServerClassLoaderFactory.createClassLoader( jar, getOrCreateSystemServerClassLoader()); } catch (Error e) { // We don't want the process to crash for this error because prefetching is just an @@ -713,7 +713,7 @@ public class ZygoteInit { "--setuid=1000", "--setgid=1000", "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023," - + "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010,3011,3012", + + "1024,1032,1065,3001,3002,3003,3005,3006,3007,3009,3010,3011,3012", "--capabilities=" + capabilities + "," + capabilities, "--nice-name=system_server", "--runtime-args", diff --git a/core/java/com/android/internal/security/VerityUtils.java b/core/java/com/android/internal/security/VerityUtils.java index 877026777ce3..76f7b2180b34 100644 --- a/core/java/com/android/internal/security/VerityUtils.java +++ b/core/java/com/android/internal/security/VerityUtils.java @@ -18,28 +18,15 @@ package com.android.internal.security; import android.annotation.NonNull; import android.os.Build; -import android.os.SharedMemory; import android.os.SystemProperties; -import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; -import android.util.Pair; import android.util.Slog; -import android.util.apk.ApkSignatureVerifier; -import android.util.apk.ByteBufferFactory; -import android.util.apk.SignatureNotFoundException; - -import libcore.util.HexEncoding; import java.io.File; -import java.io.FileDescriptor; import java.io.IOException; -import java.nio.ByteBuffer; import java.nio.file.Files; import java.nio.file.Paths; -import java.security.DigestException; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; /** Provides fsverity related operations. */ public abstract class VerityUtils { @@ -57,8 +44,6 @@ public abstract class VerityUtils { /** SHA256 hash size. */ private static final int HASH_SIZE_BYTES = 32; - private static final boolean DEBUG = false; - public static boolean isFsVeritySupported() { return Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.R || SystemProperties.getInt("ro.apk_verity.mode", 0) == 2; @@ -123,204 +108,4 @@ public abstract class VerityUtils { private static native int measureFsverityNative(@NonNull String filePath, @NonNull byte[] digest); private static native int statxForFsverityNative(@NonNull String filePath); - - /** - * Generates legacy Merkle tree and fs-verity metadata with Signing Block skipped. - * - * @deprecated This is only used for previous fs-verity implementation, and should never be used - * on new devices. - * @return {@code SetupResult} that contains the result code, and when success, the - * {@code FileDescriptor} to read all the data from. - */ - @Deprecated - public static SetupResult generateApkVeritySetupData(@NonNull String apkPath) { - if (DEBUG) { - Slog.d(TAG, "Trying to install legacy apk verity to " + apkPath); - } - SharedMemory shm = null; - try { - final byte[] signedVerityHash = ApkSignatureVerifier.getVerityRootHash(apkPath); - if (signedVerityHash == null) { - if (DEBUG) { - Slog.d(TAG, "Skip verity tree generation since there is no signed root hash"); - } - return SetupResult.skipped(); - } - - Pair<SharedMemory, Integer> result = - generateFsVerityIntoSharedMemory(apkPath, signedVerityHash); - shm = result.first; - int contentSize = result.second; - FileDescriptor rfd = shm.getFileDescriptor(); - if (rfd == null || !rfd.valid()) { - return SetupResult.failed(); - } - return SetupResult.ok(Os.dup(rfd), contentSize); - } catch (IOException | SecurityException | DigestException | NoSuchAlgorithmException - | SignatureNotFoundException | ErrnoException e) { - Slog.e(TAG, "Failed to set up apk verity: ", e); - return SetupResult.failed(); - } finally { - if (shm != null) { - shm.close(); - } - } - } - - /** - * {@see ApkSignatureVerifier#generateApkVerityRootHash(String)}. - * @deprecated This is only used for previous fs-verity implementation, and should never be used - * on new devices. - */ - @Deprecated - public static byte[] generateApkVerityRootHash(@NonNull String apkPath) - throws NoSuchAlgorithmException, DigestException, IOException { - return ApkSignatureVerifier.generateApkVerityRootHash(apkPath); - } - - /** - * {@see ApkSignatureVerifier#getVerityRootHash(String)}. - * @deprecated This is only used for previous fs-verity implementation, and should never be used - * on new devices. - */ - @Deprecated - public static byte[] getVerityRootHash(@NonNull String apkPath) - throws IOException, SignatureNotFoundException { - return ApkSignatureVerifier.getVerityRootHash(apkPath); - } - - /** - * Returns a pair of {@code SharedMemory} and {@code Integer}. The {@code SharedMemory} contains - * Merkle tree and fsverity headers for the given apk, in the form that can immediately be used - * for fsverity setup. The data is aligned to the beginning of {@code SharedMemory}, and has - * length equals to the returned {@code Integer}. - */ - private static Pair<SharedMemory, Integer> generateFsVerityIntoSharedMemory(String apkPath, - @NonNull byte[] expectedRootHash) - throws IOException, DigestException, NoSuchAlgorithmException, - SignatureNotFoundException { - TrackedShmBufferFactory shmBufferFactory = new TrackedShmBufferFactory(); - byte[] generatedRootHash = - ApkSignatureVerifier.generateApkVerity(apkPath, shmBufferFactory); - // We only generate Merkle tree once here, so it's important to make sure the root hash - // matches the signed one in the apk. - if (!Arrays.equals(expectedRootHash, generatedRootHash)) { - throw new SecurityException("verity hash mismatch: " - + bytesToString(generatedRootHash) + " != " + bytesToString(expectedRootHash)); - } - - int contentSize = shmBufferFactory.getBufferLimit(); - SharedMemory shm = shmBufferFactory.releaseSharedMemory(); - if (shm == null) { - throw new IllegalStateException("Failed to generate verity tree into shared memory"); - } - if (!shm.setProtect(OsConstants.PROT_READ)) { - throw new SecurityException("Failed to set up shared memory correctly"); - } - return Pair.create(shm, contentSize); - } - - private static String bytesToString(byte[] bytes) { - return HexEncoding.encodeToString(bytes); - } - - /** - * @deprecated This is only used for previous fs-verity implementation, and should never be used - * on new devices. - */ - @Deprecated - public static class SetupResult { - /** Result code if verity is set up correctly. */ - private static final int RESULT_OK = 1; - - /** Result code if signature is not provided. */ - private static final int RESULT_SKIPPED = 2; - - /** Result code if the setup failed. */ - private static final int RESULT_FAILED = 3; - - private final int mCode; - private final FileDescriptor mFileDescriptor; - private final int mContentSize; - - /** @deprecated */ - @Deprecated - public static SetupResult ok(@NonNull FileDescriptor fileDescriptor, int contentSize) { - return new SetupResult(RESULT_OK, fileDescriptor, contentSize); - } - - /** @deprecated */ - @Deprecated - public static SetupResult skipped() { - return new SetupResult(RESULT_SKIPPED, null, -1); - } - - /** @deprecated */ - @Deprecated - public static SetupResult failed() { - return new SetupResult(RESULT_FAILED, null, -1); - } - - private SetupResult(int code, FileDescriptor fileDescriptor, int contentSize) { - this.mCode = code; - this.mFileDescriptor = fileDescriptor; - this.mContentSize = contentSize; - } - - public boolean isFailed() { - return mCode == RESULT_FAILED; - } - - public boolean isOk() { - return mCode == RESULT_OK; - } - - public @NonNull FileDescriptor getUnownedFileDescriptor() { - return mFileDescriptor; - } - - public int getContentSize() { - return mContentSize; - } - } - - /** A {@code ByteBufferFactory} that creates a shared memory backed {@code ByteBuffer}. */ - private static class TrackedShmBufferFactory implements ByteBufferFactory { - private SharedMemory mShm; - private ByteBuffer mBuffer; - - @Override - public ByteBuffer create(int capacity) { - try { - if (DEBUG) Slog.d(TAG, "Creating shared memory for apk verity"); - // NB: This method is supposed to be called once according to the contract with - // ApkSignatureSchemeV2Verifier. - if (mBuffer != null) { - throw new IllegalStateException("Multiple instantiation from this factory"); - } - mShm = SharedMemory.create("apkverity", capacity); - if (!mShm.setProtect(OsConstants.PROT_READ | OsConstants.PROT_WRITE)) { - throw new SecurityException("Failed to set protection"); - } - mBuffer = mShm.mapReadWrite(); - return mBuffer; - } catch (ErrnoException e) { - throw new SecurityException("Failed to set protection", e); - } - } - - public SharedMemory releaseSharedMemory() { - if (mBuffer != null) { - SharedMemory.unmap(mBuffer); - mBuffer = null; - } - SharedMemory tmp = mShm; - mShm = null; - return tmp; - } - - public int getBufferLimit() { - return mBuffer == null ? -1 : mBuffer.limit(); - } - } } diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java index c6fd6eec2f91..55df09a95838 100644 --- a/core/java/com/android/internal/util/ArrayUtils.java +++ b/core/java/com/android/internal/util/ArrayUtils.java @@ -888,6 +888,15 @@ public class ArrayUtils { } } + /** + * Returns the {@code i}-th item in {@code items}, if it exists and {@code items} is not {@code + * null}, otherwise returns {@code null}. + */ + @Nullable + public static <T> T getOrNull(@Nullable T[] items, int i) { + return (items != null && items.length > i) ? items[i] : null; + } + public static @Nullable <T> T firstOrNull(T[] items) { return items.length > 0 ? items[0] : null; } diff --git a/core/java/com/android/internal/util/OWNERS b/core/java/com/android/internal/util/OWNERS index 2b7f8b2749fd..354dd9a41586 100644 --- a/core/java/com/android/internal/util/OWNERS +++ b/core/java/com/android/internal/util/OWNERS @@ -4,3 +4,4 @@ per-file *Notification* = file:/services/core/java/com/android/server/notificati per-file *ContrastColor* = file:/services/core/java/com/android/server/notification/OWNERS per-file Protocol* = etancohen@google.com, lorenzo@google.com per-file State* = jchalard@google.com, lorenzo@google.com, satk@google.com +per-file *Dump* = file:/core/java/com/android/internal/util/dump/OWNERS diff --git a/core/java/com/android/internal/util/dump/OWNERS b/core/java/com/android/internal/util/dump/OWNERS new file mode 100644 index 000000000000..ce9302aed42e --- /dev/null +++ b/core/java/com/android/internal/util/dump/OWNERS @@ -0,0 +1,2 @@ +omakoto@google.com +felipeal@google.com diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java index ae9d71610aaa..fb0b7fdd6ce3 100644 --- a/core/java/com/android/server/SystemConfig.java +++ b/core/java/com/android/server/SystemConfig.java @@ -112,17 +112,74 @@ public class SystemConfig { public final String name; public final String filename; public final String[] dependencies; + + /** + * SDK version this library was added to the BOOTCLASSPATH. + * + * <p>At the SDK level specified in this field and higher, the apps' uses-library tags for + * this library will be ignored, since the library is always available on BOOTCLASSPATH. + * + * <p>0 means not specified. + */ + public final int onBootclasspathSince; + + /** + * SDK version this library was removed from the BOOTCLASSPATH. + * + * <p>At the SDK level specified in this field and higher, this library needs to be + * explicitly added by apps. For compatibility reasons, when an app + * targets an SDK less than the value of this attribute, this library is automatically + * added. + * + * <p>0 means not specified. + */ + public final int onBootclasspathBefore; + + /** + * Declares whether this library can be safely ignored from <uses-library> tags. + * + * <p> This can happen if the library initially had to be explicitly depended-on using that + * tag but has since been moved to the BOOTCLASSPATH which means now is always available + * and the tag is no longer required. + */ + public final boolean canBeSafelyIgnored; + public final boolean isNative; - SharedLibraryEntry(String name, String filename, String[] dependencies) { - this(name, filename, dependencies, false /* isNative */); + + @VisibleForTesting + public SharedLibraryEntry(String name, String filename, String[] dependencies, + boolean isNative) { + this(name, filename, dependencies, 0 /* onBootclasspathSince */, + 0 /* onBootclasspathBefore */, isNative); } - SharedLibraryEntry(String name, String filename, String[] dependencies, boolean isNative) { + @VisibleForTesting + public SharedLibraryEntry(String name, String filename, String[] dependencies, + int onBootclasspathSince, int onBootclassPathBefore) { + this(name, filename, dependencies, onBootclasspathSince, onBootclassPathBefore, + false /* isNative */); + } + + SharedLibraryEntry(String name, String filename, String[] dependencies, + int onBootclasspathSince, int onBootclasspathBefore, boolean isNative) { this.name = name; this.filename = filename; this.dependencies = dependencies; + this.onBootclasspathSince = onBootclasspathSince; + this.onBootclasspathBefore = onBootclasspathBefore; this.isNative = isNative; + + canBeSafelyIgnored = this.onBootclasspathSince != 0 + && isSdkAtLeast(this.onBootclasspathSince); + } + + private static boolean isSdkAtLeast(int level) { + if ("REL".equals(Build.VERSION.CODENAME)) { + return Build.VERSION.SDK_INT >= level; + } + return level == Build.VERSION_CODES.CUR_DEVELOPMENT + || Build.VERSION.SDK_INT >= level; } } @@ -509,12 +566,14 @@ public class SystemConfig { } private void readAllPermissions() { + final XmlPullParser parser = Xml.newPullParser(); + // Read configuration from system - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL); // Read configuration from the old permissions dir - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL); // Vendors are only allowed to customize these @@ -524,18 +583,18 @@ public class SystemConfig { // For backward compatibility vendorPermissionFlag |= (ALLOW_PERMISSIONS | ALLOW_APP_CONFIGS); } - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag); - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag); String vendorSkuProperty = SystemProperties.get(VENDOR_SKU_PROPERTY, ""); if (!vendorSkuProperty.isEmpty()) { String vendorSkuDir = "sku_" + vendorSkuProperty; - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getVendorDirectory(), "etc", "sysconfig", vendorSkuDir), vendorPermissionFlag); - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getVendorDirectory(), "etc", "permissions", vendorSkuDir), vendorPermissionFlag); } @@ -543,18 +602,18 @@ public class SystemConfig { // Allow ODM to customize system configs as much as Vendor, because /odm is another // vendor partition other than /vendor. int odmPermissionFlag = vendorPermissionFlag; - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag); - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag); String skuProperty = SystemProperties.get(SKU_PROPERTY, ""); if (!skuProperty.isEmpty()) { String skuDir = "sku_" + skuProperty; - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getOdmDirectory(), "etc", "sysconfig", skuDir), odmPermissionFlag); - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getOdmDirectory(), "etc", "permissions", skuDir), odmPermissionFlag); } @@ -562,9 +621,9 @@ public class SystemConfig { // Allow OEM to customize these int oemPermissionFlag = ALLOW_FEATURES | ALLOW_OEM_PERMISSIONS | ALLOW_ASSOCIATIONS | ALLOW_VENDOR_APEX; - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getOemDirectory(), "etc", "sysconfig"), oemPermissionFlag); - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getOemDirectory(), "etc", "permissions"), oemPermissionFlag); // Allow Product to customize these configs @@ -579,15 +638,15 @@ public class SystemConfig { // DEVICE_INITIAL_SDK_INT for the devices without product interface enforcement. productPermissionFlag = ALLOW_ALL; } - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getProductDirectory(), "etc", "sysconfig"), productPermissionFlag); - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getProductDirectory(), "etc", "permissions"), productPermissionFlag); // Allow /system_ext to customize all system configs - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getSystemExtDirectory(), "etc", "sysconfig"), ALLOW_ALL); - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getSystemExtDirectory(), "etc", "permissions"), ALLOW_ALL); // Skip loading configuration from apex if it is not a system process. @@ -601,12 +660,14 @@ public class SystemConfig { if (f.isFile() || f.getPath().contains("@")) { continue; } - readPermissions(Environment.buildPath(f, "etc", "permissions"), apexPermissionFlag); + readPermissions(parser, Environment.buildPath(f, "etc", "permissions"), + apexPermissionFlag); } + pruneVendorApexPrivappAllowlists(); } @VisibleForTesting - public void readPermissions(File libraryDir, int permissionFlag) { + public void readPermissions(final XmlPullParser parser, File libraryDir, int permissionFlag) { // Read permissions from given directory. if (!libraryDir.exists() || !libraryDir.isDirectory()) { if (permissionFlag == ALLOW_ALL) { @@ -641,12 +702,12 @@ public class SystemConfig { continue; } - readPermissionsFromXml(f, permissionFlag); + readPermissionsFromXml(parser, f, permissionFlag); } // Read platform permissions last so it will take precedence if (platformFile != null) { - readPermissionsFromXml(platformFile, permissionFlag); + readPermissionsFromXml(parser, platformFile, permissionFlag); } } @@ -655,8 +716,9 @@ public class SystemConfig { + permFile + " at " + parser.getPositionDescription()); } - private void readPermissionsFromXml(File permFile, int permissionFlag) { - FileReader permReader = null; + private void readPermissionsFromXml(final XmlPullParser parser, File permFile, + int permissionFlag) { + final FileReader permReader; try { permReader = new FileReader(permFile); } catch (FileNotFoundException e) { @@ -668,7 +730,6 @@ public class SystemConfig { final boolean lowRam = ActivityManager.isLowRamDeviceStatic(); try { - XmlPullParser parser = Xml.newPullParser(); parser.setInput(permReader); int type; @@ -789,11 +850,17 @@ public class SystemConfig { XmlUtils.skipCurrentTag(parser); } } break; + case "apex-library": + // "apex-library" is meant to behave exactly like "library" case "library": { if (allowLibs) { String lname = parser.getAttributeValue(null, "name"); String lfile = parser.getAttributeValue(null, "file"); String ldependency = parser.getAttributeValue(null, "dependency"); + int minDeviceSdk = XmlUtils.readIntAttribute(parser, "min-device-sdk", + 0); + int maxDeviceSdk = XmlUtils.readIntAttribute(parser, "max-device-sdk", + 0); if (lname == null) { Slog.w(TAG, "<" + name + "> without name in " + permFile + " at " + parser.getPositionDescription()); @@ -801,10 +868,34 @@ public class SystemConfig { Slog.w(TAG, "<" + name + "> without file in " + permFile + " at " + parser.getPositionDescription()); } else { - //Log.i(TAG, "Got library " + lname + " in " + lfile); - SharedLibraryEntry entry = new SharedLibraryEntry(lname, lfile, - ldependency == null ? new String[0] : ldependency.split(":")); - mSharedLibraries.put(lname, entry); + boolean allowedMinSdk = minDeviceSdk <= Build.VERSION.SDK_INT; + boolean allowedMaxSdk = + maxDeviceSdk == 0 || maxDeviceSdk >= Build.VERSION.SDK_INT; + final boolean exists = new File(lfile).exists(); + if (allowedMinSdk && allowedMaxSdk && exists) { + int bcpSince = XmlUtils.readIntAttribute(parser, + "on-bootclasspath-since", 0); + int bcpBefore = XmlUtils.readIntAttribute(parser, + "on-bootclasspath-before", 0); + SharedLibraryEntry entry = new SharedLibraryEntry(lname, lfile, + ldependency == null + ? new String[0] : ldependency.split(":"), + bcpSince, bcpBefore); + mSharedLibraries.put(lname, entry); + } else { + final StringBuilder msg = new StringBuilder( + "Ignore shared library ").append(lname).append(":"); + if (!allowedMinSdk) { + msg.append(" min-device-sdk=").append(minDeviceSdk); + } + if (!allowedMaxSdk) { + msg.append(" max-device-sdk=").append(maxDeviceSdk); + } + if (!exists) { + msg.append(" ").append(lfile).append(" does not exist"); + } + Slog.i(TAG, msg.toString()); + } } } else { logNotAllowedInPartition(name, permFile, parser); @@ -1085,7 +1176,8 @@ public class SystemConfig { readPrivAppPermissions(parser, mSystemExtPrivAppPermissions, mSystemExtPrivAppDenyPermissions); } else if (apex) { - readApexPrivAppPermissions(parser, permFile); + readApexPrivAppPermissions(parser, permFile, + Environment.getApexDirectory().toPath()); } else { readPrivAppPermissions(parser, mPrivAppPermissions, mPrivAppDenyPermissions); @@ -1435,6 +1527,21 @@ public class SystemConfig { } } + /** + * Prunes out any privileged permission allowlists bundled in vendor apexes. + */ + @VisibleForTesting + public void pruneVendorApexPrivappAllowlists() { + for (String moduleName: mAllowedVendorApexes.keySet()) { + if (mApexPrivAppPermissions.containsKey(moduleName) + || mApexPrivAppDenyPermissions.containsKey(moduleName)) { + Slog.w(TAG, moduleName + " is a vendor apex, ignore its priv-app allowlist"); + mApexPrivAppPermissions.remove(moduleName); + mApexPrivAppDenyPermissions.remove(moduleName); + } + } + } + private void readInstallInUserType(XmlPullParser parser, Map<String, Set<String>> doInstallMap, Map<String, Set<String>> nonInstallMap) @@ -1645,8 +1752,7 @@ public class SystemConfig { /** * Returns the module name for a file in the apex module's partition. */ - private String getApexModuleNameFromFilePath(Path path) { - final Path apexDirectoryPath = Environment.getApexDirectory().toPath(); + private String getApexModuleNameFromFilePath(Path path, Path apexDirectoryPath) { if (!path.startsWith(apexDirectoryPath)) { throw new IllegalArgumentException("File " + path + " is not part of an APEX."); } @@ -1658,9 +1764,14 @@ public class SystemConfig { return path.getName(apexDirectoryPath.getNameCount()).toString(); } - private void readApexPrivAppPermissions(XmlPullParser parser, File permFile) - throws IOException, XmlPullParserException { - final String moduleName = getApexModuleNameFromFilePath(permFile.toPath()); + /** + * Reads the contents of the privileged permission allowlist stored inside an APEX. + */ + @VisibleForTesting + public void readApexPrivAppPermissions(XmlPullParser parser, File permFile, + Path apexDirectoryPath) throws IOException, XmlPullParserException { + final String moduleName = + getApexModuleNameFromFilePath(permFile.toPath(), apexDirectoryPath); final ArrayMap<String, ArraySet<String>> privAppPermissions; if (mApexPrivAppPermissions.containsKey(moduleName)) { privAppPermissions = mApexPrivAppPermissions.get(moduleName); diff --git a/core/jni/Android.bp b/core/jni/Android.bp index adcbb425d1cf..1d181dd9f434 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -195,7 +195,6 @@ cc_library_shared { "android_util_FileObserver.cpp", "android/opengl/poly_clip.cpp", // TODO: .arm "android/opengl/util.cpp", - "android_server_NetworkManagementSocketTagger.cpp", "android_ddm_DdmHandleNativeHeap.cpp", "android_backup_BackupDataInput.cpp", "android_backup_BackupDataOutput.cpp", @@ -244,7 +243,6 @@ cc_library_shared { "android.hardware.camera.device@3.2", "libandroid_net", "libandroidicu", - "libbpf_android", "libnetdutils", "libmemtrack", "libandroidfw", diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 0f98b74441a7..1c4107a12b74 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -164,7 +164,6 @@ extern int register_android_text_AndroidCharacter(JNIEnv *env); extern int register_android_text_Hyphenator(JNIEnv *env); extern int register_android_opengl_classes(JNIEnv *env); extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env); -extern int register_android_server_NetworkManagementSocketTagger(JNIEnv* env); extern int register_android_backup_BackupDataInput(JNIEnv *env); extern int register_android_backup_BackupDataOutput(JNIEnv *env); extern int register_android_backup_FileBackupHelperBase(JNIEnv *env); @@ -1618,7 +1617,6 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_media_midi), REG_JNI(register_android_opengl_classes), - REG_JNI(register_android_server_NetworkManagementSocketTagger), REG_JNI(register_android_ddm_DdmHandleNativeHeap), REG_JNI(register_android_backup_BackupDataInput), REG_JNI(register_android_backup_BackupDataOutput), diff --git a/core/jni/OWNERS b/core/jni/OWNERS index a17d807f946b..3a9957bcffee 100644 --- a/core/jni/OWNERS +++ b/core/jni/OWNERS @@ -63,6 +63,7 @@ per-file com_android_internal_net_* = file:/services/core/java/com/android/serve ### Graphics ### per-file android_graphics_* = file:/graphics/java/android/graphics/OWNERS per-file android_hardware_HardwareBuffer.cpp = file:/graphics/java/android/graphics/OWNERS +per-file android_hardware_SyncFence.cpp = file:/graphics/java/android/graphics/OWNERS ### Text ### per-file android_text_* = file:/core/java/android/text/OWNERS diff --git a/core/jni/android_os_HwRemoteBinder.cpp b/core/jni/android_os_HwRemoteBinder.cpp index 3af55fe810fc..d2d7213e5761 100644 --- a/core/jni/android_os_HwRemoteBinder.cpp +++ b/core/jni/android_os_HwRemoteBinder.cpp @@ -81,27 +81,37 @@ public: void binderDied(const wp<hardware::IBinder>& who) { - if (mObject != NULL) { - JNIEnv* env = javavm_to_jnienv(mVM); + JNIEnv* env = javavm_to_jnienv(mVM); + + // Serialize with our containing HwBinderDeathRecipientList so that we can't + // delete the global ref on object while the list is being iterated. + sp<HwBinderDeathRecipientList> list = mList.promote(); + if (list == nullptr) return; - env->CallStaticVoidMethod(gProxyOffsets.proxy_class, gProxyOffsets.sendDeathNotice, mObject, mCookie); + jobject object; + { + AutoMutex _l(list->lock()); + + // this function now owns the global ref - to the rest of the code, it looks like + // this binder already died, but we won't actually delete the reference until + // the Java code has processed the death + object = mObject; + + // Demote from strong ref to weak for after binderDied() has been delivered, + // to allow the DeathRecipient and BinderProxy to be GC'd if no longer needed. + mObjectWeak = env->NewWeakGlobalRef(mObject); + mObject = nullptr; + } + + if (object != nullptr) { + env->CallStaticVoidMethod(gProxyOffsets.proxy_class, gProxyOffsets.sendDeathNotice, + object, mCookie); if (env->ExceptionCheck()) { ALOGE("Uncaught exception returned from death notification."); env->ExceptionClear(); } - // Serialize with our containing HwBinderDeathRecipientList so that we can't - // delete the global ref on mObject while the list is being iterated. - sp<HwBinderDeathRecipientList> list = mList.promote(); - if (list != NULL) { - AutoMutex _l(list->lock()); - - // Demote from strong ref to weak after binderDied() has been delivered, - // to allow the DeathRecipient and BinderProxy to be GC'd if no longer needed. - mObjectWeak = env->NewWeakGlobalRef(mObject); - env->DeleteGlobalRef(mObject); - mObject = NULL; - } + env->DeleteGlobalRef(object); } } @@ -115,7 +125,7 @@ public: } } - bool matches(jobject obj) { + bool matchesLocked(jobject obj) { bool result; JNIEnv* env = javavm_to_jnienv(mVM); @@ -129,7 +139,7 @@ public: return result; } - void warnIfStillLive() { + void warnIfStillLiveLocked() { if (mObject != NULL) { // Okay, something is wrong -- we have a hard reference to a live death // recipient on the VM side, but the list is being torn down. @@ -176,7 +186,7 @@ HwBinderDeathRecipientList::~HwBinderDeathRecipientList() { AutoMutex _l(mLock); for (const sp<HwBinderDeathRecipient>& deathRecipient : mList) { - deathRecipient->warnIfStillLive(); + deathRecipient->warnIfStillLiveLocked(); } } @@ -201,7 +211,7 @@ sp<HwBinderDeathRecipient> HwBinderDeathRecipientList::find(jobject recipient) { AutoMutex _l(mLock); for(auto iter = mList.rbegin(); iter != mList.rend(); iter++) { - if ((*iter)->matches(recipient)) { + if ((*iter)->matchesLocked(recipient)) { return (*iter); } } diff --git a/core/jni/android_server_NetworkManagementSocketTagger.cpp b/core/jni/android_server_NetworkManagementSocketTagger.cpp deleted file mode 100644 index 9734ab9b9e1d..000000000000 --- a/core/jni/android_server_NetworkManagementSocketTagger.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2011, 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. - */ - -#define LOG_TAG "NMST_QTagUidNative" - -#include <android/multinetwork.h> -#include <cutils/qtaguid.h> -#include <errno.h> -#include <fcntl.h> -#include <nativehelper/JNIPlatformHelp.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <utils/Log.h> -#include <utils/misc.h> - -#include "jni.h" - -namespace android { - -static jint tagSocketFd(JNIEnv* env, jclass, jobject fileDescriptor, - jint tagNum, jint uid) { - int userFd = jniGetFDFromFileDescriptor(env, fileDescriptor); - - if (env->ExceptionCheck()) { - ALOGE("Can't get FileDescriptor num"); - return (jint)-1; - } - - int res = android_tag_socket_with_uid(userFd, tagNum, uid); - if (res < 0) { - return (jint)-errno; - } - return (jint)res; -} - -static jint untagSocketFd(JNIEnv* env, jclass, jobject fileDescriptor) { - int userFd = jniGetFDFromFileDescriptor(env, fileDescriptor); - - if (env->ExceptionCheck()) { - ALOGE("Can't get FileDescriptor num"); - return (jint)-1; - } - - int res = android_untag_socket(userFd); - if (res < 0) { - return (jint)-errno; - } - return (jint)res; -} - -static const JNINativeMethod gQTagUidMethods[] = { - { "native_tagSocketFd", "(Ljava/io/FileDescriptor;II)I", (void*)tagSocketFd}, - { "native_untagSocketFd", "(Ljava/io/FileDescriptor;)I", (void*)untagSocketFd}, -}; - -int register_android_server_NetworkManagementSocketTagger(JNIEnv* env) { - return jniRegisterNativeMethods(env, "com/android/server/NetworkManagementSocketTagger", gQTagUidMethods, NELEM(gQTagUidMethods)); -} - -}; diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index 61b91ddaa2e7..13ca13322cc7 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -873,7 +873,7 @@ void signalExceptionForError(JNIEnv* env, jobject obj, status_t err, const char* exceptionToThrow; char msg[128]; // TransactionTooLargeException is a checked exception, only throw from certain methods. - // FIXME: Transaction too large is the most common reason for FAILED_TRANSACTION + // TODO(b/28321379): Transaction size is the most common cause for FAILED_TRANSACTION // but it is not the only one. The Binder driver can return BR_FAILED_REPLY // for other reasons also, such as if the transaction is malformed or // refers to an FD that has been closed. We should change the driver @@ -890,8 +890,9 @@ void signalExceptionForError(JNIEnv* env, jobject obj, status_t err, exceptionToThrow = (canThrowRemoteException) ? "android/os/DeadObjectException" : "java/lang/RuntimeException"; - snprintf(msg, sizeof(msg)-1, - "Transaction failed on small parcel; remote process probably died"); + snprintf(msg, sizeof(msg) - 1, + "Transaction failed on small parcel; remote process probably died, but " + "this could also be caused by running out of binder buffer space"); } jniThrowException(env, exceptionToThrow, msg); } break; diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index aacf700b1168..597167026d19 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -202,6 +202,8 @@ static constexpr unsigned int STORAGE_DIR_CHECK_MAX_INTERVAL_US = 1000; */ static constexpr int STORAGE_DIR_CHECK_TIMEOUT_US = 1000 * 1000 * 60 * 5; +static void WaitUntilDirReady(const std::string& target, fail_fn_t fail_fn); + /** * A helper class containing accounting information for USAPs. */ @@ -1249,7 +1251,11 @@ static void isolateAppData(JNIEnv* env, const std::vector<std::string>& merged_d auto volPath = StringPrintf("%s/%s", externalPrivateMountPath, ent->d_name); auto cePath = StringPrintf("%s/user", volPath.c_str()); auto dePath = StringPrintf("%s/user_de", volPath.c_str()); + // Wait until dir user is created. + WaitUntilDirReady(cePath.c_str(), fail_fn); MountAppDataTmpFs(cePath.c_str(), fail_fn); + // Wait until dir user_de is created. + WaitUntilDirReady(dePath.c_str(), fail_fn); MountAppDataTmpFs(dePath.c_str(), fail_fn); } closedir(dir); @@ -1620,7 +1626,7 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, } // Also prefetch standalone system server jars. The reason for doing this here is the same // as above. - env->CallStaticObjectMethod(gZygoteInitClass, gPrefetchStandaloneSystemServerJars); + env->CallStaticVoidMethod(gZygoteInitClass, gPrefetchStandaloneSystemServerJars); if (env->ExceptionCheck()) { env->ExceptionClear(); } diff --git a/core/proto/android/service/diskstats.proto b/core/proto/android/service/diskstats.proto index f79de394a50f..ad3d67346292 100644 --- a/core/proto/android/service/diskstats.proto +++ b/core/proto/android/service/diskstats.proto @@ -99,6 +99,8 @@ message DiskStatsFreeSpaceProto { FOLDER_CACHE = 1; // System folder FOLDER_SYSTEM = 2; + // Metadata folder + FOLDER_METADATA = 3; } // Which folder? optional Folder folder = 1; diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 7f95ca912366..111b694d65f3 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1945,6 +1945,11 @@ <permission android:name="android.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE" android:protectionLevel="signature" /> + <!-- @SystemApi @hide Allows an application to manage ethernet networks. + <p>Not for use by third-party or privileged applications. --> + <permission android:name="android.permission.MANAGE_ETHERNET_NETWORKS" + android:protectionLevel="signature" /> + <!-- ======================================= --> <!-- Permissions for short range, peripheral networks --> <!-- ======================================= --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 590fcf46f373..ad368a819bd4 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1277,6 +1277,8 @@ <java-symbol type="array" name="vendor_required_apps_managed_user" /> <java-symbol type="array" name="vendor_required_apps_managed_profile" /> <java-symbol type="array" name="vendor_required_apps_managed_device" /> + <java-symbol type="array" name="vendor_required_attestation_certificates" /> + <java-symbol type="string" name="vendor_required_attestation_revocation_list_url" /> <java-symbol type="array" name="vendor_disallowed_apps_managed_user" /> <java-symbol type="array" name="vendor_disallowed_apps_managed_profile" /> <java-symbol type="array" name="vendor_disallowed_apps_managed_device" /> diff --git a/core/res/res/values/vendor_required_attestation_certificates.xml b/core/res/res/values/vendor_required_attestation_certificates.xml new file mode 100644 index 000000000000..ff7313ed1b4d --- /dev/null +++ b/core/res/res/values/vendor_required_attestation_certificates.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (C) 2022 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. + */ +--> +<resources> + <!-- The PEM-encoded certificates added here are used for verifying attestations. + The trustworthiness of the attestation depends on the root certificate of the chain. + + Certificates that can be used can be retrieved from: + https://developer.android.com/training/articles/security-key-attestation#root_certificate. + + If not already present in resource overlay, please add + vendor_required_attestation_certificates.xml (matching this file) in vendor overlay + with <item></item> of the PEM-encoded root certificates. + --> + <string-array translatable="false" name="vendor_required_attestation_certificates"> + </string-array> + + <!-- Url to mapping of revoked certificates' hex encoded serial numbers. Example format + can be found at: + https://developer.android.com/training/articles/security-key-attestation#certificate_status + --> + <string translatable="false" name="vendor_required_attestation_revocation_list_url"></string> +</resources> diff --git a/core/tests/bandwidthtests/Android.bp b/core/tests/bandwidthtests/Android.bp index f1ecd45073eb..d0b42f783bef 100644 --- a/core/tests/bandwidthtests/Android.bp +++ b/core/tests/bandwidthtests/Android.bp @@ -23,6 +23,7 @@ package { android_test { name: "BandwidthTests", + defaults: ["framework-connectivity-test-defaults"], // Include all test java files. srcs: ["src/**/*.java"], libs: [ diff --git a/core/tests/benchmarks/Android.bp b/core/tests/benchmarks/Android.bp index 4cd546753dbf..0888776f1683 100644 --- a/core/tests/benchmarks/Android.bp +++ b/core/tests/benchmarks/Android.bp @@ -27,6 +27,7 @@ package { java_library { name: "frameworks-base-core-benchmarks", + defaults: ["framework-connectivity-test-defaults"], installable: true, srcs: ["src/**/*.java"], libs: ["caliper-api-target"], diff --git a/core/tests/coretests/src/android/app/timedetector/TelephonyTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/TelephonyTimeSuggestionTest.java index 4b64dfc84fb7..cc7557977e80 100644 --- a/core/tests/coretests/src/android/app/timedetector/TelephonyTimeSuggestionTest.java +++ b/core/tests/coretests/src/android/app/timedetector/TelephonyTimeSuggestionTest.java @@ -45,13 +45,13 @@ public class TelephonyTimeSuggestionTest { assertEquals(two, one); } - builder1.setUtcTime(new TimestampedValue<>(1111L, 2222L)); + builder1.setUnixEpochTime(new TimestampedValue<>(1111L, 2222L)); { TelephonyTimeSuggestion one = builder1.build(); assertEquals(one, one); } - builder2.setUtcTime(new TimestampedValue<>(1111L, 2222L)); + builder2.setUnixEpochTime(new TimestampedValue<>(1111L, 2222L)); { TelephonyTimeSuggestion one = builder1.build(); TelephonyTimeSuggestion two = builder2.build(); @@ -61,7 +61,7 @@ public class TelephonyTimeSuggestionTest { TelephonyTimeSuggestion.Builder builder3 = new TelephonyTimeSuggestion.Builder(SLOT_INDEX + 1); - builder3.setUtcTime(new TimestampedValue<>(1111L, 2222L)); + builder3.setUnixEpochTime(new TimestampedValue<>(1111L, 2222L)); { TelephonyTimeSuggestion one = builder1.build(); TelephonyTimeSuggestion three = builder3.build(); @@ -84,7 +84,7 @@ public class TelephonyTimeSuggestionTest { TelephonyTimeSuggestion.Builder builder = new TelephonyTimeSuggestion.Builder(SLOT_INDEX); assertRoundTripParcelable(builder.build()); - builder.setUtcTime(new TimestampedValue<>(1111L, 2222L)); + builder.setUnixEpochTime(new TimestampedValue<>(1111L, 2222L)); assertRoundTripParcelable(builder.build()); // DebugInfo should also be stored (but is not checked by equals() diff --git a/core/tests/coretests/src/android/content/OWNERS b/core/tests/coretests/src/android/content/OWNERS index 0b945895ad7f..a69c6ffef8d8 100644 --- a/core/tests/coretests/src/android/content/OWNERS +++ b/core/tests/coretests/src/android/content/OWNERS @@ -1,6 +1,7 @@ per-file AssetTest.java = file:/core/java/android/content/res/OWNERS -per-file ContextTest.java = file:/services/core/java/com/android/server/wm/OWNERS +per-file Context* = file:/services/core/java/com/android/server/wm/OWNERS +per-file Context* = charlesccchen@google.com per-file *Launcher* = file:/core/java/android/content/pm/LAUNCHER_OWNERS per-file *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS -per-file ComponentCallbacksControllerTest = file:/services/core/java/com/android/server/wm/OWNERS -per-file ComponentCallbacksControllerTest = charlesccchen@google.com +per-file *ComponentCallbacks* = file:/services/core/java/com/android/server/wm/OWNERS +per-file *ComponentCallbacks* = charlesccchen@google.com diff --git a/core/tests/coretests/src/android/net/NetworkPolicyTest.kt b/core/tests/coretests/src/android/net/NetworkPolicyTest.kt index 3c8f90c9c0f8..6360a2deb544 100644 --- a/core/tests/coretests/src/android/net/NetworkPolicyTest.kt +++ b/core/tests/coretests/src/android/net/NetworkPolicyTest.kt @@ -16,7 +16,9 @@ package android.net +import android.net.NetworkStats.METERED_YES import android.net.NetworkTemplate.MATCH_BLUETOOTH +import android.net.NetworkTemplate.MATCH_CARRIER import android.net.NetworkTemplate.MATCH_ETHERNET import android.net.NetworkTemplate.MATCH_MOBILE import android.net.NetworkTemplate.MATCH_WIFI @@ -39,11 +41,19 @@ class NetworkPolicyTest { @Test fun testTemplateBackupRestore() { assertPolicyBackupRestore(createTestPolicyForTemplate( - NetworkTemplate.buildTemplateWifi(TEST_WIFI_NETWORK_KEY1))) + NetworkTemplate.Builder(MATCH_WIFI) + .setWifiNetworkKeys(setOf(TEST_WIFI_NETWORK_KEY1)) + .build())) assertPolicyBackupRestore(createTestPolicyForTemplate( - NetworkTemplate.buildTemplateMobileAll(TEST_IMSI1))) + NetworkTemplate.Builder(MATCH_MOBILE) + .setSubscriberIds(setOf(TEST_IMSI1)) + .setMeteredness(METERED_YES) + .build())) assertPolicyBackupRestore(createTestPolicyForTemplate( - NetworkTemplate.buildTemplateCarrierMetered(TEST_IMSI1))) + NetworkTemplate.Builder(MATCH_CARRIER) + .setSubscriberIds(setOf(TEST_IMSI1)) + .setMeteredness(METERED_YES) + .build())) } private fun createTestPolicyForTemplate(template: NetworkTemplate): NetworkPolicy { diff --git a/core/tests/coretests/src/android/widget/OWNERS b/core/tests/coretests/src/android/widget/OWNERS new file mode 100644 index 000000000000..5a9aed334035 --- /dev/null +++ b/core/tests/coretests/src/android/widget/OWNERS @@ -0,0 +1,5 @@ +include /core/java/android/widget/OWNERS + +per-file *SuggestionsPopup* = file:/core/java/android/text/OWNERS + +per-file *FloatingToolbar*, *SelectionToolbar* = file:/core/java/android/view/textclassifier/OWNERS
\ No newline at end of file diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java index 40ef04a5e369..152992cc57a4 100644 --- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java +++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java @@ -17,6 +17,7 @@ package android.widget; import static android.widget.espresso.CustomViewActions.longPressAtRelativeCoordinates; +import static android.widget.espresso.DragHandleUtils.assertNoSelectionHandles; import static android.widget.espresso.DragHandleUtils.onHandleView; import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarContainsItem; import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarDoesNotContainItem; @@ -426,6 +427,41 @@ public class TextViewActivityTest { } @Test + public void testSelectionOnCreateActionModeReturnsFalse() throws Throwable { + final String text = "hello world"; + mActivityRule.runOnUiThread(() -> { + final TextView textView = mActivity.findViewById(R.id.textview); + textView.setText(text); + textView.setCustomSelectionActionModeCallback( + new ActionMode.Callback() { + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + return false; + } + + @Override + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + return false; + } + + @Override + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + return false; + } + + + @Override + public void onDestroyActionMode(ActionMode mode) { + } + }); + }); + mInstrumentation.waitForIdleSync(); + onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf("d"))); + mInstrumentation.waitForIdleSync(); + assertNoSelectionHandles(); + } + + @Test public void testSelectionRemovedWhenNonselectableTextLosesFocus() throws Throwable { final TextLinks.TextLink textLink = addLinkifiedTextToTextView(R.id.nonselectable_textview); final int position = (textLink.getStart() + textLink.getEnd()) / 2; diff --git a/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java index 1cc1894a916a..a48a8822f4c0 100644 --- a/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java @@ -16,6 +16,9 @@ package com.android.internal.os; +import static android.net.NetworkStats.DEFAULT_NETWORK_NO; +import static android.net.NetworkStats.METERED_NO; +import static android.net.NetworkStats.ROAMING_NO; import static android.os.BatteryStats.POWER_DATA_UNAVAILABLE; import static com.google.common.truth.Truth.assertThat; @@ -89,7 +92,8 @@ public class MobileRadioPowerCalculatorTest { // Note application network activity NetworkStats networkStats = new NetworkStats(10000, 1) - .insertEntry("cellular", APP_UID, 0, 0, 1000, 100, 2000, 20, 100); + .addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 100, 2000, 20, 100)); mStatsRule.setNetworkStats(networkStats); ModemActivityInfo mai = new ModemActivityInfo(10000, 2000, 3000, @@ -150,7 +154,8 @@ public class MobileRadioPowerCalculatorTest { // Note application network activity NetworkStats networkStats = new NetworkStats(10000, 1) - .insertEntry("cellular", APP_UID, 0, 0, 1000, 100, 2000, 20, 100); + .addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 100, 2000, 20, 100)); mStatsRule.setNetworkStats(networkStats); ModemActivityInfo mai = new ModemActivityInfo(10000, 2000, 3000, diff --git a/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java index e7ce9a03f18a..0d944e961d1e 100644 --- a/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java @@ -16,7 +16,9 @@ package com.android.internal.os; - +import static android.net.NetworkStats.DEFAULT_NETWORK_NO; +import static android.net.NetworkStats.METERED_NO; +import static android.net.NetworkStats.ROAMING_NO; import static android.os.BatteryStats.POWER_DATA_UNAVAILABLE; import static com.google.common.truth.Truth.assertThat; @@ -67,8 +69,10 @@ public class WifiPowerCalculatorTest { new int[]{NetworkCapabilities.TRANSPORT_WIFI}); NetworkStats networkStats = new NetworkStats(10000, 1) - .insertEntry("wifi", APP_UID, 0, 0, 1000, 100, 2000, 20, 100) - .insertEntry("wifi", Process.WIFI_UID, 0, 0, 1111, 111, 2222, 22, 111); + .addEntry(new NetworkStats.Entry("wifi", APP_UID, 0, 0, METERED_NO, + ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 100, 2000, 20, 100)) + .addEntry(new NetworkStats.Entry("wifi", Process.WIFI_UID, 0, 0, METERED_NO, + ROAMING_NO, DEFAULT_NETWORK_NO, 1111, 111, 2222, 22, 111)); mStatsRule.setNetworkStats(networkStats); return batteryStats; diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java index 597ea14df56d..12e52c62b7c7 100644 --- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java +++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java @@ -288,9 +288,8 @@ public class HdmiAudioSystemClientTest { } @Override - public void addVendorCommandListener(final IHdmiVendorCommandListener listener, - final int deviceType) { - } + public void addVendorCommandListener( + final IHdmiVendorCommandListener listener, final int vendorId) {} @Override public void sendVendorCommand(final int deviceType, final int targetAddress, diff --git a/core/tests/utillib/Android.bp b/core/tests/utillib/Android.bp index d40d1d2bb6e2..1d5c16c7a536 100644 --- a/core/tests/utillib/Android.bp +++ b/core/tests/utillib/Android.bp @@ -23,6 +23,7 @@ package { java_library { name: "frameworks-core-util-lib", + defaults: ["framework-connectivity-test-defaults"], srcs: ["**/*.java"], diff --git a/data/etc/Android.bp b/data/etc/Android.bp index be1e2b2247fb..dc077583963e 100644 --- a/data/etc/Android.bp +++ b/data/etc/Android.bp @@ -1,4 +1,4 @@ -// Copyright (C} 2018 The Android Open Source Project +// Copyright (C) 2018 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. @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. - // Sysconfig files package { @@ -134,13 +133,6 @@ prebuilt_etc { } prebuilt_etc { - name: "privapp_whitelist_com.android.networkstack.tethering", - sub_dir: "permissions", - src: "com.android.networkstack.tethering.xml", - filename_from_src: true, -} - -prebuilt_etc { name: "privapp_whitelist_com.android.provision", system_ext_specific: true, sub_dir: "permissions", diff --git a/data/etc/com.android.networkstack.tethering.xml b/data/etc/com.android.networkstack.tethering.xml deleted file mode 100644 index f26a9616e07a..000000000000 --- a/data/etc/com.android.networkstack.tethering.xml +++ /dev/null @@ -1,28 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2021 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 ---> - -<permissions> - <privapp-permissions package="com.android.networkstack.tethering"> - <permission name="android.permission.BLUETOOTH_PRIVILEGED" /> - <permission name="android.permission.MANAGE_USB"/> - <permission name="android.permission.MODIFY_PHONE_STATE"/> - <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/> - <permission name="android.permission.TETHER_PRIVILEGED"/> - <permission name="android.permission.UPDATE_APP_OPS_STATS"/> - <permission name="android.permission.UPDATE_DEVICE_STATS"/> - </privapp-permissions> -</permissions> diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index fa6b086b9259..82aff6027653 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -20,13 +20,6 @@ This XML file declares which signature|privileged permissions should be granted applications that come with the platform --> <permissions> - <privapp-permissions package="android.ext.services"> - <permission name="android.permission.PROVIDE_RESOLVER_RANKER_SERVICE" /> - <permission name="android.permission.MONITOR_DEFAULT_SMS_PACKAGE" /> - <permission name="android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE" /> - <permission name="android.permission.INTERACT_ACROSS_USERS" /> - </privapp-permissions> - <!-- Needed for Build.getSerial(), which is used to send a unique number for serial, per HUIG. --> <privapp-permissions package="android.car.usb.handler"> <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/> @@ -274,6 +267,7 @@ applications that come with the platform <privapp-permissions package="com.android.server.telecom"> <permission name="android.permission.BIND_CONNECTION_SERVICE"/> <permission name="android.permission.BIND_INCALL_SERVICE"/> + <permission name="android.permission.BLUETOOTH_PRIVILEGED"/> <permission name="android.permission.CALL_PRIVILEGED"/> <permission name="android.permission.HANDLE_CAR_MODE_CHANGES"/> <permission name="android.permission.INTERACT_ACROSS_USERS"/> @@ -393,6 +387,7 @@ applications that come with the platform <!-- Permission required for CTS test - TrustTestCases --> <permission name="android.permission.PROVIDE_TRUST_AGENT" /> <permission name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" /> + <permission name="android.permission.TRUST_LISTENER" /> <!-- Permissions required for Incremental CTS tests --> <permission name="com.android.permission.USE_INSTALLER_V2"/> <permission name="android.permission.LOADER_USAGE_STATS"/> @@ -461,7 +456,11 @@ applications that come with the platform <!-- Permission needed for CTS test - WifiManagerTest --> <permission name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS" /> <permission name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" /> + <permission name="android.permission.NEARBY_WIFI_DEVICES" /> <permission name="android.permission.OVERRIDE_WIFI_CONFIG" /> + <!-- Permission needed for CTS test - ConcurrencyTest#testP2pExternalApprover + P2P external approver API sets require MANAGE_WIFI_AUTO_JOIN permission. --> + <permission name="android.permission.MANAGE_WIFI_AUTO_JOIN" /> <!-- Permission required for CTS test CarrierMessagingServiceWrapperTest --> <permission name="android.permission.BIND_CARRIER_SERVICES"/> <!-- Permission required for CTS test - MusicRecognitionManagerTest --> @@ -519,17 +518,6 @@ applications that come with the platform <permission name="android.permission.INTERACT_ACROSS_USERS"/> </privapp-permissions> - <privapp-permissions package="com.android.traceur"> - <!-- Permissions required to receive BUGREPORT_STARTED intent --> - <permission name="android.permission.DUMP"/> - <!-- Permissions required to start/stop tracing --> - <permission name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND"/> - <!-- Permissions required for quick settings tile --> - <permission name="android.permission.STATUS_BAR"/> - <!-- Permissions required to query Betterbug --> - <permission name="android.permission.QUERY_ALL_PACKAGES"/> - </privapp-permissions> - <privapp-permissions package="com.android.tv"> <permission name="android.permission.CHANGE_HDMI_CEC_ACTIVE_SOURCE"/> <permission name="android.permission.DVB_DEVICE"/> diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 42e470b7f660..5bfc32177ec0 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -1611,7 +1611,7 @@ public class Paint { * Return the paint's Align value for drawing text. This controls how the * text is positioned relative to its origin. LEFT align means that all of * the text will be drawn to the right of its origin (i.e. the origin - * specifieds the LEFT edge of the text) and so on. + * specifies the LEFT edge of the text) and so on. * * @return the paint's Align value for drawing text. */ @@ -1623,7 +1623,7 @@ public class Paint { * Set the paint's text alignment. This controls how the * text is positioned relative to its origin. LEFT align means that all of * the text will be drawn to the right of its origin (i.e. the origin - * specifieds the LEFT edge of the text) and so on. + * specifies the LEFT edge of the text) and so on. * * @param align set the paint's Align value for drawing text. */ diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java index 9b2effcde1d3..0fadae23556d 100644 --- a/graphics/java/android/graphics/SurfaceTexture.java +++ b/graphics/java/android/graphics/SurfaceTexture.java @@ -288,7 +288,7 @@ public class SurfaceTexture { * context at a time. * * @param texName The name of the OpenGL ES texture that will be created. This texture name - * must be unusued in the OpenGL ES context that is current on the calling thread. + * must be unused in the OpenGL ES context that is current on the calling thread. */ public void attachToGLContext(int texName) { int err = nativeAttachToGLContext(texName); diff --git a/identity/java/android/security/identity/IdentityCredential.java b/identity/java/android/security/identity/IdentityCredential.java index cdf746fc9900..f440b693a5b3 100644 --- a/identity/java/android/security/identity/IdentityCredential.java +++ b/identity/java/android/security/identity/IdentityCredential.java @@ -454,7 +454,8 @@ public abstract class IdentityCredential { * @param challenge is a non-empty byte array whose contents should be unique, fresh and * provided by the issuing authority. The value provided is embedded in the * generated CBOR and enables the issuing authority to verify that the - * returned proof is fresh. + * returned proof is fresh. Implementations are required to support + * challenges at least 32 bytes of length. * @return the COSE_Sign1 data structure above */ public @NonNull byte[] proveOwnership(@NonNull byte[] challenge) { @@ -485,7 +486,8 @@ public abstract class IdentityCredential { * @param challenge is a non-empty byte array whose contents should be unique, fresh and * provided by the issuing authority. The value provided is embedded in the * generated CBOR and enables the issuing authority to verify that the - * returned proof is fresh. + * returned proof is fresh. Implementations are required to support + * challenges at least 32 bytes of length. * @return the COSE_Sign1 data structure above */ public @NonNull byte[] delete(@NonNull byte[] challenge) { diff --git a/identity/java/android/security/identity/WritableIdentityCredential.java b/identity/java/android/security/identity/WritableIdentityCredential.java index 305d0ead0652..6d569648f2c6 100644 --- a/identity/java/android/security/identity/WritableIdentityCredential.java +++ b/identity/java/android/security/identity/WritableIdentityCredential.java @@ -59,7 +59,8 @@ public abstract class WritableIdentityCredential { * @param challenge is a non-empty byte array whose contents should be unique, fresh and * provided by the issuing authority. The value provided is embedded in the * attestation extension and enables the issuing authority to verify that the - * attestation certificate is fresh. + * attestation certificate is fresh. Implementations are required to support + * challenges at least 32 bytes of length. * @return the X.509 certificate for this credential's CredentialKey. */ public abstract @NonNull Collection<X509Certificate> getCredentialKeyCertificateChain( diff --git a/keystore/OWNERS b/keystore/OWNERS index a63ca46df2a6..7ab9d761e236 100644 --- a/keystore/OWNERS +++ b/keystore/OWNERS @@ -1,4 +1,4 @@ +eranm@google.com jbires@google.com jdanis@google.com -robbarnes@google.com swillden@google.com diff --git a/keystore/java/android/security/KeyStore2.java b/keystore/java/android/security/KeyStore2.java index 1034847b761b..3d53cfb388e1 100644 --- a/keystore/java/android/security/KeyStore2.java +++ b/keystore/java/android/security/KeyStore2.java @@ -108,7 +108,7 @@ public class KeyStore2 { try { return request.execute(service); } catch (ServiceSpecificException e) { - throw getKeyStoreException(e.errorCode); + throw getKeyStoreException(e.errorCode, e.getMessage()); } catch (RemoteException e) { if (firstTry) { Log.w(TAG, "Looks like we may have lost connection to the Keystore " @@ -120,7 +120,7 @@ public class KeyStore2 { firstTry = false; } else { Log.e(TAG, "Cannot connect to Keystore daemon.", e); - throw new KeyStoreException(ResponseCode.SYSTEM_ERROR, ""); + throw new KeyStoreException(ResponseCode.SYSTEM_ERROR, "", e.getMessage()); } } } @@ -322,26 +322,32 @@ public class KeyStore2 { } } - static KeyStoreException getKeyStoreException(int errorCode) { + static KeyStoreException getKeyStoreException(int errorCode, String serviceErrorMessage) { if (errorCode > 0) { // KeyStore layer error switch (errorCode) { case ResponseCode.LOCKED: - return new KeyStoreException(errorCode, "User authentication required"); + return new KeyStoreException(errorCode, "User authentication required", + serviceErrorMessage); case ResponseCode.UNINITIALIZED: - return new KeyStoreException(errorCode, "Keystore not initialized"); + return new KeyStoreException(errorCode, "Keystore not initialized", + serviceErrorMessage); case ResponseCode.SYSTEM_ERROR: - return new KeyStoreException(errorCode, "System error"); + return new KeyStoreException(errorCode, "System error", serviceErrorMessage); case ResponseCode.PERMISSION_DENIED: - return new KeyStoreException(errorCode, "Permission denied"); + return new KeyStoreException(errorCode, "Permission denied", + serviceErrorMessage); case ResponseCode.KEY_NOT_FOUND: - return new KeyStoreException(errorCode, "Key not found"); + return new KeyStoreException(errorCode, "Key not found", serviceErrorMessage); case ResponseCode.VALUE_CORRUPTED: - return new KeyStoreException(errorCode, "Key blob corrupted"); + return new KeyStoreException(errorCode, "Key blob corrupted", + serviceErrorMessage); case ResponseCode.KEY_PERMANENTLY_INVALIDATED: - return new KeyStoreException(errorCode, "Key permanently invalidated"); + return new KeyStoreException(errorCode, "Key permanently invalidated", + serviceErrorMessage); default: - return new KeyStoreException(errorCode, String.valueOf(errorCode)); + return new KeyStoreException(errorCode, String.valueOf(errorCode), + serviceErrorMessage); } } else { // Keymaster layer error @@ -350,10 +356,12 @@ public class KeyStore2 { // The name of this parameter significantly differs between Keymaster and // framework APIs. Use the framework wording to make life easier for developers. return new KeyStoreException(errorCode, - "Invalid user authentication validity duration"); + "Invalid user authentication validity duration", + serviceErrorMessage); default: return new KeyStoreException(errorCode, - KeymasterDefs.getErrorMessage(errorCode)); + KeymasterDefs.getErrorMessage(errorCode), + serviceErrorMessage); } } } diff --git a/keystore/java/android/security/KeyStoreException.java b/keystore/java/android/security/KeyStoreException.java index 30389a29d342..54184dbf6e08 100644 --- a/keystore/java/android/security/KeyStoreException.java +++ b/keystore/java/android/security/KeyStoreException.java @@ -16,25 +16,458 @@ package android.security; +import android.annotation.IntDef; +import android.annotation.Nullable; import android.annotation.TestApi; +import android.security.keymaster.KeymasterDefs; +import android.system.keystore2.ResponseCode; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.HashMap; +import java.util.Map; /** - * KeyStore/keymaster exception with positive error codes coming from the KeyStore and negative - * ones from keymaster. + * Exception containing information about the failure at the Keystore / KeyMint layer while + * generating or using a key. * - * @hide + * The public error codes indicate the cause of the error and the methods indicate whether + * it's a system/key issue and whether re-trying the operation (with the same key or a new key) + * is likely to succeed. */ -@TestApi public class KeyStoreException extends Exception { + /** + * This error code is for mapping errors that the caller will not know about. If the caller is + * targeting an API level earlier than the one the error was introduced in, then the error will + * be mapped to this one. + * In API level 33 no errors map to this error. + */ + public static final int ERROR_OTHER = 1; + /** + * Indicating the key could not be used because the user needs to authenticate first. + * See + * {@link android.security.keystore.KeyGenParameterSpec.Builder#setUserAuthenticationRequired(boolean)}. + */ + public static final int ERROR_USER_AUTHENTICATION_REQUIRED = 2; + /** + * Indicating that {@code load()} has not been called on the Keystore instance, or an attempt + * has been made to generate an authorization bound key while the user has not set a lock + * screen knowledge factor (LSKF). Instruct the user to set an LSKF and retry. + */ + public static final int ERROR_KEYSTORE_UNINITIALIZED = 3; + /** + * An internal system error - refer to {@link #isTransientFailure()} to determine whether + * re-trying the operation is likely to yield different results. + */ + public static final int ERROR_INTERNAL_SYSTEM_ERROR = 4; + /** + * The caller has requested key parameters or operation which are only available to system + * or privileged apps. + */ + public static final int ERROR_PERMISSION_DENIED = 5; + /** + * The key the operation refers to doesn't exist. + */ + public static final int ERROR_KEY_DOES_NOT_EXIST = 6; + /** + * The key is corrupted and could not be recovered. + */ + public static final int ERROR_KEY_CORRUPTED = 7; + /** + * The error related to inclusion of device identifiers in the attestation record. + */ + public static final int ERROR_ID_ATTESTATION_FAILURE = 8; + /** + * The attestation challenge specified is too large. + */ + public static final int ERROR_ATTESTATION_CHALLENGE_TOO_LARGE = 9; + /** + * General error in the KeyMint layer. + */ + public static final int ERROR_KEYMINT_FAILURE = 10; + /** + * Failure in the Keystore layer. + */ + public static final int ERROR_KEYSTORE_FAILURE = 11; + /** + * The feature the caller is trying to use is not implemented by the underlying + * KeyMint implementation. + * This could happen when an unsupported algorithm is requested, or when trying to import + * a key in a format other than raw or PKCS#8. + */ + public static final int ERROR_UNIMPLEMENTED = 12; + /** + * The feature the caller is trying to use is not compatible with the parameters used to + * generate the key. For example, trying to use a key generated for a different signature + * algorithm, or a digest not specified during key creation. + * Another case is the attempt to generate a symmetric AES key and requesting key attestation. + */ + public static final int ERROR_INCORRECT_USAGE = 13; + /** + * The key is not currently valid: Either at has expired or it will be valid for use in the + * future. + */ + public static final int ERROR_KEY_NOT_TEMPORALLY_VALID = 14; + /** + * The crypto object the caller has been using held a reference to a KeyMint operation that + * has been evacuated (likely due to other concurrent operations taking place). + * The caller should re-create the crypto object and try again. + */ + public static final int ERROR_KEY_OPERATION_EXPIRED = 15; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, prefix = {"ERROR_"}, value = { + ERROR_OTHER, + ERROR_USER_AUTHENTICATION_REQUIRED, + ERROR_KEYSTORE_UNINITIALIZED, + ERROR_INTERNAL_SYSTEM_ERROR, + ERROR_PERMISSION_DENIED, + ERROR_KEY_DOES_NOT_EXIST, + ERROR_KEY_CORRUPTED, + ERROR_ID_ATTESTATION_FAILURE, + ERROR_ATTESTATION_CHALLENGE_TOO_LARGE, + ERROR_KEYMINT_FAILURE, + ERROR_KEYSTORE_FAILURE, + ERROR_UNIMPLEMENTED, + ERROR_INCORRECT_USAGE, + ERROR_KEY_NOT_TEMPORALLY_VALID, + ERROR_KEY_OPERATION_EXPIRED + }) + public @interface PublicErrorCode { + } + // Constants for encoding information about the error encountered: + // Whether the error relates to the system state/implementation as a whole, or a specific key. + private static final int IS_SYSTEM_ERROR = 1 << 1; + // Whether the error is permanent. + private static final int IS_TRANSIENT_ERROR = 1 << 2; + // Whether the cause of the error is the user not having authenticated recently. + private static final int REQUIRES_USER_AUTHENTICATION = 1 << 3; + + // The internal error code. NOT to be returned directly to callers or made part of the + // public API. private final int mErrorCode; - public KeyStoreException(int errorCode, String message) { + /** + * @hide + */ + public KeyStoreException(int errorCode, @Nullable String message) { super(message); mErrorCode = errorCode; } + /** + * @hide + */ + public KeyStoreException(int errorCode, @Nullable String message, + @Nullable String keystoreErrorMessage) { + super(message + " (internal Keystore code: " + errorCode + " message: " + + keystoreErrorMessage + ")"); + mErrorCode = errorCode; + } + + /** + * Returns the internal error code. Only for use by the platform. + * + * @hide + */ + @TestApi public int getErrorCode() { return mErrorCode; } + + /** + * Returns one of the error codes exported by the class. + * + * @return a public error code, one of the values in {@link PublicErrorCode}. + */ + @PublicErrorCode + public int getNumericErrorCode() { + PublicErrorInformation failureInfo = getErrorInformation(mErrorCode); + return failureInfo.errorCode; + } + + /** + * Returns true if the failure is a transient failure - that is, performing the same operation + * again at a late time is likely to succeed. + * + * If {@link #isSystemError()} returns true, the transient nature of the failure relates to the + * device, otherwise relates to the key (so a permanent failure with an existing key likely + * requires creating another key to repeat the operation with). + */ + public boolean isTransientFailure() { + PublicErrorInformation failureInfo = getErrorInformation(mErrorCode); + return (failureInfo.indicators & IS_TRANSIENT_ERROR) != 0; + } + + /** + * Indicates whether the failure is due to the device being locked. + * + * @return true if the key operation failed because the user has to authenticate + * (e.g. by unlocking the device). + */ + public boolean requiresUserAuthentication() { + PublicErrorInformation failureInfo = getErrorInformation(mErrorCode); + return (failureInfo.indicators & REQUIRES_USER_AUTHENTICATION) != 0; + } + + /** + * Indicates whether the error related to the Keystore/KeyMint implementation and not + * a specific key. + * + * @return true if the error is related to the system, not the key in use. System + * errors indicate a feature isn't working, whereas key-related errors are likely + * to succeed with a new key. + */ + public boolean isSystemError() { + PublicErrorInformation failureInfo = getErrorInformation(mErrorCode); + return (failureInfo.indicators & IS_SYSTEM_ERROR) != 0; + } + + @Override + public String toString() { + String errorCodes = String.format(" (public error code: %d internal Keystore code: %d)", + getNumericErrorCode(), mErrorCode); + return super.toString() + errorCodes; + } + + private static PublicErrorInformation getErrorInformation(int internalErrorCode) { + PublicErrorInformation errorInfo = sErrorCodeToFailureInfo.get(internalErrorCode); + if (errorInfo != null) { + return errorInfo; + } + + /** + * KeyStore/keymaster exception with positive error codes coming from the KeyStore and + * negative ones from keymaster. + * This is a safety fall-back: All error codes should be present in the map. + */ + if (internalErrorCode > 0) { + return GENERAL_KEYSTORE_ERROR; + } else { + return GENERAL_KEYMINT_ERROR; + } + } + + private static final class PublicErrorInformation { + public final int indicators; + public final int errorCode; + + PublicErrorInformation(int indicators, @PublicErrorCode int errorCode) { + this.indicators = indicators; + this.errorCode = errorCode; + } + } + + private static final PublicErrorInformation GENERAL_KEYMINT_ERROR = + new PublicErrorInformation(0, ERROR_KEYMINT_FAILURE); + + private static final PublicErrorInformation GENERAL_KEYSTORE_ERROR = + new PublicErrorInformation(0, ERROR_KEYSTORE_FAILURE); + + private static final PublicErrorInformation KEYMINT_UNIMPLEMENTED_ERROR = + new PublicErrorInformation(IS_SYSTEM_ERROR, ERROR_UNIMPLEMENTED); + + private static final PublicErrorInformation KEYMINT_RETRYABLE_ERROR = + new PublicErrorInformation(IS_SYSTEM_ERROR | IS_TRANSIENT_ERROR, + ERROR_KEYMINT_FAILURE); + + private static final PublicErrorInformation KEYMINT_INCORRECT_USAGE_ERROR = + new PublicErrorInformation(0, ERROR_INCORRECT_USAGE); + + private static final PublicErrorInformation KEYMINT_TEMPORAL_VALIDITY_ERROR = + new PublicErrorInformation(0, ERROR_KEY_NOT_TEMPORALLY_VALID); + + + private static final Map<Integer, PublicErrorInformation> sErrorCodeToFailureInfo = + new HashMap(); + + /** + * @hide + */ + @TestApi + public static boolean hasFailureInfoForError(int internalErrorCode) { + return sErrorCodeToFailureInfo.containsKey(internalErrorCode); + } + + static { + // KeyMint error codes + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_OK, GENERAL_KEYMINT_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_ROOT_OF_TRUST_ALREADY_SET, + GENERAL_KEYMINT_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_PURPOSE, + KEYMINT_INCORRECT_USAGE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INCOMPATIBLE_PURPOSE, + KEYMINT_INCORRECT_USAGE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_ALGORITHM, + KEYMINT_UNIMPLEMENTED_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INCOMPATIBLE_ALGORITHM, + KEYMINT_INCORRECT_USAGE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_KEY_SIZE, + KEYMINT_UNIMPLEMENTED_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_BLOCK_MODE, + KEYMINT_UNIMPLEMENTED_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INCOMPATIBLE_BLOCK_MODE, + KEYMINT_INCORRECT_USAGE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_MAC_LENGTH, + KEYMINT_UNIMPLEMENTED_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_PADDING_MODE, + KEYMINT_INCORRECT_USAGE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INCOMPATIBLE_PADDING_MODE, + KEYMINT_INCORRECT_USAGE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_DIGEST, + KEYMINT_UNIMPLEMENTED_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INCOMPATIBLE_DIGEST, + KEYMINT_INCORRECT_USAGE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INVALID_EXPIRATION_TIME, + KEYMINT_INCORRECT_USAGE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INVALID_USER_ID, + GENERAL_KEYMINT_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT, + KEYMINT_INCORRECT_USAGE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_KEY_FORMAT, + KEYMINT_INCORRECT_USAGE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INCOMPATIBLE_KEY_FORMAT, + KEYMINT_INCORRECT_USAGE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM, + KEYMINT_UNIMPLEMENTED_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_KEY_VERIFICATION_ALGORITHM, + KEYMINT_UNIMPLEMENTED_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INVALID_INPUT_LENGTH, + KEYMINT_INCORRECT_USAGE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_KEY_EXPORT_OPTIONS_INVALID, + KEYMINT_INCORRECT_USAGE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_DELEGATION_NOT_ALLOWED, + GENERAL_KEYMINT_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID, + KEYMINT_TEMPORAL_VALIDITY_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_KEY_EXPIRED, + KEYMINT_TEMPORAL_VALIDITY_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED, + new PublicErrorInformation(REQUIRES_USER_AUTHENTICATION, + ERROR_USER_AUTHENTICATION_REQUIRED)); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_OUTPUT_PARAMETER_NULL, + GENERAL_KEYMINT_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INVALID_OPERATION_HANDLE, + new PublicErrorInformation(IS_SYSTEM_ERROR | IS_TRANSIENT_ERROR, + ERROR_KEY_OPERATION_EXPIRED)); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INSUFFICIENT_BUFFER_SPACE, + GENERAL_KEYMINT_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_VERIFICATION_FAILED, + GENERAL_KEYMINT_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_TOO_MANY_OPERATIONS, + GENERAL_KEYMINT_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNEXPECTED_NULL_POINTER, + GENERAL_KEYMINT_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INVALID_KEY_BLOB, + GENERAL_KEYMINT_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_IMPORTED_KEY_NOT_ENCRYPTED, + KEYMINT_INCORRECT_USAGE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_IMPORTED_KEY_DECRYPTION_FAILED, + KEYMINT_INCORRECT_USAGE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_IMPORTED_KEY_NOT_SIGNED, + KEYMINT_INCORRECT_USAGE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_IMPORTED_KEY_VERIFICATION_FAILED, + KEYMINT_INCORRECT_USAGE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INVALID_ARGUMENT, + GENERAL_KEYMINT_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_TAG, + KEYMINT_UNIMPLEMENTED_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INVALID_TAG, + KEYMINT_INCORRECT_USAGE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_MEMORY_ALLOCATION_FAILED, + GENERAL_KEYMINT_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_IMPORT_PARAMETER_MISMATCH, + GENERAL_KEYMINT_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_SECURE_HW_ACCESS_DENIED, + GENERAL_KEYMINT_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_OPERATION_CANCELLED, + GENERAL_KEYMINT_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_CONCURRENT_ACCESS_CONFLICT, + GENERAL_KEYMINT_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_SECURE_HW_BUSY, + KEYMINT_RETRYABLE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_SECURE_HW_COMMUNICATION_FAILED, + KEYMINT_RETRYABLE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_EC_FIELD, + KEYMINT_UNIMPLEMENTED_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_MISSING_NONCE, + KEYMINT_INCORRECT_USAGE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INVALID_NONCE, + KEYMINT_INCORRECT_USAGE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_MISSING_MAC_LENGTH, + KEYMINT_INCORRECT_USAGE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, + KEYMINT_RETRYABLE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_CALLER_NONCE_PROHIBITED, + GENERAL_KEYMINT_ERROR); + // Error related to MAX_USES_PER_BOOT, restricting the number of uses per boot. + // It is not re-tryable. + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_KEY_MAX_OPS_EXCEEDED, + GENERAL_KEYMINT_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INVALID_MAC_LENGTH, + KEYMINT_INCORRECT_USAGE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_MISSING_MIN_MAC_LENGTH, + KEYMINT_INCORRECT_USAGE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH, + KEYMINT_INCORRECT_USAGE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_KDF, + KEYMINT_UNIMPLEMENTED_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_EC_CURVE, + KEYMINT_UNIMPLEMENTED_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_ATTESTATION_CHALLENGE_MISSING, + KEYMINT_INCORRECT_USAGE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_KEYMINT_NOT_CONFIGURED, + new PublicErrorInformation(IS_SYSTEM_ERROR, ERROR_KEYMINT_FAILURE)); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_ATTESTATION_APPLICATION_ID_MISSING, + KEYMINT_RETRYABLE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_CANNOT_ATTEST_IDS, + new PublicErrorInformation(IS_SYSTEM_ERROR, + ERROR_ID_ATTESTATION_FAILURE)); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_ROLLBACK_RESISTANCE_UNAVAILABLE, + KEYMINT_UNIMPLEMENTED_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_HARDWARE_TYPE_UNAVAILABLE, + KEYMINT_UNIMPLEMENTED_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_DEVICE_LOCKED, + new PublicErrorInformation(IS_SYSTEM_ERROR | REQUIRES_USER_AUTHENTICATION, + ERROR_USER_AUTHENTICATION_REQUIRED)); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_STORAGE_KEY_UNSUPPORTED, + KEYMINT_UNIMPLEMENTED_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INCOMPATIBLE_MGF_DIGEST, + KEYMINT_INCORRECT_USAGE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_MGF_DIGEST, + KEYMINT_UNIMPLEMENTED_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_MISSING_NOT_BEFORE, + KEYMINT_INCORRECT_USAGE_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_MISSING_NOT_AFTER, + KEYMINT_INCORRECT_USAGE_ERROR); + // This should not be exposed to apps as it's handled by Keystore. + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_HARDWARE_NOT_YET_AVAILABLE, + GENERAL_KEYMINT_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNIMPLEMENTED, + KEYMINT_UNIMPLEMENTED_ERROR); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNKNOWN_ERROR, + new PublicErrorInformation(IS_SYSTEM_ERROR, + ERROR_KEYMINT_FAILURE)); + sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_VERSION_MISMATCH, GENERAL_KEYMINT_ERROR); + + // Keystore error codes + sErrorCodeToFailureInfo.put(ResponseCode.LOCKED, + new PublicErrorInformation(REQUIRES_USER_AUTHENTICATION, + ERROR_USER_AUTHENTICATION_REQUIRED)); + sErrorCodeToFailureInfo.put(ResponseCode.UNINITIALIZED, + new PublicErrorInformation(IS_SYSTEM_ERROR, ERROR_KEYSTORE_UNINITIALIZED)); + sErrorCodeToFailureInfo.put(ResponseCode.SYSTEM_ERROR, + new PublicErrorInformation(IS_SYSTEM_ERROR, + ERROR_INTERNAL_SYSTEM_ERROR)); + sErrorCodeToFailureInfo.put(ResponseCode.PERMISSION_DENIED, + new PublicErrorInformation(0, ERROR_PERMISSION_DENIED)); + sErrorCodeToFailureInfo.put(ResponseCode.KEY_NOT_FOUND, + new PublicErrorInformation(0, ERROR_KEY_DOES_NOT_EXIST)); + sErrorCodeToFailureInfo.put(ResponseCode.VALUE_CORRUPTED, + new PublicErrorInformation(0, ERROR_KEY_CORRUPTED)); + sErrorCodeToFailureInfo.put(ResponseCode.KEY_PERMANENTLY_INVALIDATED, + new PublicErrorInformation(0, ERROR_KEY_DOES_NOT_EXIST)); + } } diff --git a/keystore/java/android/security/KeyStoreOperation.java b/keystore/java/android/security/KeyStoreOperation.java index e6c1ea827118..737ff2b4822f 100644 --- a/keystore/java/android/security/KeyStoreOperation.java +++ b/keystore/java/android/security/KeyStoreOperation.java @@ -75,7 +75,7 @@ public class KeyStoreOperation { ); } default: - throw KeyStore2.getKeyStoreException(e.errorCode); + throw KeyStore2.getKeyStoreException(e.errorCode, e.getMessage()); } } catch (RemoteException e) { // Log exception and report invalid operation handle. @@ -85,7 +85,8 @@ public class KeyStoreOperation { "Remote exception while advancing a KeyStoreOperation.", e ); - throw new KeyStoreException(KeymasterDefs.KM_ERROR_INVALID_OPERATION_HANDLE, ""); + throw new KeyStoreException(KeymasterDefs.KM_ERROR_INVALID_OPERATION_HANDLE, "", + e.getMessage()); } } diff --git a/keystore/java/android/security/KeyStoreSecurityLevel.java b/keystore/java/android/security/KeyStoreSecurityLevel.java index b85dd742cc49..9c0b46c8e87b 100644 --- a/keystore/java/android/security/KeyStoreSecurityLevel.java +++ b/keystore/java/android/security/KeyStoreSecurityLevel.java @@ -54,12 +54,12 @@ public class KeyStoreSecurityLevel { try { return request.execute(); } catch (ServiceSpecificException e) { - throw KeyStore2.getKeyStoreException(e.errorCode); + throw KeyStore2.getKeyStoreException(e.errorCode, e.getMessage()); } catch (RemoteException e) { // Log exception and report invalid operation handle. // This should prompt the caller drop the reference to this operation and retry. Log.e(TAG, "Could not connect to Keystore.", e); - throw new KeyStoreException(ResponseCode.SYSTEM_ERROR, ""); + throw new KeyStoreException(ResponseCode.SYSTEM_ERROR, "", e.getMessage()); } } @@ -117,7 +117,7 @@ public class KeyStoreSecurityLevel { break; } default: - throw KeyStore2.getKeyStoreException(e.errorCode); + throw KeyStore2.getKeyStoreException(e.errorCode, e.getMessage()); } } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java index 2e85b304ec47..31dd10a8ed53 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java @@ -66,6 +66,7 @@ import java.security.SecureRandom; import java.security.UnrecoverableKeyException; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.ECGenParameterSpec; +import java.security.spec.NamedParameterSpec; import java.security.spec.RSAKeyGenParameterSpec; import java.util.ArrayList; import java.util.Arrays; @@ -119,36 +120,42 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato private static final int RSA_MIN_KEY_SIZE = 512; private static final int RSA_MAX_KEY_SIZE = 8192; - private static final Map<String, Integer> SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE = + private static final Map<String, Integer> SUPPORTED_EC_CURVE_NAME_TO_SIZE = new HashMap<String, Integer>(); - private static final List<String> SUPPORTED_EC_NIST_CURVE_NAMES = new ArrayList<String>(); - private static final List<Integer> SUPPORTED_EC_NIST_CURVE_SIZES = new ArrayList<Integer>(); + private static final List<String> SUPPORTED_EC_CURVE_NAMES = new ArrayList<String>(); + private static final List<Integer> SUPPORTED_EC_CURVE_SIZES = new ArrayList<Integer>(); + private static final String CURVE_X_25519 = NamedParameterSpec.X25519.getName(); + private static final String CURVE_ED_25519 = NamedParameterSpec.ED25519.getName(); + static { // Aliases for NIST P-224 - SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-224", 224); - SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp224r1", 224); + SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("p-224", 224); + SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("secp224r1", 224); // Aliases for NIST P-256 - SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-256", 256); - SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp256r1", 256); - SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("prime256v1", 256); + SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("p-256", 256); + SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("secp256r1", 256); + SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("prime256v1", 256); + // Aliases for Curve 25519 + SUPPORTED_EC_CURVE_NAME_TO_SIZE.put(CURVE_X_25519.toLowerCase(Locale.US), 256); + SUPPORTED_EC_CURVE_NAME_TO_SIZE.put(CURVE_ED_25519.toLowerCase(Locale.US), 256); // Aliases for NIST P-384 - SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-384", 384); - SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp384r1", 384); + SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("p-384", 384); + SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("secp384r1", 384); // Aliases for NIST P-521 - SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-521", 521); - SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp521r1", 521); + SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("p-521", 521); + SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("secp521r1", 521); - SUPPORTED_EC_NIST_CURVE_NAMES.addAll(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.keySet()); - Collections.sort(SUPPORTED_EC_NIST_CURVE_NAMES); + SUPPORTED_EC_CURVE_NAMES.addAll(SUPPORTED_EC_CURVE_NAME_TO_SIZE.keySet()); + Collections.sort(SUPPORTED_EC_CURVE_NAMES); - SUPPORTED_EC_NIST_CURVE_SIZES.addAll( - new HashSet<Integer>(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.values())); - Collections.sort(SUPPORTED_EC_NIST_CURVE_SIZES); + SUPPORTED_EC_CURVE_SIZES.addAll( + new HashSet<Integer>(SUPPORTED_EC_CURVE_NAME_TO_SIZE.values())); + Collections.sort(SUPPORTED_EC_CURVE_SIZES); } private final int mOriginalKeymasterAlgorithm; @@ -164,6 +171,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato private int mKeySizeBits; private SecureRandom mRng; private KeyDescriptor mAttestKeyDescriptor; + private String mEcCurveName; private int[] mKeymasterPurposes; private int[] mKeymasterBlockModes; @@ -177,12 +185,15 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato mOriginalKeymasterAlgorithm = keymasterAlgorithm; } - private @EcCurve int keySize2EcCurve(int keySizeBits) + private static @EcCurve int keySizeAndNameToEcCurve(int keySizeBits, String ecCurveName) throws InvalidAlgorithmParameterException { switch (keySizeBits) { case 224: return EcCurve.P_224; case 256: + if (isCurve25519(ecCurveName)) { + return EcCurve.CURVE_25519; + } return EcCurve.P_256; case 384: return EcCurve.P_384; @@ -247,7 +258,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato if (mKeySizeBits == -1) { mKeySizeBits = getDefaultKeySize(keymasterAlgorithm); } - checkValidKeySize(keymasterAlgorithm, mKeySizeBits, mSpec.isStrongBoxBacked()); + checkValidKeySize(keymasterAlgorithm, mKeySizeBits, mSpec.isStrongBoxBacked(), + mEcCurveName); if (spec.getKeystoreAlias() == null) { throw new InvalidAlgorithmParameterException("KeyStore entry alias not provided"); @@ -299,6 +311,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato mAttestKeyDescriptor = buildAndCheckAttestKeyDescriptor(spec); checkAttestKeyPurpose(spec); + checkCorrectKeyPurposeForCurve(spec); success = true; } finally { @@ -317,6 +330,42 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato } } + private void checkCorrectKeyPurposeForCurve(KeyGenParameterSpec spec) + throws InvalidAlgorithmParameterException { + // Validate the key usage purposes against the curve. x25519 should be + // key exchange only, ed25519 signing and attesting. + + if (!isCurve25519(mEcCurveName)) { + return; + } + + if (mEcCurveName.equalsIgnoreCase(CURVE_X_25519) + && spec.getPurposes() != KeyProperties.PURPOSE_AGREE_KEY) { + throw new InvalidAlgorithmParameterException( + "x25519 may only be used for key agreement."); + } else if (mEcCurveName.equalsIgnoreCase(CURVE_ED_25519) + && !hasOnlyAllowedPurposeForEd25519(spec.getPurposes())) { + throw new InvalidAlgorithmParameterException( + "ed25519 may not be used for key agreement."); + } + } + + private static boolean isCurve25519(String ecCurveName) { + if (ecCurveName == null) { + return false; + } + return ecCurveName.equalsIgnoreCase(CURVE_X_25519) + || ecCurveName.equalsIgnoreCase(CURVE_ED_25519); + } + + private static boolean hasOnlyAllowedPurposeForEd25519(@KeyProperties.PurposeEnum int purpose) { + final int allowedPurposes = KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY + | KeyProperties.PURPOSE_ATTEST_KEY; + boolean hasAllowedPurpose = (purpose & allowedPurposes) != 0; + boolean hasDisallowedPurpose = (purpose & ~allowedPurposes) != 0; + return hasAllowedPurpose && !hasDisallowedPurpose; + } + private KeyDescriptor buildAndCheckAttestKeyDescriptor(KeyGenParameterSpec spec) throws InvalidAlgorithmParameterException { if (spec.getAttestKeyAlias() != null) { @@ -473,6 +522,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato mRSAPublicExponent = null; mRng = null; mKeyStore = null; + mEcCurveName = null; } private void initAlgorithmSpecificParameters() throws InvalidAlgorithmParameterException { @@ -514,13 +564,13 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato case KeymasterDefs.KM_ALGORITHM_EC: if (algSpecificSpec instanceof ECGenParameterSpec) { ECGenParameterSpec ecSpec = (ECGenParameterSpec) algSpecificSpec; - String curveName = ecSpec.getName(); - Integer ecSpecKeySizeBits = SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.get( - curveName.toLowerCase(Locale.US)); + mEcCurveName = ecSpec.getName(); + final Integer ecSpecKeySizeBits = SUPPORTED_EC_CURVE_NAME_TO_SIZE.get( + mEcCurveName.toLowerCase(Locale.US)); if (ecSpecKeySizeBits == null) { throw new InvalidAlgorithmParameterException( - "Unsupported EC curve name: " + curveName - + ". Supported: " + SUPPORTED_EC_NIST_CURVE_NAMES); + "Unsupported EC curve name: " + mEcCurveName + + ". Supported: " + SUPPORTED_EC_CURVE_NAMES); } if (mKeySizeBits == -1) { mKeySizeBits = ecSpecKeySizeBits; @@ -744,7 +794,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_EC) { params.add(KeyStore2ParameterUtils.makeEnum( - Tag.EC_CURVE, keySize2EcCurve(mKeySizeBits) + Tag.EC_CURVE, keySizeAndNameToEcCurve(mKeySizeBits, mEcCurveName) )); } @@ -864,7 +914,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato private static void checkValidKeySize( int keymasterAlgorithm, int keySize, - boolean isStrongBoxBacked) + boolean isStrongBoxBacked, + String mEcCurveName) throws InvalidAlgorithmParameterException { switch (keymasterAlgorithm) { case KeymasterDefs.KM_ALGORITHM_EC: @@ -873,9 +924,13 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato "Unsupported StrongBox EC key size: " + keySize + " bits. Supported: 256"); } - if (!SUPPORTED_EC_NIST_CURVE_SIZES.contains(keySize)) { + if (isStrongBoxBacked && isCurve25519(mEcCurveName)) { + throw new InvalidAlgorithmParameterException( + "Unsupported StrongBox EC: " + mEcCurveName); + } + if (!SUPPORTED_EC_CURVE_SIZES.contains(keySize)) { throw new InvalidAlgorithmParameterException("Unsupported EC key size: " - + keySize + " bits. Supported: " + SUPPORTED_EC_NIST_CURVE_SIZES); + + keySize + " bits. Supported: " + SUPPORTED_EC_CURVE_SIZES); } break; case KeymasterDefs.KM_ALGORITHM_RSA: diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java index 72a145fa6a05..358104fffbf6 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java @@ -66,6 +66,11 @@ public class AndroidKeyStoreProvider extends Provider { private static final String DESEDE_SYSTEM_PROPERTY = "ro.hardware.keystore_desede"; + // Conscrypt returns the Ed25519 OID as the JCA key algorithm. + private static final String ED25519_OID = "1.3.101.112"; + // Conscrypt returns "XDH" as the X25519 JCA key algorithm. + private static final String X25519_ALIAS = "XDH"; + /** @hide **/ public AndroidKeyStoreProvider() { super(PROVIDER_NAME, 1.0, "Android KeyStore security provider"); @@ -78,10 +83,16 @@ public class AndroidKeyStoreProvider extends Provider { // java.security.KeyPairGenerator put("KeyPairGenerator.EC", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$EC"); put("KeyPairGenerator.RSA", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$RSA"); + put("KeyPairGenerator." + X25519_ALIAS, + PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$RSA"); + put("KeyPairGenerator." + ED25519_OID, + PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$RSA"); // java.security.KeyFactory putKeyFactoryImpl("EC"); putKeyFactoryImpl("RSA"); + putKeyFactoryImpl(X25519_ALIAS); + putKeyFactoryImpl(ED25519_OID); // javax.crypto.KeyGenerator put("KeyGenerator.AES", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$AES"); @@ -219,12 +230,17 @@ public class AndroidKeyStoreProvider extends Provider { KeyStoreSecurityLevel securityLevel = iSecurityLevel; if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(jcaKeyAlgorithm)) { - return new AndroidKeyStoreECPublicKey(descriptor, metadata, iSecurityLevel, (ECPublicKey) publicKey); } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(jcaKeyAlgorithm)) { return new AndroidKeyStoreRSAPublicKey(descriptor, metadata, iSecurityLevel, (RSAPublicKey) publicKey); + } else if (ED25519_OID.equalsIgnoreCase(jcaKeyAlgorithm)) { + //TODO(b/214203951) missing classes in conscrypt + throw new ProviderException("Curve " + ED25519_OID + " not supported yet"); + } else if (X25519_ALIAS.equalsIgnoreCase(jcaKeyAlgorithm)) { + //TODO(b/214203951) missing classes in conscrypt + throw new ProviderException("Curve " + X25519_ALIAS + " not supported yet"); } else { throw new ProviderException("Unsupported Android Keystore public key algorithm: " + jcaKeyAlgorithm); diff --git a/keystore/tests/src/android/security/keystore/KeyStoreExceptionTest.java b/keystore/tests/src/android/security/keystore/KeyStoreExceptionTest.java new file mode 100644 index 000000000000..31c742289a61 --- /dev/null +++ b/keystore/tests/src/android/security/keystore/KeyStoreExceptionTest.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2022 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 android.security.keystore; + +import static org.junit.Assert.assertTrue; + +import android.security.KeyStoreException; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class KeyStoreExceptionTest { + @Test + public void testKeystoreMessageIsIncluded() { + final String primaryMessage = "some_message"; + final String keystoreMessage = "ks_message"; + KeyStoreException exception = new KeyStoreException(-1, primaryMessage, keystoreMessage); + + String exceptionMessage = exception.getMessage(); + assertTrue(exceptionMessage.contains(primaryMessage)); + assertTrue(exceptionMessage.contains(keystoreMessage)); + + String exceptionString = exception.toString(); + assertTrue(exceptionString.contains(primaryMessage)); + assertTrue(exceptionString.contains(keystoreMessage)); + } +} diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp index d17c32817994..8150e78fdddc 100644 --- a/libs/androidfw/LoadedArsc.cpp +++ b/libs/androidfw/LoadedArsc.cpp @@ -686,6 +686,12 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk, std::unordered_set<uint32_t> finalized_ids; const auto lib_alias = child_chunk.header<ResTable_staged_alias_header>(); if (!lib_alias) { + LOG(ERROR) << "RES_TABLE_STAGED_ALIAS_TYPE is too small."; + return {}; + } + if ((child_chunk.data_size() / sizeof(ResTable_staged_alias_entry)) + < dtohl(lib_alias->count)) { + LOG(ERROR) << "RES_TABLE_STAGED_ALIAS_TYPE is too small to hold entries."; return {}; } const auto entry_begin = child_chunk.data_ptr().convert<ResTable_staged_alias_entry>(); diff --git a/libs/androidfw/tests/BackupHelpers_test.cpp b/libs/androidfw/tests/BackupHelpers_test.cpp index 86b7fb361228..c2fcb6990f90 100644 --- a/libs/androidfw/tests/BackupHelpers_test.cpp +++ b/libs/androidfw/tests/BackupHelpers_test.cpp @@ -50,7 +50,7 @@ TEST_F(BackupHelpersTest, WriteTarFileWithSizeLessThan2GB) { TEST_F(BackupHelpersTest, WriteTarFileWithSizeGreaterThan2GB) { TemporaryFile tf; // Allocate a 2 GB file. - off64_t fileSize = 2ll * 1024ll * 1024ll * 1024ll + 512ll; + off64_t fileSize = 2LL * 1024LL * 1024LL * 1024LL + 512LL; ASSERT_EQ(0, posix_fallocate64(tf.fd, 0, fileSize)); off64_t tarSize = 0; int err = write_tarfile(/* packageName */ String8("test-pkg"), /* domain */ String8(""), /* rootpath */ String8(""), /* filePath */ String8(tf.path), /* outSize */ &tarSize, /* writer */ NULL); diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 2fed4686f16e..00561be3c1c4 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -287,7 +287,7 @@ private: }; // Need at least 4 because we do quad buffer. Add a 5th for good measure. - RingBuffer<SwapHistory, 5> mSwapHistory; + RingBuffer<SwapHistory, 7> mSwapHistory; int64_t mFrameNumber = -1; int64_t mDamageId = 0; diff --git a/media/Android.bp b/media/Android.bp index 1b7bef53dba4..b7c3a9c112d1 100644 --- a/media/Android.bp +++ b/media/Android.bp @@ -100,6 +100,11 @@ aidl_interface { vndk: { enabled: true, }, + min_sdk_version: "29", + apex_available: [ + "//apex_available:platform", + "com.android.bluetooth", + ], }, }, } diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java index a186566aec0b..3edb10108497 100644 --- a/media/java/android/media/AudioDeviceInfo.java +++ b/media/java/android/media/AudioDeviceInfo.java @@ -177,6 +177,11 @@ public final class AudioDeviceInfo { */ public static final int TYPE_HDMI_EARC = 29; + /** + * A device type describing a Bluetooth Low Energy (BLE) broadcast group. + */ + public static final int TYPE_BLE_BROADCAST = 30; + /** @hide */ @IntDef(flag = false, prefix = "TYPE", value = { TYPE_BUILTIN_EARPIECE, @@ -207,7 +212,8 @@ public final class AudioDeviceInfo { TYPE_REMOTE_SUBMIX, TYPE_BLE_HEADSET, TYPE_BLE_SPEAKER, - TYPE_ECHO_REFERENCE} + TYPE_ECHO_REFERENCE, + TYPE_BLE_BROADCAST} ) @Retention(RetentionPolicy.SOURCE) public @interface AudioDeviceType {} @@ -264,7 +270,8 @@ public final class AudioDeviceInfo { TYPE_HEARING_AID, TYPE_BUILTIN_SPEAKER_SAFE, TYPE_BLE_HEADSET, - TYPE_BLE_SPEAKER} + TYPE_BLE_SPEAKER, + TYPE_BLE_BROADCAST} ) @Retention(RetentionPolicy.SOURCE) public @interface AudioDeviceTypeOut {} @@ -296,6 +303,7 @@ public final class AudioDeviceInfo { case TYPE_BUILTIN_SPEAKER_SAFE: case TYPE_BLE_HEADSET: case TYPE_BLE_SPEAKER: + case TYPE_BLE_BROADCAST: return true; default: return false; @@ -627,6 +635,7 @@ public final class AudioDeviceInfo { INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX, TYPE_REMOTE_SUBMIX); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLE_HEADSET, TYPE_BLE_HEADSET); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLE_SPEAKER, TYPE_BLE_SPEAKER); + INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLE_BROADCAST, TYPE_BLE_BROADCAST); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BUILTIN_MIC, TYPE_BUILTIN_MIC); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET, TYPE_BLUETOOTH_SCO); @@ -684,6 +693,7 @@ public final class AudioDeviceInfo { EXT_TO_INT_DEVICE_MAPPING.put(TYPE_REMOTE_SUBMIX, AudioSystem.DEVICE_OUT_REMOTE_SUBMIX); EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BLE_HEADSET, AudioSystem.DEVICE_OUT_BLE_HEADSET); EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BLE_SPEAKER, AudioSystem.DEVICE_OUT_BLE_SPEAKER); + EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BLE_BROADCAST, AudioSystem.DEVICE_OUT_BLE_BROADCAST); // privileges mapping to input device EXT_TO_INT_INPUT_DEVICE_MAPPING = new SparseIntArray(); diff --git a/media/java/android/media/AudioDevicePort.java b/media/java/android/media/AudioDevicePort.java index ebe08822a0c9..9211c53a17bc 100644 --- a/media/java/android/media/AudioDevicePort.java +++ b/media/java/android/media/AudioDevicePort.java @@ -90,7 +90,8 @@ public class AudioDevicePort extends AudioPort { * {@link AudioManager#DEVICE_OUT_BLE_HEADSET}, {@link AudioManager#DEVICE_OUT_BLE_SPEAKER}) * use the MAC address of the bluetooth device in the form "00:11:22:AA:BB:CC" as reported by * {@link BluetoothDevice#getAddress()}. - * - Deivces that do not have an address will indicate an empty string "". + * - Bluetooth LE broadcast group ({@link AudioManager#DEVICE_OUT_BLE_BROADCAST} use the group number. + * - Devices that do not have an address will indicate an empty string "". */ public String address() { return mAddress; diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index b7e8c8cb0a7e..ce2bccfb1059 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -5404,6 +5404,10 @@ public class AudioManager { */ public static final int DEVICE_OUT_BLE_SPEAKER = AudioSystem.DEVICE_OUT_BLE_SPEAKER; /** @hide + * The audio output device code for a BLE audio brodcast group. + */ + public static final int DEVICE_OUT_BLE_BROADCAST = AudioSystem.DEVICE_OUT_BLE_BROADCAST; + /** @hide * This is not used as a returned value from {@link #getDevicesForStream}, but could be * used in the future in a set method to select whatever default device is chosen by the * platform-specific implementation. @@ -5806,13 +5810,14 @@ public class AudioManager { * @param newDevice Bluetooth device connected or null if there is no new devices * @param previousDevice Bluetooth device disconnected or null if there is no disconnected * devices - * @param info contain all info related to the device. {@link BtProfileConnectionInfo} + * @param info contain all info related to the device. {@link BluetoothProfileConnectionInfo} * {@hide} */ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) public void handleBluetoothActiveDeviceChanged(@Nullable BluetoothDevice newDevice, - @Nullable BluetoothDevice previousDevice, @NonNull BtProfileConnectionInfo info) { + @Nullable BluetoothDevice previousDevice, + @NonNull BluetoothProfileConnectionInfo info) { final IAudioService service = getService(); try { service.handleBluetoothActiveDeviceChanged(newDevice, previousDevice, info); diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 143b11f76f23..33b877c6a958 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -982,6 +982,8 @@ public class AudioSystem public static final int DEVICE_OUT_BLE_HEADSET = 0x20000000; /** @hide */ public static final int DEVICE_OUT_BLE_SPEAKER = 0x20000001; + /** @hide */ + public static final int DEVICE_OUT_BLE_BROADCAST = 0x20000002; /** @hide */ public static final int DEVICE_OUT_DEFAULT = DEVICE_BIT_DEFAULT; @@ -1042,6 +1044,7 @@ public class AudioSystem DEVICE_OUT_ALL_SET.add(DEVICE_OUT_ECHO_CANCELLER); DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLE_HEADSET); DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLE_SPEAKER); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLE_BROADCAST); DEVICE_OUT_ALL_SET.add(DEVICE_OUT_DEFAULT); DEVICE_OUT_ALL_A2DP_SET = new HashSet<>(); @@ -1072,6 +1075,7 @@ public class AudioSystem DEVICE_OUT_ALL_BLE_SET = new HashSet<>(); DEVICE_OUT_ALL_BLE_SET.add(DEVICE_OUT_BLE_HEADSET); DEVICE_OUT_ALL_BLE_SET.add(DEVICE_OUT_BLE_SPEAKER); + DEVICE_OUT_ALL_BLE_SET.add(DEVICE_OUT_BLE_BROADCAST); } // input devices @@ -1255,6 +1259,7 @@ public class AudioSystem /** @hide */ public static final String DEVICE_OUT_ECHO_CANCELLER_NAME = "echo_canceller"; /** @hide */ public static final String DEVICE_OUT_BLE_HEADSET_NAME = "ble_headset"; /** @hide */ public static final String DEVICE_OUT_BLE_SPEAKER_NAME = "ble_speaker"; + /** @hide */ public static final String DEVICE_OUT_BLE_BROADCAST_NAME = "ble_broadcast"; /** @hide */ public static final String DEVICE_IN_COMMUNICATION_NAME = "communication"; /** @hide */ public static final String DEVICE_IN_AMBIENT_NAME = "ambient"; @@ -1354,6 +1359,8 @@ public class AudioSystem return DEVICE_OUT_BLE_HEADSET_NAME; case DEVICE_OUT_BLE_SPEAKER: return DEVICE_OUT_BLE_SPEAKER_NAME; + case DEVICE_OUT_BLE_BROADCAST: + return DEVICE_OUT_BLE_BROADCAST_NAME; case DEVICE_OUT_DEFAULT: default: return Integer.toString(device); diff --git a/media/java/android/media/BtProfileConnectionInfo.aidl b/media/java/android/media/BluetoothProfileConnectionInfo.aidl index 047f06be0964..0617084fd826 100644 --- a/media/java/android/media/BtProfileConnectionInfo.aidl +++ b/media/java/android/media/BluetoothProfileConnectionInfo.aidl @@ -16,5 +16,5 @@ package android.media; -parcelable BtProfileConnectionInfo; +parcelable BluetoothProfileConnectionInfo; diff --git a/media/java/android/media/BtProfileConnectionInfo.java b/media/java/android/media/BluetoothProfileConnectionInfo.java index 88b9777e911d..c14884657ddd 100644 --- a/media/java/android/media/BtProfileConnectionInfo.java +++ b/media/java/android/media/BluetoothProfileConnectionInfo.java @@ -26,15 +26,14 @@ import android.os.Parcelable; * {@hide} */ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) -public final class BtProfileConnectionInfo implements Parcelable { - +public final class BluetoothProfileConnectionInfo implements Parcelable { private final int mProfile; private final boolean mSupprNoisy; private final int mVolume; private final boolean mIsLeOutput; - private BtProfileConnectionInfo(int profile, boolean suppressNoisyIntent, int volume, - boolean isLeOutput) { + private BluetoothProfileConnectionInfo(int profile, boolean suppressNoisyIntent, + int volume, boolean isLeOutput) { mProfile = profile; mSupprNoisy = suppressNoisyIntent; mVolume = volume; @@ -45,21 +44,21 @@ public final class BtProfileConnectionInfo implements Parcelable { * Constructor used by BtHelper when a profile is connected * {@hide} */ - public BtProfileConnectionInfo(int profile) { + public BluetoothProfileConnectionInfo(int profile) { this(profile, false, -1, false); } - public static final @NonNull Parcelable.Creator<BtProfileConnectionInfo> CREATOR = - new Parcelable.Creator<BtProfileConnectionInfo>() { + public static final @NonNull Parcelable.Creator<BluetoothProfileConnectionInfo> CREATOR = + new Parcelable.Creator<BluetoothProfileConnectionInfo>() { @Override - public BtProfileConnectionInfo createFromParcel(Parcel source) { - return new BtProfileConnectionInfo(source.readInt(), source.readBoolean(), - source.readInt(), source.readBoolean()); + public BluetoothProfileConnectionInfo createFromParcel(Parcel source) { + return new BluetoothProfileConnectionInfo(source.readInt(), + source.readBoolean(), source.readInt(), source.readBoolean()); } @Override - public BtProfileConnectionInfo[] newArray(int size) { - return new BtProfileConnectionInfo[size]; + public BluetoothProfileConnectionInfo[] newArray(int size) { + return new BluetoothProfileConnectionInfo[size]; } }; @@ -84,10 +83,10 @@ public final class BtProfileConnectionInfo implements Parcelable { * * @param volume of device -1 to ignore value */ - public static @NonNull BtProfileConnectionInfo a2dpInfo(boolean suppressNoisyIntent, - int volume) { - return new BtProfileConnectionInfo(BluetoothProfile.A2DP, suppressNoisyIntent, volume, - false); + public static @NonNull BluetoothProfileConnectionInfo createA2dpInfo( + boolean suppressNoisyIntent, int volume) { + return new BluetoothProfileConnectionInfo(BluetoothProfile.A2DP, suppressNoisyIntent, + volume, false); } /** @@ -96,8 +95,8 @@ public final class BtProfileConnectionInfo implements Parcelable { * * @param volume of device -1 to ignore value */ - public static @NonNull BtProfileConnectionInfo a2dpSinkInfo(int volume) { - return new BtProfileConnectionInfo(BluetoothProfile.A2DP_SINK, true, volume, false); + public static @NonNull BluetoothProfileConnectionInfo createA2dpSinkInfo(int volume) { + return new BluetoothProfileConnectionInfo(BluetoothProfile.A2DP_SINK, true, volume, false); } /** @@ -106,9 +105,10 @@ public final class BtProfileConnectionInfo implements Parcelable { * @param suppressNoisyIntent if true the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} * intent will not be sent. */ - public static @NonNull BtProfileConnectionInfo hearingAidInfo(boolean suppressNoisyIntent) { - return new BtProfileConnectionInfo(BluetoothProfile.HEARING_AID, suppressNoisyIntent, -1, - false); + public static @NonNull BluetoothProfileConnectionInfo createHearingAidInfo( + boolean suppressNoisyIntent) { + return new BluetoothProfileConnectionInfo(BluetoothProfile.HEARING_AID, suppressNoisyIntent, + -1, false); } /** @@ -119,10 +119,10 @@ public final class BtProfileConnectionInfo implements Parcelable { * * @param isLeOutput if true mean the device is an output device, if false it's an input device */ - public static @NonNull BtProfileConnectionInfo leAudio(boolean suppressNoisyIntent, - boolean isLeOutput) { - return new BtProfileConnectionInfo(BluetoothProfile.LE_AUDIO, suppressNoisyIntent, -1, - isLeOutput); + public static @NonNull BluetoothProfileConnectionInfo createLeAudioInfo( + boolean suppressNoisyIntent, boolean isLeOutput) { + return new BluetoothProfileConnectionInfo(BluetoothProfile.LE_AUDIO, suppressNoisyIntent, + -1, isLeOutput); } /** @@ -136,7 +136,7 @@ public final class BtProfileConnectionInfo implements Parcelable { * @return {@code true} if {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be * sent */ - public boolean getSuppressNoisyIntent() { + public boolean isSuppressNoisyIntent() { return mSupprNoisy; } @@ -153,7 +153,7 @@ public final class BtProfileConnectionInfo implements Parcelable { * @return {@code true} is the LE device is an output device, {@code false} if it's an input * device */ - public boolean getIsLeOutput() { + public boolean isLeOutput() { return mIsLeOutput; } } diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 5ff56f9c680d..d5a2d07d4bb7 100755 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -24,7 +24,7 @@ import android.media.AudioFocusInfo; import android.media.AudioPlaybackConfiguration; import android.media.AudioRecordingConfiguration; import android.media.AudioRoutesInfo; -import android.media.BtProfileConnectionInfo; +import android.media.BluetoothProfileConnectionInfo; import android.media.IAudioFocusDispatcher; import android.media.IAudioModeDispatcher; import android.media.IAudioRoutesObserver; @@ -268,7 +268,7 @@ interface IAudioService { oneway void playerHasOpPlayAudio(in int piid, in boolean hasOpPlayAudio); void handleBluetoothActiveDeviceChanged(in BluetoothDevice newDevice, - in BluetoothDevice previousDevice, in BtProfileConnectionInfo info); + in BluetoothDevice previousDevice, in BluetoothProfileConnectionInfo info); oneway void setFocusRequestResultFromExtPolicy(in AudioFocusInfo afi, int requestResult, in IAudioPolicyCallback pcb); diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java index 1da41fb87b40..33bc84636624 100644 --- a/media/java/android/media/session/MediaController.java +++ b/media/java/android/media/session/MediaController.java @@ -407,7 +407,7 @@ public final class MediaController { /** * Get the session owner's package name. * - * @return The package name of of the session owner. + * @return The package name of the session owner. */ public String getPackageName() { if (mPackageName == null) { diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java index d8f48c2cf0c6..20d711cf4c54 100755 --- a/media/java/android/mtp/MtpDatabase.java +++ b/media/java/android/mtp/MtpDatabase.java @@ -103,6 +103,7 @@ public class MtpDatabase implements AutoCloseable { private int mDeviceType; private String mHostType; private boolean mSkipThumbForHost = false; + private volatile boolean mHostIsWindows = false; private MtpServer mServer; private MtpStorageManager mManager; @@ -358,7 +359,7 @@ public class MtpDatabase implements AutoCloseable { } public void addStorage(StorageVolume storage) { - MtpStorage mtpStorage = mManager.addMtpStorage(storage); + MtpStorage mtpStorage = mManager.addMtpStorage(storage, () -> mHostIsWindows); mStorageMap.put(storage.getPath(), mtpStorage); if (mServer != null) { mServer.addStorage(mtpStorage); @@ -413,6 +414,7 @@ public class MtpDatabase implements AutoCloseable { } mHostType = ""; mSkipThumbForHost = false; + mHostIsWindows = false; } @VisibleForNative @@ -736,10 +738,12 @@ public class MtpDatabase implements AutoCloseable { : MtpConstants.RESPONSE_GENERAL_ERROR); case MtpConstants.DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO: mHostType = stringValue; + Log.d(TAG, "setDeviceProperty." + Integer.toHexString(property) + + "=" + stringValue); if (stringValue.startsWith("Android/")) { - Log.d(TAG, "setDeviceProperty." + Integer.toHexString(property) - + "=" + stringValue); mSkipThumbForHost = true; + } else if (stringValue.startsWith("Windows/")) { + mHostIsWindows = true; } return MtpConstants.RESPONSE_OK; } diff --git a/media/java/android/mtp/MtpStorage.java b/media/java/android/mtp/MtpStorage.java index 88c32a3ea72b..a3754e90a875 100644 --- a/media/java/android/mtp/MtpStorage.java +++ b/media/java/android/mtp/MtpStorage.java @@ -19,6 +19,8 @@ package android.mtp; import android.compat.annotation.UnsupportedAppUsage; import android.os.storage.StorageVolume; +import java.util.function.Supplier; + /** * This class represents a storage unit on an MTP device. * Used only for MTP support in USB responder mode. @@ -33,14 +35,16 @@ public class MtpStorage { private final boolean mRemovable; private final long mMaxFileSize; private final String mVolumeName; + private final Supplier<Boolean> mIsHostWindows; - public MtpStorage(StorageVolume volume, int storageId) { + public MtpStorage(StorageVolume volume, int storageId, Supplier<Boolean> isHostWindows) { mStorageId = storageId; mPath = volume.getPath(); mDescription = volume.getDescription(null); mRemovable = volume.isRemovable(); mMaxFileSize = volume.getMaxFileSize(); mVolumeName = volume.getMediaStoreVolumeName(); + mIsHostWindows = isHostWindows; } /** @@ -93,4 +97,13 @@ public class MtpStorage { public String getVolumeName() { return mVolumeName; } + + /** + * Returns true if the mtp host of this storage is Windows. + * + * @return is host Windows + */ + public boolean isHostWindows() { + return mIsHostWindows.get(); + } } diff --git a/media/java/android/mtp/MtpStorageManager.java b/media/java/android/mtp/MtpStorageManager.java index 0bede0dccbed..e9426cf2ce31 100644 --- a/media/java/android/mtp/MtpStorageManager.java +++ b/media/java/android/mtp/MtpStorageManager.java @@ -18,7 +18,11 @@ package android.mtp; import android.media.MediaFile; import android.os.FileObserver; +import android.os.SystemProperties; import android.os.storage.StorageVolume; +import android.system.ErrnoException; +import android.system.Os; +import android.system.StructStat; import android.util.Log; import com.android.internal.util.Preconditions; @@ -35,6 +39,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.function.Supplier; /** * MtpStorageManager provides functionality for listing, tracking, and notifying MtpServer of @@ -199,7 +204,38 @@ public class MtpStorageManager { } public long getSize() { - return mIsDir ? 0 : getPath().toFile().length(); + return mIsDir ? 0 : maybeApplyTranscodeLengthWorkaround(getPath().toFile().length()); + } + + private long maybeApplyTranscodeLengthWorkaround(long length) { + // Windows truncates transferred files to the size advertised in the object property. + if (mStorage.isHostWindows() && isTranscodeMtpEnabled() && isFileTranscodeSupported()) { + // If the file supports transcoding, we double the returned size to accommodate + // the increase in size from transcoding to AVC. This is the same heuristic + // applied in the FUSE daemon (MediaProvider). + return length * 2; + } + return length; + } + + private boolean isTranscodeMtpEnabled() { + return SystemProperties.getBoolean("sys.fuse.transcode_mtp", false); + } + + private boolean isFileTranscodeSupported() { + // Check if the file supports transcoding by reading the |st_nlinks| struct stat + // field. This will be > 1 if the file supports transcoding. The FUSE daemon + // sets the field accordingly to enable the MTP stack workaround some Windows OS + // MTP client bug where they ignore the size returned as part of getting the MTP + // object, see MtpServer#doGetObject. + final Path path = getPath(); + try { + StructStat stat = Os.stat(path.toString()); + return stat.st_nlink > 1; + } catch (ErrnoException e) { + Log.w(TAG, "Failed to stat path: " + getPath() + ". Ignoring transcoding."); + return false; + } } public Path getPath() { @@ -420,10 +456,12 @@ public class MtpStorageManager { * @param volume Storage to add. * @return the associated MtpStorage */ - public synchronized MtpStorage addMtpStorage(StorageVolume volume) { + public synchronized MtpStorage addMtpStorage(StorageVolume volume, + Supplier<Boolean> isHostWindows) { int storageId = ((getNextStorageId() & 0x0000FFFF) << 16) + 1; - MtpStorage storage = new MtpStorage(volume, storageId); - MtpObject root = new MtpObject(storage.getPath(), storageId, storage, null, true); + MtpStorage storage = new MtpStorage(volume, storageId, isHostWindows); + MtpObject root = new MtpObject(storage.getPath(), storageId, storage, /* parent= */ null, + /* isDir= */ true); mRoots.put(storageId, root); return storage; } diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/BtProfileConnectionInfoTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/BtProfileConnectionInfoTest.java deleted file mode 100644 index fd66d3b9904e..000000000000 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/BtProfileConnectionInfoTest.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.mediaframeworktest.unit; - -import static org.junit.Assert.assertEquals; - -import android.bluetooth.BluetoothProfile; -import android.media.BtProfileConnectionInfo; - -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -public class BtProfileConnectionInfoTest { - - @Test - public void testCoverageA2dp() { - final boolean supprNoisy = false; - final int volume = 42; - final BtProfileConnectionInfo info = BtProfileConnectionInfo.a2dpInfo(supprNoisy, volume); - assertEquals(info.getProfile(), BluetoothProfile.A2DP); - assertEquals(info.getSuppressNoisyIntent(), supprNoisy); - assertEquals(info.getVolume(), volume); - } - - @Test - public void testCoverageA2dpSink() { - final int volume = 42; - final BtProfileConnectionInfo info = BtProfileConnectionInfo.a2dpSinkInfo(volume); - assertEquals(info.getProfile(), BluetoothProfile.A2DP_SINK); - assertEquals(info.getVolume(), volume); - } - - @Test - public void testCoveragehearingAid() { - final boolean supprNoisy = true; - final BtProfileConnectionInfo info = BtProfileConnectionInfo.hearingAidInfo(supprNoisy); - assertEquals(info.getProfile(), BluetoothProfile.HEARING_AID); - assertEquals(info.getSuppressNoisyIntent(), supprNoisy); - } - - @Test - public void testCoverageLeAudio() { - final boolean supprNoisy = false; - final boolean isLeOutput = true; - final BtProfileConnectionInfo info = BtProfileConnectionInfo.leAudio(supprNoisy, - isLeOutput); - assertEquals(info.getProfile(), BluetoothProfile.LE_AUDIO); - assertEquals(info.getSuppressNoisyIntent(), supprNoisy); - assertEquals(info.getIsLeOutput(), isLeOutput); - } -} - diff --git a/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java b/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java index fdf65823b1f3..eb357f67caea 100644 --- a/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java +++ b/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java @@ -159,10 +159,11 @@ public class MtpStorageManagerTest { Log.d(TAG, "sendObjectInfoChanged: " + id); objectsInfoChanged.add(id); } - }, null); + }, /* subdirectories= */ null); - mainMtpStorage = manager.addMtpStorage(mainStorage); - secondaryMtpStorage = manager.addMtpStorage(secondaryStorage); + mainMtpStorage = manager.addMtpStorage(mainStorage, /* isHostWindows= */ () -> false); + secondaryMtpStorage = manager.addMtpStorage(secondaryStorage, + /* isHostWindows= */ () -> false); } @After diff --git a/native/android/OWNERS b/native/android/OWNERS index 8b35f8d38691..3fb524d1e8c6 100644 --- a/native/android/OWNERS +++ b/native/android/OWNERS @@ -1,14 +1,23 @@ -jreck@google.com +jreck@google.com #{LAST_RESORT_SUGGESTION} +# General NDK API reviewers +per-file libandroid.map.txt = danalbert@google.com, etalvala@google.com, michaelwr@google.com +per-file libandroid.map.txt = jreck@google.com, zyy@google.com + +# Networking per-file libandroid_net.map.txt, net.c = set noparent per-file libandroid_net.map.txt, net.c = jchalard@google.com, junyulai@google.com per-file libandroid_net.map.txt, net.c = lorenzo@google.com, reminv@google.com, satk@google.com + +# Fonts per-file system_fonts.cpp = file:/graphics/java/android/graphics/fonts/OWNERS +# Window manager per-file native_window_jni.cpp = file:/services/core/java/com/android/server/wm/OWNERS per-file native_activity.cpp = file:/services/core/java/com/android/server/wm/OWNERS per-file surface_control.cpp = file:/services/core/java/com/android/server/wm/OWNERS +# Graphics per-file choreographer.cpp = file:/graphics/java/android/graphics/OWNERS per-file hardware_buffer_jni.cpp = file:/graphics/java/android/graphics/OWNERS per-file native_window_jni.cpp = file:/graphics/java/android/graphics/OWNERS diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt index f33e11817730..220175398eba 100644 --- a/native/android/libandroid.map.txt +++ b/native/android/libandroid.map.txt @@ -300,6 +300,9 @@ LIBANDROID { android_res_nquery; # introduced=29 android_res_nresult; # introduced=29 android_res_nsend; # introduced=29 + android_tag_socket_with_uid; # introduced=Tiramisu + android_tag_socket; # introduced=Tiramisu + android_untag_socket; # introduced=Tiramisu AThermal_acquireManager; # introduced=30 AThermal_releaseManager; # introduced=30 AThermal_getCurrentThermalStatus; # introduced=30 diff --git a/omapi/aidl/vts/functional/config/Android.bp b/omapi/aidl/vts/functional/config/Android.bp new file mode 100644 index 000000000000..7c08257bf828 --- /dev/null +++ b/omapi/aidl/vts/functional/config/Android.bp @@ -0,0 +1,26 @@ +// +// Copyright (C) 2022 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"], +} + +xsd_config { + name: "omapi_uuid_map_config", + srcs: ["omapi_uuid_map_config.xsd"], + api_dir: "schema", + package_name: "omapi.uuid.map.config", +} diff --git a/omapi/aidl/vts/functional/config/omapi_uuid_map_config.xsd b/omapi/aidl/vts/functional/config/omapi_uuid_map_config.xsd new file mode 100644 index 000000000000..ffeb7a032c38 --- /dev/null +++ b/omapi/aidl/vts/functional/config/omapi_uuid_map_config.xsd @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2022 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. +--> +<xs:schema version="2.0" + attributeFormDefault="unqualified" + elementFormDefault="qualified" + xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <xs:element name="ref_do"> + <xs:complexType> + <xs:sequence> + <xs:element name="uuid_ref_do" maxOccurs="unbounded" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="uids"> + <xs:complexType> + <xs:sequence> + <xs:element type="xs:short" name="uid" maxOccurs="unbounded" minOccurs="0"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element type="xs:string" name="uuid"/> + </xs:sequence> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:complexType> + </xs:element> +</xs:schema> diff --git a/omapi/aidl/vts/functional/config/schema/current.txt b/omapi/aidl/vts/functional/config/schema/current.txt new file mode 100644 index 000000000000..c2e930b949d9 --- /dev/null +++ b/omapi/aidl/vts/functional/config/schema/current.txt @@ -0,0 +1,30 @@ +// Signature format: 2.0 +package omapi.uuid.map.config { + + public class RefDo { + ctor public RefDo(); + method public java.util.List<omapi.uuid.map.config.RefDo.UuidRefDo> getUuid_ref_do(); + } + + public static class RefDo.UuidRefDo { + ctor public RefDo.UuidRefDo(); + method public omapi.uuid.map.config.RefDo.UuidRefDo.Uids getUids(); + method public String getUuid(); + method public void setUids(omapi.uuid.map.config.RefDo.UuidRefDo.Uids); + method public void setUuid(String); + } + + public static class RefDo.UuidRefDo.Uids { + ctor public RefDo.UuidRefDo.Uids(); + method public java.util.List<java.lang.Short> getUid(); + } + + public class XmlParser { + ctor public XmlParser(); + method public static omapi.uuid.map.config.RefDo read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException; + method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; + method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; + } + +} + diff --git a/omapi/aidl/vts/functional/config/schema/last_current.txt b/omapi/aidl/vts/functional/config/schema/last_current.txt new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/omapi/aidl/vts/functional/config/schema/last_current.txt diff --git a/omapi/aidl/vts/functional/config/schema/last_removed.txt b/omapi/aidl/vts/functional/config/schema/last_removed.txt new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/omapi/aidl/vts/functional/config/schema/last_removed.txt diff --git a/apex/media/framework/api/removed.txt b/omapi/aidl/vts/functional/config/schema/removed.txt index d802177e249b..d802177e249b 100644 --- a/apex/media/framework/api/removed.txt +++ b/omapi/aidl/vts/functional/config/schema/removed.txt diff --git a/omapi/aidl/vts/functional/omapi/Android.bp b/omapi/aidl/vts/functional/omapi/Android.bp index c3ab8d13920c..c41479f9e9cf 100644 --- a/omapi/aidl/vts/functional/omapi/Android.bp +++ b/omapi/aidl/vts/functional/omapi/Android.bp @@ -39,6 +39,11 @@ cc_test { static_libs: [ "VtsHalHidlTargetTestBase", "android.se.omapi-V1-ndk", + "android.hardware.audio.common.test.utility", + "libxml2", + ], + data: [ + ":omapi_uuid_map_config", ], cflags: [ "-O0", @@ -51,4 +56,5 @@ cc_test { "general-tests", "vts", ], + test_config: "VtsHalOmapiSeServiceV1_TargetTest.xml", } diff --git a/omapi/aidl/vts/functional/omapi/VtsHalOmapiSeServiceV1_TargetTest.cpp b/omapi/aidl/vts/functional/omapi/VtsHalOmapiSeServiceV1_TargetTest.cpp index 319cb7e70884..5303651b4b22 100644 --- a/omapi/aidl/vts/functional/omapi/VtsHalOmapiSeServiceV1_TargetTest.cpp +++ b/omapi/aidl/vts/functional/omapi/VtsHalOmapiSeServiceV1_TargetTest.cpp @@ -32,6 +32,7 @@ #include <hidl/GtestPrinter.h> #include <hidl/ServiceManagement.h> #include <utils/String16.h> +#include "utility/ValidateXml.h" using namespace std; using namespace ::testing; @@ -176,6 +177,25 @@ class OMAPISEServiceHalTest : public TestWithParam<std::string> { return (deviceSupportsFeature(FEATURE_SE_OMAPI_ESE.c_str())); } + std::optional<std::string> getUuidMappingFile() { + char value[PROPERTY_VALUE_MAX] = {0}; + int len = property_get("ro.boot.product.hardware.sku", value, "config"); + std::string uuidMappingConfigFile = UUID_MAPPING_CONFIG_PREFIX + + std::string(value, len) + + UUID_MAPPING_CONFIG_EXT; + std::string uuidMapConfigPath; + // Search in predefined folders + for (auto path : UUID_MAPPING_CONFIG_PATHS) { + uuidMapConfigPath = path + uuidMappingConfigFile; + auto confFile = fopen(uuidMapConfigPath.c_str(), "r"); + if (confFile) { + fclose(confFile); + return uuidMapConfigPath; + } + } + return std::optional<std::string>(); + } + void SetUp() override { LOG(INFO) << "get OMAPI service with name:" << GetParam(); ::ndk::SpAIBinder ks2Binder(AServiceManager_getService(GetParam().c_str())); @@ -300,6 +320,10 @@ class OMAPISEServiceHalTest : public TestWithParam<std::string> { std::map<std::string, std::shared_ptr<aidl::android::se::omapi::ISecureElementReader>> mVSReaders = {}; + + std::string UUID_MAPPING_CONFIG_PREFIX = "hal_uuid_map_"; + std::string UUID_MAPPING_CONFIG_EXT = ".xml"; + std::string UUID_MAPPING_CONFIG_PATHS[3] = {"/odm/etc/", "/vendor/etc/", "/etc/"}; }; /** Tests getReaders API */ @@ -600,6 +624,14 @@ TEST_P(OMAPISEServiceHalTest, TestP2Value) { } } +TEST_P(OMAPISEServiceHalTest, TestUuidMappingConfig) { + constexpr const char* xsd = "/data/local/tmp/omapi_uuid_map_config.xsd"; + auto uuidMappingFile = getUuidMappingFile(); + ASSERT_TRUE(uuidMappingFile.has_value()) << "Unable to determine UUID mapping config file path"; + LOG(INFO) << "UUID Mapping config file: " << uuidMappingFile.value(); + EXPECT_VALID_XML(uuidMappingFile->c_str(), xsd); +} + INSTANTIATE_TEST_SUITE_P(PerInstance, OMAPISEServiceHalTest, testing::ValuesIn(::android::getAidlHalInstanceNames( aidl::android::se::omapi::ISecureElementService::descriptor)), diff --git a/omapi/aidl/vts/functional/omapi/VtsHalOmapiSeServiceV1_TargetTest.xml b/omapi/aidl/vts/functional/omapi/VtsHalOmapiSeServiceV1_TargetTest.xml new file mode 100644 index 000000000000..3ee0414711f3 --- /dev/null +++ b/omapi/aidl/vts/functional/omapi/VtsHalOmapiSeServiceV1_TargetTest.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2022 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. +--> +<configuration description="Runs VtsHalOmapiSeServiceV1_TargetTest."> + <option name="test-suite-tag" value="apct" /> + <option name="test-suite-tag" value="apct-native" /> + + <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"> + </target_preparer> + + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> + <option name="cleanup" value="true" /> + <option name="push" + value="omapi_uuid_map_config.xsd->/data/local/tmp/omapi_uuid_map_config.xsd" /> + <option name="push" + value="VtsHalOmapiSeServiceV1_TargetTest->/data/local/tmp/VtsHalOmapiSeServiceV1_TargetTest" /> + </target_preparer> + + <test class="com.android.tradefed.testtype.GTest" > + <option name="native-test-device-path" value="/data/local/tmp" /> + <option name="module-name" value="VtsHalOmapiSeServiceV1_TargetTest" /> + </test> +</configuration> diff --git a/packages/ConnectivityT/framework-t/Android.bp b/packages/ConnectivityT/framework-t/Android.bp index 223bdcdd9c95..66527802a0e4 100644 --- a/packages/ConnectivityT/framework-t/Android.bp +++ b/packages/ConnectivityT/framework-t/Android.bp @@ -39,7 +39,6 @@ filegroup { "src/android/net/TrafficStats.java", "src/android/net/UnderlyingNetworkInfo.*", "src/android/net/netstats/**/*.*", - "src/com/android/server/NetworkManagementSocketTagger.java", ], path: "src", visibility: [ @@ -126,14 +125,14 @@ filegroup { name: "framework-connectivity-ethernet-sources", srcs: [ "src/android/net/EthernetManager.java", + "src/android/net/EthernetNetworkManagementException.java", + "src/android/net/EthernetNetworkManagementException.aidl", "src/android/net/EthernetNetworkSpecifier.java", + "src/android/net/EthernetNetworkUpdateRequest.java", + "src/android/net/EthernetNetworkUpdateRequest.aidl", "src/android/net/IEthernetManager.aidl", + "src/android/net/IEthernetNetworkManagementListener.aidl", "src/android/net/IEthernetServiceListener.aidl", - "src/android/net/IInternalNetworkManagementListener.aidl", - "src/android/net/InternalNetworkUpdateRequest.java", - "src/android/net/InternalNetworkUpdateRequest.aidl", - "src/android/net/InternalNetworkManagementException.java", - "src/android/net/InternalNetworkManagementException.aidl", "src/android/net/ITetheredInterfaceCallback.aidl", ], path: "src", @@ -159,8 +158,6 @@ filegroup { name: "framework-connectivity-tiramisu-sources", srcs: [ ":framework-connectivity-ethernet-sources", - ":framework-connectivity-ipsec-sources", - ":framework-connectivity-netstats-sources", ], visibility: ["//frameworks/base"], } @@ -168,6 +165,8 @@ filegroup { filegroup { name: "framework-connectivity-tiramisu-updatable-sources", srcs: [ + ":framework-connectivity-ipsec-sources", + ":framework-connectivity-netstats-sources", ":framework-connectivity-nsd-sources", ":framework-connectivity-tiramisu-internal-sources", ], @@ -176,3 +175,31 @@ filegroup { "//packages/modules/Connectivity:__subpackages__", ], } + +cc_library_shared { + name: "libframework-connectivity-tiramisu-jni", + min_sdk_version: "30", + cflags: [ + "-Wall", + "-Werror", + "-Wno-unused-parameter", + // Don't warn about S API usage even with + // min_sdk 30: the library is only loaded + // on S+ devices + "-Wno-unguarded-availability", + "-Wthread-safety", + ], + srcs: [ + "jni/android_net_TrafficStats.cpp", + "jni/onload.cpp", + ], + shared_libs: [ + "libandroid", + "liblog", + "libnativehelper", + ], + stl: "none", + apex_available: [ + "com.android.tethering", + ], +} diff --git a/packages/ConnectivityT/framework-t/jni/android_net_TrafficStats.cpp b/packages/ConnectivityT/framework-t/jni/android_net_TrafficStats.cpp new file mode 100644 index 000000000000..f3c58b112f0d --- /dev/null +++ b/packages/ConnectivityT/framework-t/jni/android_net_TrafficStats.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2022 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. + */ + +#include <android/file_descriptor_jni.h> +#include <android/multinetwork.h> +#include <nativehelper/JNIHelp.h> + +namespace android { + +static jint tagSocketFd(JNIEnv* env, jclass, jobject fileDescriptor, jint tag, jint uid) { + int fd = AFileDescriptor_getFd(env, fileDescriptor); + if (fd == -1) return -EBADF; + return android_tag_socket_with_uid(fd, tag, uid); +} + +static jint untagSocketFd(JNIEnv* env, jclass, jobject fileDescriptor) { + int fd = AFileDescriptor_getFd(env, fileDescriptor); + if (fd == -1) return -EBADF; + return android_untag_socket(fd); +} + +static const JNINativeMethod gMethods[] = { + /* name, signature, funcPtr */ + { "native_tagSocketFd", "(Ljava/io/FileDescriptor;II)I", (void*) tagSocketFd }, + { "native_untagSocketFd", "(Ljava/io/FileDescriptor;)I", (void*) untagSocketFd }, +}; + +int register_android_net_TrafficStats(JNIEnv* env) { + return jniRegisterNativeMethods(env, "android/net/TrafficStats", gMethods, NELEM(gMethods)); +} + +}; // namespace android + diff --git a/packages/ConnectivityT/framework-t/jni/onload.cpp b/packages/ConnectivityT/framework-t/jni/onload.cpp new file mode 100644 index 000000000000..1fb42c63477e --- /dev/null +++ b/packages/ConnectivityT/framework-t/jni/onload.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2022 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. + */ + +#define LOG_TAG "FrameworkConnectivityJNI" + +#include <log/log.h> +#include <nativehelper/JNIHelp.h> + +namespace android { + +int register_android_net_TrafficStats(JNIEnv* env); + +extern "C" jint JNI_OnLoad(JavaVM* vm, void*) { + JNIEnv *env; + if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { + __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "ERROR: GetEnv failed"); + return JNI_ERR; + } + + if (register_android_net_TrafficStats(env) < 0) return JNI_ERR; + + return JNI_VERSION_1_6; +} + +}; // namespace android + diff --git a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java index 5ce7e59b38ff..ca080ce4c64a 100644 --- a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -27,7 +27,6 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; -import android.annotation.TestApi; import android.annotation.WorkerThread; import android.app.usage.NetworkStats.Bucket; import android.compat.annotation.UnsupportedAppUsage; @@ -192,9 +191,13 @@ public class NetworkStatsManager { } } - /** @hide */ + /** + * Set poll force flag to indicate that calling any subsequent query method will force a stats + * poll. + * @hide + */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @TestApi + @SystemApi(client = MODULE_LIBRARIES) public void setPollForce(boolean pollForce) { if (pollForce) { mFlags |= FLAG_POLL_FORCE; @@ -696,7 +699,9 @@ public class NetworkStatsManager { * @hide */ @SystemApi - @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK}) @NonNull public android.net.NetworkStats getMobileUidStats() { try { return mService.getUidStatsForTransport(TRANSPORT_CELLULAR); @@ -720,7 +725,9 @@ public class NetworkStatsManager { * @hide */ @SystemApi - @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK}) @NonNull public android.net.NetworkStats getWifiUidStats() { try { return mService.getUidStatsForTransport(TRANSPORT_WIFI); @@ -737,8 +744,9 @@ public class NetworkStatsManager { * {@link #unregisterUsageCallback} is called. * * @param template Template used to match networks. See {@link NetworkTemplate}. - * @param thresholdBytes Threshold in bytes to be notified on. The provided value that lower - * than 2MiB will be clamped for non-privileged callers. + * @param thresholdBytes Threshold in bytes to be notified on. Provided values lower than 2MiB + * will be clamped for callers except callers with the NETWORK_STACK + * permission. * @param executor The executor on which callback will be invoked. The provided {@link Executor} * must run callback sequentially, otherwise the order of callbacks cannot be * guaranteed. @@ -747,6 +755,9 @@ public class NetworkStatsManager { * @hide */ @SystemApi(client = MODULE_LIBRARIES) + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK}, conditional = true) public void registerUsageCallback(@NonNull NetworkTemplate template, long thresholdBytes, @NonNull @CallbackExecutor Executor executor, @NonNull UsageCallback callback) { Objects.requireNonNull(template, "NetworkTemplate cannot be null"); diff --git a/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java b/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java index 630f902ecfd7..9bffbfb27a8d 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java +++ b/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java @@ -18,6 +18,7 @@ package android.net; import android.annotation.SystemApi; import android.app.SystemServiceRegistry; +import android.app.usage.NetworkStatsManager; import android.content.Context; import android.net.nsd.INsdManager; import android.net.nsd.NsdManager; @@ -48,5 +49,24 @@ public final class ConnectivityFrameworkInitializerTiramisu { return new NsdManager(context, service); } ); + + SystemServiceRegistry.registerContextAwareService( + Context.IPSEC_SERVICE, + IpSecManager.class, + (context, serviceBinder) -> { + IIpSecService service = IIpSecService.Stub.asInterface(serviceBinder); + return new IpSecManager(context, service); + } + ); + + SystemServiceRegistry.registerContextAwareService( + Context.NETWORK_STATS_SERVICE, + NetworkStatsManager.class, + (context, serviceBinder) -> { + INetworkStatsService service = + INetworkStatsService.Stub.asInterface(serviceBinder); + return new NetworkStatsManager(context, service); + } + ); } } diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java index ece54df96665..72243f9e87d9 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java +++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java @@ -16,28 +16,34 @@ package android.net; +import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; + import android.annotation.CallbackExecutor; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; -import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; +import android.content.pm.PackageManager; import android.os.Build; import android.os.RemoteException; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.BackgroundThread; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Objects; import java.util.concurrent.Executor; import java.util.function.BiConsumer; /** - * A class representing the IP configuration of the Ethernet network. + * A class that manages and configures Ethernet interfaces. * * @hide */ @@ -52,11 +58,13 @@ public class EthernetManager { private final IEthernetServiceListener.Stub mServiceListener = new IEthernetServiceListener.Stub() { @Override - public void onAvailabilityChanged(String iface, boolean isAvailable) { + public void onInterfaceStateChanged(String iface, int state, int role, + IpConfiguration configuration) { synchronized (mListeners) { for (ListenerInfo li : mListeners) { li.executor.execute(() -> - li.listener.onAvailabilityChanged(iface, isAvailable)); + li.listener.onInterfaceStateChanged(iface, state, role, + configuration)); } } } @@ -66,19 +74,93 @@ public class EthernetManager { @NonNull public final Executor executor; @NonNull - public final Listener listener; + public final InterfaceStateListener listener; - private ListenerInfo(@NonNull Executor executor, @NonNull Listener listener) { + private ListenerInfo(@NonNull Executor executor, @NonNull InterfaceStateListener listener) { this.executor = executor; this.listener = listener; } } /** + * The interface is absent. + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public static final int STATE_ABSENT = 0; + + /** + * The interface is present but link is down. + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public static final int STATE_LINK_DOWN = 1; + + /** + * The interface is present and link is up. + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public static final int STATE_LINK_UP = 2; + + /** @hide */ + @IntDef(prefix = "STATE_", value = {STATE_ABSENT, STATE_LINK_DOWN, STATE_LINK_UP}) + @Retention(RetentionPolicy.SOURCE) + public @interface InterfaceState {} + + /** + * The interface currently does not have any specific role. + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public static final int ROLE_NONE = 0; + + /** + * The interface is in client mode (e.g., connected to the Internet). + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public static final int ROLE_CLIENT = 1; + + /** + * Ethernet interface is in server mode (e.g., providing Internet access to tethered devices). + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public static final int ROLE_SERVER = 2; + + /** @hide */ + @IntDef(prefix = "ROLE_", value = {ROLE_NONE, ROLE_CLIENT, ROLE_SERVER}) + @Retention(RetentionPolicy.SOURCE) + public @interface Role {} + + /** + * A listener that receives notifications about the state of Ethernet interfaces on the system. + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public interface InterfaceStateListener { + /** + * Called when an Ethernet interface changes state. + * + * @param iface the name of the interface. + * @param state the current state of the interface, or {@link #STATE_ABSENT} if the + * interface was removed. + * @param role whether the interface is in client mode or server mode. + * @param configuration the current IP configuration of the interface. + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + void onInterfaceStateChanged(@NonNull String iface, @InterfaceState int state, + @Role int role, @Nullable IpConfiguration configuration); + } + + /** * A listener interface to receive notification on changes in Ethernet. + * This has never been a supported API. Use {@link InterfaceStateListener} instead. * @hide */ - public interface Listener { + public interface Listener extends InterfaceStateListener { /** * Called when Ethernet port's availability is changed. * @param iface Ethernet interface name @@ -87,6 +169,13 @@ public class EthernetManager { */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) void onAvailabilityChanged(String iface, boolean isAvailable); + + /** Default implementation for backwards compatibility. Only calls the legacy listener. */ + default void onInterfaceStateChanged(@NonNull String iface, @InterfaceState int state, + @Role int role, @Nullable IpConfiguration configuration) { + onAvailabilityChanged(iface, (state >= STATE_LINK_UP)); + } + } /** @@ -119,7 +208,7 @@ public class EthernetManager { * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public void setConfiguration(String iface, IpConfiguration config) { + public void setConfiguration(@NonNull String iface, @NonNull IpConfiguration config) { try { mService.setConfiguration(iface, config); } catch (RemoteException e) { @@ -153,9 +242,8 @@ public class EthernetManager { /** * Adds a listener. + * This has never been a supported API. Use {@link #addInterfaceStateListener} instead. * - * Consider using {@link #addListener(Listener, Executor)} instead: this method uses a default - * executor that may have higher latency than a provided executor. * @param listener A {@link Listener} to add. * @throws IllegalArgumentException If the listener is null. * @hide @@ -167,6 +255,8 @@ public class EthernetManager { /** * Adds a listener. + * This has never been a supported API. Use {@link #addInterfaceStateListener} instead. + * * @param listener A {@link Listener} to add. * @param executor Executor to run callbacks on. * @throws IllegalArgumentException If the listener or executor is null. @@ -174,6 +264,28 @@ public class EthernetManager { */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void addListener(@NonNull Listener listener, @NonNull Executor executor) { + addInterfaceStateListener(executor, listener); + } + + /** + * Listen to changes in the state of Ethernet interfaces. + * + * Adds a listener to receive notification for any state change of all existing Ethernet + * interfaces. + * <p>{@link Listener#onInterfaceStateChanged} will be triggered immediately for all + * existing interfaces upon adding a listener. The same method will be called on the + * listener every time any of the interface changes state. In particular, if an + * interface is removed, it will be called with state {@link #STATE_ABSENT}. + * <p>Use {@link #removeInterfaceStateListener} with the same object to stop listening. + * + * @param executor Executor to run callbacks on. + * @param listener A {@link Listener} to add. + * @hide + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @SystemApi(client = MODULE_LIBRARIES) + public void addInterfaceStateListener(@NonNull Executor executor, + @NonNull InterfaceStateListener listener) { if (listener == null || executor == null) { throw new NullPointerException("listener and executor must not be null"); } @@ -204,15 +316,13 @@ public class EthernetManager { /** * Removes a listener. + * * @param listener A {@link Listener} to remove. - * @throws IllegalArgumentException If the listener is null. * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public void removeListener(@NonNull Listener listener) { - if (listener == null) { - throw new IllegalArgumentException("listener must not be null"); - } + @SystemApi(client = MODULE_LIBRARIES) + public void removeInterfaceStateListener(@NonNull InterfaceStateListener listener) { + Objects.requireNonNull(listener); synchronized (mListeners) { mListeners.removeIf(l -> l.listener == listener); if (mListeners.isEmpty()) { @@ -226,12 +336,26 @@ public class EthernetManager { } /** + * Removes a listener. + * This has never been a supported API. Use {@link #removeInterfaceStateListener} instead. + * @param listener A {@link Listener} to remove. + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public void removeListener(@NonNull Listener listener) { + if (listener == null) { + throw new IllegalArgumentException("listener must not be null"); + } + removeInterfaceStateListener(listener); + } + + /** * Whether to treat interfaces created by {@link TestNetworkManager#createTapInterface} * as Ethernet interfaces. The effects of this method apply to any test interfaces that are * already present on the system. * @hide */ - @TestApi + @SystemApi(client = MODULE_LIBRARIES) public void setIncludeTestInterfaces(boolean include) { try { mService.setIncludeTestInterfaces(include); @@ -320,15 +444,15 @@ public class EthernetManager { } private static final class InternalNetworkManagementListener - extends IInternalNetworkManagementListener.Stub { + extends IEthernetNetworkManagementListener.Stub { @NonNull private final Executor mExecutor; @NonNull - private final BiConsumer<Network, InternalNetworkManagementException> mListener; + private final BiConsumer<Network, EthernetNetworkManagementException> mListener; InternalNetworkManagementListener( @NonNull final Executor executor, - @NonNull final BiConsumer<Network, InternalNetworkManagementException> listener) { + @NonNull final BiConsumer<Network, EthernetNetworkManagementException> listener) { Objects.requireNonNull(executor, "Pass a non-null executor"); Objects.requireNonNull(listener, "Pass a non-null listener"); mExecutor = executor; @@ -338,14 +462,14 @@ public class EthernetManager { @Override public void onComplete( @Nullable final Network network, - @Nullable final InternalNetworkManagementException e) { + @Nullable final EthernetNetworkManagementException e) { mExecutor.execute(() -> mListener.accept(network, e)); } } private InternalNetworkManagementListener getInternalNetworkManagementListener( @Nullable final Executor executor, - @Nullable final BiConsumer<Network, InternalNetworkManagementException> listener) { + @Nullable final BiConsumer<Network, EthernetNetworkManagementException> listener) { if (null != listener) { Objects.requireNonNull(executor, "Pass a non-null executor, or a null listener"); } @@ -358,11 +482,43 @@ public class EthernetManager { return proxy; } - private void updateConfiguration( + /** + * Updates the configuration of an automotive device's ethernet network. + * + * The {@link EthernetNetworkUpdateRequest} {@code request} argument describes how to update the + * configuration for this network. + * Use {@link StaticIpConfiguration.Builder} to build a {@code StaticIpConfiguration} object for + * this network to put inside the {@code request}. + * Similarly, use {@link NetworkCapabilities.Builder} to build a {@code NetworkCapabilities} + * object for this network to put inside the {@code request}. + * + * If non-null, the listener will be called exactly once after this is called, unless + * a synchronous exception was thrown. + * + * @param iface the name of the interface to act upon. + * @param request the {@link EthernetNetworkUpdateRequest} used to set an ethernet network's + * {@link StaticIpConfiguration} and {@link NetworkCapabilities} values. + * @param executor an {@link Executor} to execute the listener on. Optional if listener is null. + * @param listener an optional {@link BiConsumer} to listen for completion of the operation. + * @throws SecurityException if the process doesn't hold + * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. + * @throws UnsupportedOperationException if called on a non-automotive device or on an + * unsupported interface. + * @hide + */ + @SystemApi + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK, + android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) + @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) + public void updateConfiguration( @NonNull String iface, - @NonNull InternalNetworkUpdateRequest request, + @NonNull EthernetNetworkUpdateRequest request, @Nullable @CallbackExecutor Executor executor, - @Nullable BiConsumer<Network, InternalNetworkManagementException> listener) { + @Nullable BiConsumer<Network, EthernetNetworkManagementException> listener) { + Objects.requireNonNull(iface, "iface must be non-null"); + Objects.requireNonNull(request, "request must be non-null"); final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( executor, listener); try { @@ -372,10 +528,34 @@ public class EthernetManager { } } - private void connectNetwork( + /** + * Set an ethernet network's link state up. + * + * When the link is successfully turned up, the listener will be called with the resulting + * network. If any error or unexpected condition happens while the system tries to turn the + * interface up, the listener will be called with an appropriate exception. + * The listener is guaranteed to be called exactly once for each call to this method, but this + * may take an unbounded amount of time depending on the actual network conditions. + * + * @param iface the name of the interface to act upon. + * @param executor an {@link Executor} to execute the listener on. Optional if listener is null. + * @param listener an optional {@link BiConsumer} to listen for completion of the operation. + * @throws SecurityException if the process doesn't hold + * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. + * @throws UnsupportedOperationException if called on a non-automotive device. + * @hide + */ + @SystemApi + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK, + android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) + @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) + public void connectNetwork( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, - @Nullable BiConsumer<Network, InternalNetworkManagementException> listener) { + @Nullable BiConsumer<Network, EthernetNetworkManagementException> listener) { + Objects.requireNonNull(iface, "iface must be non-null"); final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( executor, listener); try { @@ -385,10 +565,33 @@ public class EthernetManager { } } - private void disconnectNetwork( + /** + * Set an ethernet network's link state down. + * + * When the link is successfully turned down, the listener will be called with the network that + * was torn down, if any. If any error or unexpected condition happens while the system tries to + * turn the interface down, the listener will be called with an appropriate exception. + * The listener is guaranteed to be called exactly once for each call to this method. + * + * @param iface the name of the interface to act upon. + * @param executor an {@link Executor} to execute the listener on. Optional if listener is null. + * @param listener an optional {@link BiConsumer} to listen for completion of the operation. + * @throws SecurityException if the process doesn't hold + * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. + * @throws UnsupportedOperationException if called on a non-automotive device. + * @hide + */ + @SystemApi + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK, + android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) + @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) + public void disconnectNetwork( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, - @Nullable BiConsumer<Network, InternalNetworkManagementException> listener) { + @Nullable BiConsumer<Network, EthernetNetworkManagementException> listener) { + Objects.requireNonNull(iface, "iface must be non-null"); final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( executor, listener); try { diff --git a/packages/ConnectivityT/framework-t/src/android/net/InternalNetworkManagementException.aidl b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.aidl index dcce706989f6..adf9e5a4db9d 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/InternalNetworkManagementException.aidl +++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.aidl @@ -16,4 +16,4 @@ package android.net; - parcelable InternalNetworkManagementException;
\ No newline at end of file + parcelable EthernetNetworkManagementException;
\ No newline at end of file diff --git a/packages/ConnectivityT/framework-t/src/android/net/InternalNetworkManagementException.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.java index 7f4e403f2259..a69cc55363b2 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/InternalNetworkManagementException.java +++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.java @@ -17,25 +17,39 @@ package android.net; import android.annotation.NonNull; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; +import java.util.Objects; + /** @hide */ -public final class InternalNetworkManagementException +@SystemApi +public final class EthernetNetworkManagementException extends RuntimeException implements Parcelable { /* @hide */ - public InternalNetworkManagementException(@NonNull final Throwable t) { - super(t); + public EthernetNetworkManagementException(@NonNull final String errorMessage) { + super(errorMessage); + } + + @Override + public int hashCode() { + return Objects.hash(getMessage()); } - private InternalNetworkManagementException(@NonNull final Parcel source) { - super(source.readString()); + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + final EthernetNetworkManagementException that = (EthernetNetworkManagementException) obj; + + return Objects.equals(getMessage(), that.getMessage()); } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeString(getCause().getMessage()); + dest.writeString(getMessage()); } @Override @@ -44,16 +58,16 @@ public final class InternalNetworkManagementException } @NonNull - public static final Parcelable.Creator<InternalNetworkManagementException> CREATOR = - new Parcelable.Creator<InternalNetworkManagementException>() { + public static final Parcelable.Creator<EthernetNetworkManagementException> CREATOR = + new Parcelable.Creator<EthernetNetworkManagementException>() { @Override - public InternalNetworkManagementException[] newArray(int size) { - return new InternalNetworkManagementException[size]; + public EthernetNetworkManagementException[] newArray(int size) { + return new EthernetNetworkManagementException[size]; } @Override - public InternalNetworkManagementException createFromParcel(@NonNull Parcel source) { - return new InternalNetworkManagementException(source); + public EthernetNetworkManagementException createFromParcel(@NonNull Parcel source) { + return new EthernetNetworkManagementException(source.readString()); } }; } diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkSpecifier.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkSpecifier.java index 925d12b574a6..e4d6e248d48a 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkSpecifier.java +++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkSpecifier.java @@ -18,7 +18,6 @@ package android.net; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; @@ -29,9 +28,7 @@ import java.util.Objects; * A {@link NetworkSpecifier} used to identify ethernet interfaces. * * @see EthernetManager - * @hide */ -@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public final class EthernetNetworkSpecifier extends NetworkSpecifier implements Parcelable { /** @@ -61,6 +58,7 @@ public final class EthernetNetworkSpecifier extends NetworkSpecifier implements return mInterfaceName; } + /** @hide */ @Override public boolean canBeSatisfiedBy(@Nullable NetworkSpecifier other) { return equals(other); diff --git a/packages/ConnectivityT/framework-t/src/android/net/InternalNetworkUpdateRequest.aidl b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.aidl index da00cb97afb4..debc348ea363 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/InternalNetworkUpdateRequest.aidl +++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.aidl @@ -16,4 +16,4 @@ package android.net; - parcelable InternalNetworkUpdateRequest;
\ No newline at end of file + parcelable EthernetNetworkUpdateRequest;
\ No newline at end of file diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java new file mode 100644 index 000000000000..a6269711055a --- /dev/null +++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2021 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 android.net; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** @hide */ +@SystemApi +public final class EthernetNetworkUpdateRequest implements Parcelable { + @NonNull + private final IpConfiguration mIpConfig; + @NonNull + private final NetworkCapabilities mNetworkCapabilities; + + @NonNull + public IpConfiguration getIpConfiguration() { + return new IpConfiguration(mIpConfig); + } + + @NonNull + public NetworkCapabilities getNetworkCapabilities() { + return new NetworkCapabilities(mNetworkCapabilities); + } + + private EthernetNetworkUpdateRequest(@NonNull final IpConfiguration ipConfig, + @NonNull final NetworkCapabilities networkCapabilities) { + Objects.requireNonNull(ipConfig); + Objects.requireNonNull(networkCapabilities); + mIpConfig = new IpConfiguration(ipConfig); + mNetworkCapabilities = new NetworkCapabilities(networkCapabilities); + } + + private EthernetNetworkUpdateRequest(@NonNull final Parcel source) { + Objects.requireNonNull(source); + mIpConfig = IpConfiguration.CREATOR.createFromParcel(source); + mNetworkCapabilities = NetworkCapabilities.CREATOR.createFromParcel(source); + } + + /** + * Builder used to create {@link EthernetNetworkUpdateRequest} objects. + */ + public static final class Builder { + @Nullable + private IpConfiguration mBuilderIpConfig; + @Nullable + private NetworkCapabilities mBuilderNetworkCapabilities; + + public Builder(){} + + /** + * Constructor to populate the builder's values with an already built + * {@link EthernetNetworkUpdateRequest}. + * @param request the {@link EthernetNetworkUpdateRequest} to populate with. + */ + public Builder(@NonNull final EthernetNetworkUpdateRequest request) { + Objects.requireNonNull(request); + mBuilderIpConfig = new IpConfiguration(request.mIpConfig); + mBuilderNetworkCapabilities = new NetworkCapabilities(request.mNetworkCapabilities); + } + + /** + * Set the {@link IpConfiguration} to be used with the {@code Builder}. + * @param ipConfig the {@link IpConfiguration} to set. + * @return The builder to facilitate chaining. + */ + @NonNull + public Builder setIpConfiguration(@NonNull final IpConfiguration ipConfig) { + Objects.requireNonNull(ipConfig); + mBuilderIpConfig = new IpConfiguration(ipConfig); + return this; + } + + /** + * Set the {@link NetworkCapabilities} to be used with the {@code Builder}. + * @param nc the {@link NetworkCapabilities} to set. + * @return The builder to facilitate chaining. + */ + @NonNull + public Builder setNetworkCapabilities(@NonNull final NetworkCapabilities nc) { + Objects.requireNonNull(nc); + mBuilderNetworkCapabilities = new NetworkCapabilities(nc); + return this; + } + + /** + * Build {@link EthernetNetworkUpdateRequest} return the current update request. + */ + @NonNull + public EthernetNetworkUpdateRequest build() { + return new EthernetNetworkUpdateRequest(mBuilderIpConfig, mBuilderNetworkCapabilities); + } + } + + @Override + public String toString() { + return "EthernetNetworkUpdateRequest{" + + "mIpConfig=" + mIpConfig + + ", mNetworkCapabilities=" + mNetworkCapabilities + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + EthernetNetworkUpdateRequest that = (EthernetNetworkUpdateRequest) o; + + return Objects.equals(that.getIpConfiguration(), mIpConfig) + && Objects.equals(that.getNetworkCapabilities(), mNetworkCapabilities); + } + + @Override + public int hashCode() { + return Objects.hash(mIpConfig, mNetworkCapabilities); + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + mIpConfig.writeToParcel(dest, flags); + mNetworkCapabilities.writeToParcel(dest, flags); + } + + @Override + public int describeContents() { + return 0; + } + + @NonNull + public static final Parcelable.Creator<EthernetNetworkUpdateRequest> CREATOR = + new Parcelable.Creator<EthernetNetworkUpdateRequest>() { + @Override + public EthernetNetworkUpdateRequest[] newArray(int size) { + return new EthernetNetworkUpdateRequest[size]; + } + + @Override + public EthernetNetworkUpdateRequest createFromParcel(@NonNull Parcel source) { + return new EthernetNetworkUpdateRequest(source); + } + }; +} diff --git a/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl b/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl index e688bea1cfac..544d02ba76ff 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl +++ b/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl @@ -18,8 +18,8 @@ package android.net; import android.net.IpConfiguration; import android.net.IEthernetServiceListener; -import android.net.IInternalNetworkManagementListener; -import android.net.InternalNetworkUpdateRequest; +import android.net.IEthernetNetworkManagementListener; +import android.net.EthernetNetworkUpdateRequest; import android.net.ITetheredInterfaceCallback; /** @@ -38,8 +38,8 @@ interface IEthernetManager void setIncludeTestInterfaces(boolean include); void requestTetheredInterface(in ITetheredInterfaceCallback callback); void releaseTetheredInterface(in ITetheredInterfaceCallback callback); - void updateConfiguration(String iface, in InternalNetworkUpdateRequest request, - in IInternalNetworkManagementListener listener); - void connectNetwork(String iface, in IInternalNetworkManagementListener listener); - void disconnectNetwork(String iface, in IInternalNetworkManagementListener listener); + void updateConfiguration(String iface, in EthernetNetworkUpdateRequest request, + in IEthernetNetworkManagementListener listener); + void connectNetwork(String iface, in IEthernetNetworkManagementListener listener); + void disconnectNetwork(String iface, in IEthernetNetworkManagementListener listener); } diff --git a/packages/ConnectivityT/framework-t/src/android/net/IInternalNetworkManagementListener.aidl b/packages/ConnectivityT/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl index 69cde3bd14e8..93edccfdafd9 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/IInternalNetworkManagementListener.aidl +++ b/packages/ConnectivityT/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl @@ -16,10 +16,10 @@ package android.net; -import android.net.InternalNetworkManagementException; +import android.net.EthernetNetworkManagementException; import android.net.Network; /** @hide */ -oneway interface IInternalNetworkManagementListener { - void onComplete(in Network network, in InternalNetworkManagementException exception); +oneway interface IEthernetNetworkManagementListener { + void onComplete(in Network network, in EthernetNetworkManagementException exception); }
\ No newline at end of file diff --git a/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl b/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl index 782fa19d9df7..6d2ba03f78d4 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl +++ b/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl @@ -16,8 +16,11 @@ package android.net; +import android.net.IpConfiguration; + /** @hide */ oneway interface IEthernetServiceListener { - void onAvailabilityChanged(String iface, boolean isAvailable); + void onInterfaceStateChanged(String iface, int state, int role, + in IpConfiguration configuration); } diff --git a/packages/ConnectivityT/framework-t/src/android/net/InternalNetworkUpdateRequest.java b/packages/ConnectivityT/framework-t/src/android/net/InternalNetworkUpdateRequest.java deleted file mode 100644 index f42c4b7c420d..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/InternalNetworkUpdateRequest.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2021 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 android.net; - -import android.annotation.NonNull; -import android.os.Parcel; -import android.os.Parcelable; - -import java.util.Objects; - -/** @hide */ -public final class InternalNetworkUpdateRequest implements Parcelable { - @NonNull - private final StaticIpConfiguration mIpConfig; - @NonNull - private final NetworkCapabilities mNetworkCapabilities; - - @NonNull - public StaticIpConfiguration getIpConfig() { - return new StaticIpConfiguration(mIpConfig); - } - - @NonNull - public NetworkCapabilities getNetworkCapabilities() { - return new NetworkCapabilities(mNetworkCapabilities); - } - - /** @hide */ - public InternalNetworkUpdateRequest(@NonNull final StaticIpConfiguration ipConfig, - @NonNull final NetworkCapabilities networkCapabilities) { - Objects.requireNonNull(ipConfig); - Objects.requireNonNull(networkCapabilities); - mIpConfig = new StaticIpConfiguration(ipConfig); - mNetworkCapabilities = new NetworkCapabilities(networkCapabilities); - } - - private InternalNetworkUpdateRequest(@NonNull final Parcel source) { - Objects.requireNonNull(source); - mIpConfig = StaticIpConfiguration.CREATOR.createFromParcel(source); - mNetworkCapabilities = NetworkCapabilities.CREATOR.createFromParcel(source); - } - - @Override - public String toString() { - return "InternalNetworkUpdateRequest{" - + "mIpConfig=" + mIpConfig - + ", mNetworkCapabilities=" + mNetworkCapabilities + '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - InternalNetworkUpdateRequest that = (InternalNetworkUpdateRequest) o; - - return Objects.equals(that.getIpConfig(), mIpConfig) - && Objects.equals(that.getNetworkCapabilities(), mNetworkCapabilities); - } - - @Override - public int hashCode() { - return Objects.hash(mIpConfig, mNetworkCapabilities); - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - mIpConfig.writeToParcel(dest, flags); - mNetworkCapabilities.writeToParcel(dest, flags); - } - - @Override - public int describeContents() { - return 0; - } - - @NonNull - public static final Parcelable.Creator<InternalNetworkUpdateRequest> CREATOR = - new Parcelable.Creator<InternalNetworkUpdateRequest>() { - @Override - public InternalNetworkUpdateRequest[] newArray(int size) { - return new InternalNetworkUpdateRequest[size]; - } - - @Override - public InternalNetworkUpdateRequest createFromParcel(@NonNull Parcel source) { - return new InternalNetworkUpdateRequest(source); - } - }; -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java index a423783bc1ca..9cb0947b2370 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java +++ b/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java @@ -61,7 +61,7 @@ import java.util.Objects; * Internet Protocol</a> */ @SystemService(Context.IPSEC_SERVICE) -public final class IpSecManager { +public class IpSecManager { private static final String TAG = "IpSecManager"; /** diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java index 56faa52e82df..a48f94b66def 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java +++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java @@ -20,6 +20,7 @@ import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.NetworkTemplate.NETWORK_TYPE_ALL; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import android.annotation.IntDef; import android.annotation.NonNull; @@ -86,6 +87,7 @@ public class NetworkIdentity { final int mType; final int mRatType; + final int mSubId; final String mSubscriberId; final String mWifiNetworkKey; final boolean mRoaming; @@ -96,7 +98,7 @@ public class NetworkIdentity { /** @hide */ public NetworkIdentity( int type, int ratType, @Nullable String subscriberId, @Nullable String wifiNetworkKey, - boolean roaming, boolean metered, boolean defaultNetwork, int oemManaged) { + boolean roaming, boolean metered, boolean defaultNetwork, int oemManaged, int subId) { mType = type; mRatType = ratType; mSubscriberId = subscriberId; @@ -105,12 +107,13 @@ public class NetworkIdentity { mMetered = metered; mDefaultNetwork = defaultNetwork; mOemManaged = oemManaged; + mSubId = subId; } @Override public int hashCode() { return Objects.hash(mType, mRatType, mSubscriberId, mWifiNetworkKey, mRoaming, mMetered, - mDefaultNetwork, mOemManaged); + mDefaultNetwork, mOemManaged, mSubId); } @Override @@ -122,7 +125,8 @@ public class NetworkIdentity { && Objects.equals(mWifiNetworkKey, ident.mWifiNetworkKey) && mMetered == ident.mMetered && mDefaultNetwork == ident.mDefaultNetwork - && mOemManaged == ident.mOemManaged; + && mOemManaged == ident.mOemManaged + && mSubId == ident.mSubId; } return false; } @@ -150,6 +154,7 @@ public class NetworkIdentity { builder.append(", metered=").append(mMetered); builder.append(", defaultNetwork=").append(mDefaultNetwork); builder.append(", oemManaged=").append(getOemManagedNames(mOemManaged)); + builder.append(", subId=").append(mSubId); return builder.append("}").toString(); } @@ -184,14 +189,14 @@ public class NetworkIdentity { public void dumpDebug(ProtoOutputStream proto, long tag) { final long start = proto.start(tag); - proto.write(NetworkIdentityProto.TYPE, mType); + proto.write(NetworkIdentityProto.TYPE_FIELD_NUMBER, mType); // TODO: dump mRatType as well. - proto.write(NetworkIdentityProto.ROAMING, mRoaming); - proto.write(NetworkIdentityProto.METERED, mMetered); - proto.write(NetworkIdentityProto.DEFAULT_NETWORK, mDefaultNetwork); - proto.write(NetworkIdentityProto.OEM_MANAGED_NETWORK, mOemManaged); + proto.write(NetworkIdentityProto.ROAMING_FIELD_NUMBER, mRoaming); + proto.write(NetworkIdentityProto.METERED_FIELD_NUMBER, mMetered); + proto.write(NetworkIdentityProto.DEFAULT_NETWORK_FIELD_NUMBER, mDefaultNetwork); + proto.write(NetworkIdentityProto.OEM_MANAGED_NETWORK_FIELD_NUMBER, mOemManaged); proto.end(start); } @@ -256,6 +261,11 @@ public class NetworkIdentity { return mOemManaged; } + /** Get the SubId of this instance. */ + public int getSubId() { + return mSubId; + } + /** * Assemble a {@link NetworkIdentity} from the passed arguments. * @@ -276,7 +286,8 @@ public class NetworkIdentity { public static NetworkIdentity buildNetworkIdentity(Context context, @NonNull NetworkStateSnapshot snapshot, boolean defaultNetwork, int ratType) { final NetworkIdentity.Builder builder = new NetworkIdentity.Builder() - .setNetworkStateSnapshot(snapshot).setDefaultNetwork(defaultNetwork); + .setNetworkStateSnapshot(snapshot).setDefaultNetwork(defaultNetwork) + .setSubId(snapshot.getSubId()); if (snapshot.getLegacyType() == TYPE_MOBILE && ratType != NETWORK_TYPE_ALL) { builder.setRatType(ratType); } @@ -325,6 +336,9 @@ public class NetworkIdentity { if (res == 0) { res = Integer.compare(left.mOemManaged, right.mOemManaged); } + if (res == 0) { + res = Integer.compare(left.mSubId, right.mSubId); + } return res; } @@ -345,6 +359,7 @@ public class NetworkIdentity { private boolean mMetered; private boolean mDefaultNetwork; private int mOemManaged; + private int mSubId; /** * Creates a new Builder. @@ -359,6 +374,7 @@ public class NetworkIdentity { mMetered = false; mDefaultNetwork = false; mOemManaged = NetworkTemplate.OEM_MANAGED_NO; + mSubId = INVALID_SUBSCRIPTION_ID; } /** @@ -537,6 +553,19 @@ public class NetworkIdentity { return this; } + /** + * Set the Subscription Id. + * + * @param subId the Subscription Id of the network. Or INVALID_SUBSCRIPTION_ID if not + * applicable. + * @return this builder. + */ + @NonNull + public Builder setSubId(int subId) { + mSubId = subId; + return this; + } + private void ensureValidParameters() { // Assert non-mobile network cannot have a ratType. if (mType != TYPE_MOBILE && mRatType != NetworkTemplate.NETWORK_TYPE_ALL) { @@ -559,7 +588,7 @@ public class NetworkIdentity { public NetworkIdentity build() { ensureValidParameters(); return new NetworkIdentity(mType, mRatType, mSubscriberId, mWifiNetworkKey, - mRoaming, mMetered, mDefaultNetwork, mOemManaged); + mRoaming, mMetered, mDefaultNetwork, mOemManaged, mSubId); } } } diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentitySet.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentitySet.java index dfa347f6f12b..56461babfe49 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentitySet.java +++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentitySet.java @@ -17,6 +17,7 @@ package android.net; import static android.net.ConnectivityManager.TYPE_MOBILE; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import android.annotation.NonNull; import android.service.NetworkIdentitySetProto; @@ -42,6 +43,7 @@ public class NetworkIdentitySet extends HashSet<NetworkIdentity> { private static final int VERSION_ADD_METERED = 4; private static final int VERSION_ADD_DEFAULT_NETWORK = 5; private static final int VERSION_ADD_OEM_MANAGED_NETWORK = 6; + private static final int VERSION_ADD_SUB_ID = 7; /** * Construct a {@link NetworkIdentitySet} object. @@ -103,8 +105,15 @@ public class NetworkIdentitySet extends HashSet<NetworkIdentity> { oemNetCapabilities = NetworkIdentity.OEM_NONE; } + final int subId; + if (version >= VERSION_ADD_SUB_ID) { + subId = in.readInt(); + } else { + subId = INVALID_SUBSCRIPTION_ID; + } + add(new NetworkIdentity(type, ratType, subscriberId, networkId, roaming, metered, - defaultNetwork, oemNetCapabilities)); + defaultNetwork, oemNetCapabilities, subId)); } } @@ -113,7 +122,7 @@ public class NetworkIdentitySet extends HashSet<NetworkIdentity> { * @hide */ public void writeToStream(DataOutput out) throws IOException { - out.writeInt(VERSION_ADD_OEM_MANAGED_NETWORK); + out.writeInt(VERSION_ADD_SUB_ID); out.writeInt(size()); for (NetworkIdentity ident : this) { out.writeInt(ident.getType()); @@ -124,6 +133,7 @@ public class NetworkIdentitySet extends HashSet<NetworkIdentity> { out.writeBoolean(ident.isMetered()); out.writeBoolean(ident.isDefaultNetwork()); out.writeInt(ident.getOemManaged()); + out.writeInt(ident.getSubId()); } } @@ -212,7 +222,7 @@ public class NetworkIdentitySet extends HashSet<NetworkIdentity> { final long start = proto.start(tag); for (NetworkIdentity ident : this) { - ident.dumpDebug(proto, NetworkIdentitySetProto.IDENTITIES); + ident.dumpDebug(proto, NetworkIdentitySetProto.IDENTITIES_FIELD_NUMBER); } proto.end(start); diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.aidl b/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.aidl deleted file mode 100644 index cb602d7927ce..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2021, 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 android.net; - -parcelable NetworkStateSnapshot; diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.java index 39156343924d..d3f785a8f983 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.java +++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.java @@ -17,6 +17,8 @@ package android.net; import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import android.annotation.NonNull; import android.annotation.Nullable; @@ -98,12 +100,29 @@ public final class NetworkStateSnapshot implements Parcelable { return mLinkProperties; } - /** Get the Subscriber Id of the network associated with this snapshot. */ + /** + * Get the Subscriber Id of the network associated with this snapshot. + * @deprecated Please use #getSubId, which doesn't return personally identifiable + * information. + */ + @Deprecated @Nullable public String getSubscriberId() { return mSubscriberId; } + /** Get the subId of the network associated with this snapshot. */ + public int getSubId() { + if (mNetworkCapabilities.hasTransport(TRANSPORT_CELLULAR)) { + final NetworkSpecifier spec = mNetworkCapabilities.getNetworkSpecifier(); + if (spec instanceof TelephonyNetworkSpecifier) { + return ((TelephonyNetworkSpecifier) spec).getSubscriptionId(); + } + } + return INVALID_SUBSCRIPTION_ID; + } + + /** * Get the legacy type of the network associated with this snapshot. * @return the legacy network type. See {@code ConnectivityManager#TYPE_*}. diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java index 9175809d9c7c..f681ba1c3853 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java +++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java @@ -28,6 +28,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.Process; import android.os.SystemClock; +import android.text.TextUtils; import android.util.SparseBooleanArray; import com.android.internal.annotations.VisibleForTesting; @@ -500,7 +501,7 @@ public final class NetworkStats implements Parcelable, Iterable<NetworkStats.Ent && roaming == e.roaming && defaultNetwork == e.defaultNetwork && rxBytes == e.rxBytes && rxPackets == e.rxPackets && txBytes == e.txBytes && txPackets == e.txPackets - && operations == e.operations && iface.equals(e.iface); + && operations == e.operations && TextUtils.equals(iface, e.iface); } return false; } diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java index 735c44d5c87e..67d48f0000d5 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java +++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java @@ -732,19 +732,19 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W final long start = proto.start(tag); for (Key key : getSortedKeys()) { - final long startStats = proto.start(NetworkStatsCollectionProto.STATS); + final long startStats = proto.start(NetworkStatsCollectionProto.STATS_FIELD_NUMBER); // Key - final long startKey = proto.start(NetworkStatsCollectionStatsProto.KEY); - key.ident.dumpDebug(proto, NetworkStatsCollectionKeyProto.IDENTITY); - proto.write(NetworkStatsCollectionKeyProto.UID, key.uid); - proto.write(NetworkStatsCollectionKeyProto.SET, key.set); - proto.write(NetworkStatsCollectionKeyProto.TAG, key.tag); + final long startKey = proto.start(NetworkStatsCollectionStatsProto.KEY_FIELD_NUMBER); + key.ident.dumpDebug(proto, NetworkStatsCollectionKeyProto.IDENTITY_FIELD_NUMBER); + proto.write(NetworkStatsCollectionKeyProto.UID_FIELD_NUMBER, key.uid); + proto.write(NetworkStatsCollectionKeyProto.SET_FIELD_NUMBER, key.set); + proto.write(NetworkStatsCollectionKeyProto.TAG_FIELD_NUMBER, key.tag); proto.end(startKey); // Value final NetworkStatsHistory history = mStats.get(key); - history.dumpDebug(proto, NetworkStatsCollectionStatsProto.HISTORY); + history.dumpDebug(proto, NetworkStatsCollectionStatsProto.HISTORY_FIELD_NUMBER); proto.end(startStats); } diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java index 78c137073aaa..822a16e0bb41 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java +++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java @@ -915,17 +915,18 @@ public final class NetworkStatsHistory implements Parcelable { public void dumpDebug(ProtoOutputStream proto, long tag) { final long start = proto.start(tag); - proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS, bucketDuration); + proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS_FIELD_NUMBER, bucketDuration); for (int i = 0; i < bucketCount; i++) { - final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS); - - proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS, bucketStart[i]); - dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_BYTES, rxBytes, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_PACKETS, rxPackets, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_BYTES, txBytes, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_PACKETS, txPackets, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.OPERATIONS, operations, i); + final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS_FIELD_NUMBER); + + proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS_FIELD_NUMBER, + bucketStart[i]); + dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_BYTES_FIELD_NUMBER, rxBytes, i); + dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_PACKETS_FIELD_NUMBER, rxPackets, i); + dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_BYTES_FIELD_NUMBER, txBytes, i); + dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_PACKETS_FIELD_NUMBER, txPackets, i); + dumpDebug(proto, NetworkStatsHistoryBucketProto.OPERATIONS_FIELD_NUMBER, operations, i); proto.end(startBucket); } diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java index 9b58b016bbf3..7b5afd720016 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java +++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java @@ -79,7 +79,8 @@ public final class NetworkTemplate implements Parcelable { MATCH_WIFI, MATCH_ETHERNET, MATCH_BLUETOOTH, - MATCH_CARRIER + MATCH_PROXY, + MATCH_CARRIER, }) public @interface TemplateMatchRule{} @@ -104,9 +105,8 @@ public final class NetworkTemplate implements Parcelable { /** Match rule to match bluetooth networks. */ public static final int MATCH_BLUETOOTH = 8; /** - * Match rule to match networks with {@link Connectivity#TYPE_PROXY} as the legacy network type. - * - * @hide + * Match rule to match networks with {@link ConnectivityManager#TYPE_PROXY} as the legacy + * network type. */ public static final int MATCH_PROXY = 9; /** diff --git a/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java b/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java index c2f0cdfb048c..bc836d857e3e 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java +++ b/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java @@ -31,12 +31,9 @@ import android.media.MediaPlayer; import android.os.Binder; import android.os.Build; import android.os.RemoteException; +import android.os.StrictMode; import android.util.Log; -import com.android.server.NetworkManagementSocketTagger; - -import dalvik.system.SocketTagger; - import java.io.FileDescriptor; import java.io.IOException; import java.net.DatagramSocket; @@ -56,6 +53,10 @@ import java.net.SocketException; * use {@link NetworkStatsManager} instead. */ public class TrafficStats { + static { + System.loadLibrary("framework-connectivity-tiramisu-jni"); + } + private static final String TAG = TrafficStats.class.getSimpleName(); /** * The return value to indicate that the device does not support the statistic. @@ -232,9 +233,68 @@ public class TrafficStats { */ @SystemApi(client = MODULE_LIBRARIES) public static void attachSocketTagger() { - NetworkManagementSocketTagger.install(); + dalvik.system.SocketTagger.set(new SocketTagger()); + } + + private static class SocketTagger extends dalvik.system.SocketTagger { + + // TODO: set to false + private static final boolean LOGD = true; + + SocketTagger() { + } + + @Override + public void tag(FileDescriptor fd) throws SocketException { + final UidTag tagInfo = sThreadUidTag.get(); + if (LOGD) { + Log.d(TAG, "tagSocket(" + fd.getInt$() + ") with statsTag=0x" + + Integer.toHexString(tagInfo.tag) + ", statsUid=" + tagInfo.uid); + } + if (tagInfo.tag == -1) { + StrictMode.noteUntaggedSocket(); + } + + if (tagInfo.tag == -1 && tagInfo.uid == -1) return; + final int errno = native_tagSocketFd(fd, tagInfo.tag, tagInfo.uid); + if (errno < 0) { + Log.i(TAG, "tagSocketFd(" + fd.getInt$() + ", " + + tagInfo.tag + ", " + + tagInfo.uid + ") failed with errno" + errno); + } + } + + @Override + public void untag(FileDescriptor fd) throws SocketException { + if (LOGD) { + Log.i(TAG, "untagSocket(" + fd.getInt$() + ")"); + } + + final UidTag tagInfo = sThreadUidTag.get(); + if (tagInfo.tag == -1 && tagInfo.uid == -1) return; + + final int errno = native_untagSocketFd(fd); + if (errno < 0) { + Log.w(TAG, "untagSocket(" + fd.getInt$() + ") failed with errno " + errno); + } + } + } + + private static native int native_tagSocketFd(FileDescriptor fd, int tag, int uid); + private static native int native_untagSocketFd(FileDescriptor fd); + + private static class UidTag { + public int tag = -1; + public int uid = -1; } + private static ThreadLocal<UidTag> sThreadUidTag = new ThreadLocal<UidTag>() { + @Override + protected UidTag initialValue() { + return new UidTag(); + } + }; + /** * Set active tag to use when accounting {@link Socket} traffic originating * from the current thread. Only one active tag per thread is supported. @@ -249,7 +309,7 @@ public class TrafficStats { * @see #clearThreadStatsTag() */ public static void setThreadStatsTag(int tag) { - NetworkManagementSocketTagger.setThreadSocketStatsTag(tag); + getAndSetThreadStatsTag(tag); } /** @@ -267,7 +327,9 @@ public class TrafficStats { * restore any existing values after a nested operation is finished */ public static int getAndSetThreadStatsTag(int tag) { - return NetworkManagementSocketTagger.setThreadSocketStatsTag(tag); + final int old = sThreadUidTag.get().tag; + sThreadUidTag.get().tag = tag; + return old; } /** @@ -327,7 +389,7 @@ public class TrafficStats { * @see #setThreadStatsTag(int) */ public static int getThreadStatsTag() { - return NetworkManagementSocketTagger.getThreadSocketStatsTag(); + return sThreadUidTag.get().tag; } /** @@ -337,7 +399,7 @@ public class TrafficStats { * @see #setThreadStatsTag(int) */ public static void clearThreadStatsTag() { - NetworkManagementSocketTagger.setThreadSocketStatsTag(-1); + sThreadUidTag.get().tag = -1; } /** @@ -357,7 +419,7 @@ public class TrafficStats { */ @SuppressLint("RequiresPermission") public static void setThreadStatsUid(int uid) { - NetworkManagementSocketTagger.setThreadSocketStatsUid(uid); + sThreadUidTag.get().uid = uid; } /** @@ -368,7 +430,7 @@ public class TrafficStats { * @see #setThreadStatsUid(int) */ public static int getThreadStatsUid() { - return NetworkManagementSocketTagger.getThreadSocketStatsUid(); + return sThreadUidTag.get().uid; } /** @@ -395,7 +457,7 @@ public class TrafficStats { */ @SuppressLint("RequiresPermission") public static void clearThreadStatsUid() { - NetworkManagementSocketTagger.setThreadSocketStatsUid(-1); + setThreadStatsUid(-1); } /** diff --git a/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdManager.java b/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdManager.java index 0f21e55b9f27..512fbcee9330 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdManager.java +++ b/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdManager.java @@ -16,6 +16,9 @@ package android.net.nsd; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemService; @@ -23,15 +26,22 @@ import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.content.Context; +import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; +import android.net.Network; +import android.net.NetworkRequest; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.ArraySet; import android.util.Log; import android.util.SparseArray; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import java.util.Objects; @@ -278,9 +288,180 @@ public final class NsdManager { private final SparseArray mListenerMap = new SparseArray(); private final SparseArray<NsdServiceInfo> mServiceMap = new SparseArray<>(); private final Object mMapLock = new Object(); + // Map of listener key sent by client -> per-network discovery tracker + @GuardedBy("mPerNetworkDiscoveryMap") + private final ArrayMap<Integer, PerNetworkDiscoveryTracker> + mPerNetworkDiscoveryMap = new ArrayMap<>(); private final ServiceHandler mHandler; + private class PerNetworkDiscoveryTracker { + final String mServiceType; + final int mProtocolType; + final DiscoveryListener mBaseListener; + final ArrayMap<Network, DelegatingDiscoveryListener> mPerNetworkListeners = + new ArrayMap<>(); + + final NetworkCallback mNetworkCb = new NetworkCallback() { + @Override + public void onAvailable(@NonNull Network network) { + final DelegatingDiscoveryListener wrappedListener = new DelegatingDiscoveryListener( + network, mBaseListener); + mPerNetworkListeners.put(network, wrappedListener); + discoverServices(mServiceType, mProtocolType, network, wrappedListener); + } + + @Override + public void onLost(@NonNull Network network) { + final DelegatingDiscoveryListener listener = mPerNetworkListeners.get(network); + if (listener == null) return; + listener.notifyAllServicesLost(); + // Listener will be removed from map in discovery stopped callback + stopServiceDiscovery(listener); + } + }; + + // Accessed from mHandler + private boolean mStopRequested; + + public void start(@NonNull NetworkRequest request) { + final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class); + cm.registerNetworkCallback(request, mNetworkCb, mHandler); + mHandler.post(() -> mBaseListener.onDiscoveryStarted(mServiceType)); + } + + /** + * Stop discovery on all networks tracked by this class. + * + * This will request all underlying listeners to stop, and the last one to stop will call + * onDiscoveryStopped or onStopDiscoveryFailed. + * + * Must be called on the handler thread. + */ + public void requestStop() { + mHandler.post(() -> { + mStopRequested = true; + final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class); + cm.unregisterNetworkCallback(mNetworkCb); + if (mPerNetworkListeners.size() == 0) { + mBaseListener.onDiscoveryStopped(mServiceType); + return; + } + for (int i = 0; i < mPerNetworkListeners.size(); i++) { + final DelegatingDiscoveryListener listener = mPerNetworkListeners.valueAt(i); + stopServiceDiscovery(listener); + } + }); + } + + private PerNetworkDiscoveryTracker(String serviceType, int protocolType, + DiscoveryListener baseListener) { + mServiceType = serviceType; + mProtocolType = protocolType; + mBaseListener = baseListener; + } + + /** + * Subset of NsdServiceInfo that is tracked to generate service lost notifications when a + * network is lost. + * + * Service lost notifications only contain service name, type and network, so only track + * that information (Network is known from the listener). This also implements + * equals/hashCode for usage in maps. + */ + private class TrackedNsdInfo { + private final String mServiceName; + private final String mServiceType; + TrackedNsdInfo(NsdServiceInfo info) { + mServiceName = info.getServiceName(); + mServiceType = info.getServiceType(); + } + + @Override + public int hashCode() { + return Objects.hash(mServiceName, mServiceType); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof TrackedNsdInfo)) return false; + final TrackedNsdInfo other = (TrackedNsdInfo) obj; + return Objects.equals(mServiceName, other.mServiceName) + && Objects.equals(mServiceType, other.mServiceType); + } + } + + private class DelegatingDiscoveryListener implements DiscoveryListener { + private final Network mNetwork; + private final DiscoveryListener mWrapped; + private final ArraySet<TrackedNsdInfo> mFoundInfo = new ArraySet<>(); + + private DelegatingDiscoveryListener(Network network, DiscoveryListener listener) { + mNetwork = network; + mWrapped = listener; + } + + void notifyAllServicesLost() { + for (int i = 0; i < mFoundInfo.size(); i++) { + final TrackedNsdInfo trackedInfo = mFoundInfo.valueAt(i); + final NsdServiceInfo serviceInfo = new NsdServiceInfo( + trackedInfo.mServiceName, trackedInfo.mServiceType); + serviceInfo.setNetwork(mNetwork); + mWrapped.onServiceLost(serviceInfo); + } + } + + @Override + public void onStartDiscoveryFailed(String serviceType, int errorCode) { + // The delegated listener is used when NsdManager takes care of starting/stopping + // discovery on multiple networks. Failure to start on one network is not a global + // failure to be reported up, as other networks may succeed: just log. + Log.e(TAG, "Failed to start discovery for " + serviceType + " on " + mNetwork + + " with code " + errorCode); + mPerNetworkListeners.remove(mNetwork); + } + + @Override + public void onDiscoveryStarted(String serviceType) { + // Wrapped listener was called upon registration, it is not called for discovery + // on each network + } + + @Override + public void onStopDiscoveryFailed(String serviceType, int errorCode) { + Log.e(TAG, "Failed to stop discovery for " + serviceType + " on " + mNetwork + + " with code " + errorCode); + mPerNetworkListeners.remove(mNetwork); + if (mStopRequested && mPerNetworkListeners.size() == 0) { + // Do not report onStopDiscoveryFailed when some underlying listeners failed: + // this does not mean that all listeners did, and onStopDiscoveryFailed is not + // actionable anyway. Just report that discovery stopped. + mWrapped.onDiscoveryStopped(serviceType); + } + } + + @Override + public void onDiscoveryStopped(String serviceType) { + mPerNetworkListeners.remove(mNetwork); + if (mStopRequested && mPerNetworkListeners.size() == 0) { + mWrapped.onDiscoveryStopped(serviceType); + } + } + + @Override + public void onServiceFound(NsdServiceInfo serviceInfo) { + mFoundInfo.add(new TrackedNsdInfo(serviceInfo)); + mWrapped.onServiceFound(serviceInfo); + } + + @Override + public void onServiceLost(NsdServiceInfo serviceInfo) { + mFoundInfo.remove(new TrackedNsdInfo(serviceInfo)); + mWrapped.onServiceLost(serviceInfo); + } + } + } + /** * Create a new Nsd instance. Applications use * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve @@ -634,6 +815,14 @@ public final class NsdManager { } /** + * Same as {@link #discoverServices(String, int, Network, DiscoveryListener)} with a null + * {@link Network}. + */ + public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) { + discoverServices(serviceType, protocolType, (Network) null, listener); + } + + /** * Initiate service discovery to browse for instances of a service type. Service discovery * consumes network bandwidth and will continue until the application calls * {@link #stopServiceDiscovery}. @@ -657,11 +846,13 @@ public final class NsdManager { * @param serviceType The service type being discovered. Examples include "_http._tcp" for * http services or "_ipp._tcp" for printers * @param protocolType The service discovery protocol + * @param network Network to discover services on, or null to discover on all available networks * @param listener The listener notifies of a successful discovery and is used * to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}. * Cannot be null. Cannot be in use for an active service discovery. */ - public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) { + public void discoverServices(@NonNull String serviceType, int protocolType, + @Nullable Network network, @NonNull DiscoveryListener listener) { if (TextUtils.isEmpty(serviceType)) { throw new IllegalArgumentException("Service type cannot be empty"); } @@ -669,6 +860,7 @@ public final class NsdManager { NsdServiceInfo s = new NsdServiceInfo(); s.setServiceType(serviceType); + s.setNetwork(network); int key = putListener(listener, s); try { @@ -679,6 +871,67 @@ public final class NsdManager { } /** + * Initiate service discovery to browse for instances of a service type. Service discovery + * consumes network bandwidth and will continue until the application calls + * {@link #stopServiceDiscovery}. + * + * <p> The function call immediately returns after sending a request to start service + * discovery to the framework. The application is notified of a success to initiate + * discovery through the callback {@link DiscoveryListener#onDiscoveryStarted} or a failure + * through {@link DiscoveryListener#onStartDiscoveryFailed}. + * + * <p> Upon successful start, application is notified when a service is found with + * {@link DiscoveryListener#onServiceFound} or when a service is lost with + * {@link DiscoveryListener#onServiceLost}. + * + * <p> Upon failure to start, service discovery is not active and application does + * not need to invoke {@link #stopServiceDiscovery} + * + * <p> The application should call {@link #stopServiceDiscovery} when discovery of this + * service type is no longer required, and/or whenever the application is paused or + * stopped. + * + * <p> During discovery, new networks may connect or existing networks may disconnect - for + * example if wifi is reconnected. When a service was found on a network that disconnects, + * {@link DiscoveryListener#onServiceLost} will be called. If a new network connects that + * matches the {@link NetworkRequest}, {@link DiscoveryListener#onServiceFound} will be called + * for services found on that network. Applications that do not want to track networks + * themselves are encouraged to use this method instead of other overloads of + * {@code discoverServices}, as they will receive proper notifications when a service becomes + * available or unavailable due to network changes. + * + * @param serviceType The service type being discovered. Examples include "_http._tcp" for + * http services or "_ipp._tcp" for printers + * @param protocolType The service discovery protocol + * @param networkRequest Request specifying networks that should be considered when discovering + * @param listener The listener notifies of a successful discovery and is used + * to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}. + * Cannot be null. Cannot be in use for an active service discovery. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + public void discoverServices(@NonNull String serviceType, int protocolType, + @NonNull NetworkRequest networkRequest, @NonNull DiscoveryListener listener) { + if (TextUtils.isEmpty(serviceType)) { + throw new IllegalArgumentException("Service type cannot be empty"); + } + Objects.requireNonNull(networkRequest, "NetworkRequest cannot be null"); + checkProtocol(protocolType); + + NsdServiceInfo s = new NsdServiceInfo(); + s.setServiceType(serviceType); + + final int baseListenerKey = putListener(listener, s); + + final PerNetworkDiscoveryTracker discoveryInfo = new PerNetworkDiscoveryTracker( + serviceType, protocolType, listener); + + synchronized (mPerNetworkDiscoveryMap) { + mPerNetworkDiscoveryMap.put(baseListenerKey, discoveryInfo); + discoveryInfo.start(networkRequest); + } + } + + /** * Stop service discovery initiated with {@link #discoverServices}. An active service * discovery is notified to the application with {@link DiscoveryListener#onDiscoveryStarted} * and it stays active until the application invokes a stop service discovery. A successful @@ -696,6 +949,14 @@ public final class NsdManager { */ public void stopServiceDiscovery(DiscoveryListener listener) { int id = getListenerKey(listener); + // If this is a PerNetworkDiscovery request, handle it as such + synchronized (mPerNetworkDiscoveryMap) { + final PerNetworkDiscoveryTracker info = mPerNetworkDiscoveryMap.get(id); + if (info != null) { + info.requestStop(); + return; + } + } try { mService.stopDiscovery(id); } catch (RemoteException e) { diff --git a/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdServiceInfo.java b/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdServiceInfo.java index 0946499f164f..8506db1fbe01 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdServiceInfo.java +++ b/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdServiceInfo.java @@ -17,7 +17,9 @@ package android.net.nsd; import android.annotation.NonNull; +import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; +import android.net.Network; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; @@ -49,6 +51,9 @@ public final class NsdServiceInfo implements Parcelable { private int mPort; + @Nullable + private Network mNetwork; + public NsdServiceInfo() { } @@ -307,18 +312,37 @@ public final class NsdServiceInfo implements Parcelable { return txtRecord; } - public String toString() { - StringBuffer sb = new StringBuffer(); + /** + * Get the network where the service can be found. + * + * This is never null if this {@link NsdServiceInfo} was obtained from + * {@link NsdManager#discoverServices} or {@link NsdManager#resolveService}. + */ + @Nullable + public Network getNetwork() { + return mNetwork; + } + /** + * Set the network where the service can be found. + * @param network The network, or null to search for, or to announce, the service on all + * connected networks. + */ + public void setNetwork(@Nullable Network network) { + mNetwork = network; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); sb.append("name: ").append(mServiceName) .append(", type: ").append(mServiceType) .append(", host: ").append(mHost) - .append(", port: ").append(mPort); + .append(", port: ").append(mPort) + .append(", network: ").append(mNetwork); byte[] txtRecord = getTxtRecord(); - if (txtRecord != null) { - sb.append(", txtRecord: ").append(new String(txtRecord, StandardCharsets.UTF_8)); - } + sb.append(", txtRecord: ").append(new String(txtRecord, StandardCharsets.UTF_8)); return sb.toString(); } @@ -352,6 +376,8 @@ public final class NsdServiceInfo implements Parcelable { } dest.writeString(key); } + + dest.writeParcelable(mNetwork, 0); } /** Implement the Parcelable interface */ @@ -381,6 +407,7 @@ public final class NsdServiceInfo implements Parcelable { } info.mTxtRecord.put(in.readString(), valueArray); } + info.mNetwork = in.readParcelable(null, Network.class); return info; } diff --git a/packages/ConnectivityT/framework-t/src/com/android/server/NetworkManagementSocketTagger.java b/packages/ConnectivityT/framework-t/src/com/android/server/NetworkManagementSocketTagger.java deleted file mode 100644 index 8bb12a6defe5..000000000000 --- a/packages/ConnectivityT/framework-t/src/com/android/server/NetworkManagementSocketTagger.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (C) 2011 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 com.android.server; - -import android.os.StrictMode; -import android.util.Log; - -import dalvik.system.SocketTagger; - -import java.io.FileDescriptor; -import java.net.SocketException; - -/** - * Assigns tags to sockets for traffic stats. - * @hide - */ -public final class NetworkManagementSocketTagger extends SocketTagger { - private static final String TAG = "NetworkManagementSocketTagger"; - private static final boolean LOGD = false; - - private static ThreadLocal<SocketTags> threadSocketTags = new ThreadLocal<SocketTags>() { - @Override - protected SocketTags initialValue() { - return new SocketTags(); - } - }; - - public static void install() { - SocketTagger.set(new NetworkManagementSocketTagger()); - } - - public static int setThreadSocketStatsTag(int tag) { - final int old = threadSocketTags.get().statsTag; - threadSocketTags.get().statsTag = tag; - return old; - } - - public static int getThreadSocketStatsTag() { - return threadSocketTags.get().statsTag; - } - - public static int setThreadSocketStatsUid(int uid) { - final int old = threadSocketTags.get().statsUid; - threadSocketTags.get().statsUid = uid; - return old; - } - - public static int getThreadSocketStatsUid() { - return threadSocketTags.get().statsUid; - } - - @Override - public void tag(FileDescriptor fd) throws SocketException { - final SocketTags options = threadSocketTags.get(); - if (LOGD) { - Log.d(TAG, "tagSocket(" + fd.getInt$() + ") with statsTag=0x" - + Integer.toHexString(options.statsTag) + ", statsUid=" + options.statsUid); - } - if (options.statsTag == -1) { - StrictMode.noteUntaggedSocket(); - } - // TODO: skip tagging when options would be no-op - tagSocketFd(fd, options.statsTag, options.statsUid); - } - - private void tagSocketFd(FileDescriptor fd, int tag, int uid) { - if (tag == -1 && uid == -1) return; - - final int errno = native_tagSocketFd(fd, tag, uid); - if (errno < 0) { - Log.i(TAG, "tagSocketFd(" + fd.getInt$() + ", " - + tag + ", " - + uid + ") failed with errno" + errno); - } - } - - @Override - public void untag(FileDescriptor fd) throws SocketException { - if (LOGD) { - Log.i(TAG, "untagSocket(" + fd.getInt$() + ")"); - } - unTagSocketFd(fd); - } - - private void unTagSocketFd(FileDescriptor fd) { - final SocketTags options = threadSocketTags.get(); - if (options.statsTag == -1 && options.statsUid == -1) return; - - final int errno = native_untagSocketFd(fd); - if (errno < 0) { - Log.w(TAG, "untagSocket(" + fd.getInt$() + ") failed with errno " + errno); - } - } - - public static class SocketTags { - public int statsTag = -1; - public int statsUid = -1; - } - - /** - * Convert {@code /proc/} tag format to {@link Integer}. Assumes incoming - * format like {@code 0x7fffffff00000000}. - */ - public static int kernelToTag(String string) { - int length = string.length(); - if (length > 10) { - return Long.decode(string.substring(0, length - 8)).intValue(); - } else { - return 0; - } - } - - private static native int native_tagSocketFd(FileDescriptor fd, int tag, int uid); - private static native int native_untagSocketFd(FileDescriptor fd); -} diff --git a/packages/ConnectivityT/service/Android.bp b/packages/ConnectivityT/service/Android.bp index 24bc91d91ef7..5100e7c5b9a4 100644 --- a/packages/ConnectivityT/service/Android.bp +++ b/packages/ConnectivityT/service/Android.bp @@ -28,6 +28,11 @@ filegroup { "src/com/android/server/net/NetworkStats*.java", "src/com/android/server/net/BpfInterfaceMapUpdater.java", "src/com/android/server/net/InterfaceMapValue.java", + "src/com/android/server/net/CookieTagMapKey.java", + "src/com/android/server/net/CookieTagMapValue.java", + "src/com/android/server/net/StatsMapKey.java", + "src/com/android/server/net/StatsMapValue.java", + "src/com/android/server/net/UidStatsMapKey.java", ], path: "src", visibility: [ @@ -35,6 +40,30 @@ filegroup { ], } +// For test code only. +filegroup { + name: "lib_networkStatsFactory_native", + srcs: [ + "jni/com_android_server_net_NetworkStatsFactory.cpp", + ], + path: "jni", + visibility: [ + "//packages/modules/Connectivity:__subpackages__", + ], +} + +filegroup { + name: "services.connectivity-netstats-jni-sources", + srcs: [ + "jni/com_android_server_net_NetworkStatsFactory.cpp", + "jni/com_android_server_net_NetworkStatsService.cpp", + ], + path: "jni", + visibility: [ + "//packages/modules/Connectivity:__subpackages__", + ], +} + // Nsd related libraries. filegroup { @@ -83,8 +112,6 @@ filegroup { name: "services.connectivity-tiramisu-sources", srcs: [ ":services.connectivity-ethernet-sources", - ":services.connectivity-ipsec-sources", - ":services.connectivity-netstats-sources", ], path: "src", visibility: ["//frameworks/base/services/core"], @@ -93,6 +120,8 @@ filegroup { filegroup { name: "services.connectivity-tiramisu-updatable-sources", srcs: [ + ":services.connectivity-ipsec-sources", + ":services.connectivity-netstats-sources", ":services.connectivity-nsd-sources", ], path: "src", diff --git a/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp b/packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsFactory.cpp index 8b6526ff49f0..8b6526ff49f0 100644 --- a/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp +++ b/packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsFactory.cpp diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsService.cpp index f8a81682bdcf..39cbaf716fc0 100644 --- a/services/core/jni/com_android_server_net_NetworkStatsService.cpp +++ b/packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsService.cpp @@ -102,15 +102,10 @@ static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type) { } } -static int deleteTagData(JNIEnv* /* env */, jclass /* clazz */, jint uid) { - return qtaguid_deleteTagData(0, uid); -} - static const JNINativeMethod gMethods[] = { {"nativeGetTotalStat", "(I)J", (void*)getTotalStat}, {"nativeGetIfaceStat", "(Ljava/lang/String;I)J", (void*)getIfaceStat}, {"nativeGetUidStat", "(II)J", (void*)getUidStat}, - {"nativeDeleteTagData", "(I)I", (void*)deleteTagData}, }; int register_android_server_net_NetworkStatsService(JNIEnv* env) { diff --git a/packages/ConnectivityT/service/src/com/android/server/IpSecService.java b/packages/ConnectivityT/service/src/com/android/server/IpSecService.java index 179d9459fd84..4bc40eae4404 100644 --- a/packages/ConnectivityT/service/src/com/android/server/IpSecService.java +++ b/packages/ConnectivityT/service/src/com/android/server/IpSecService.java @@ -1008,16 +1008,10 @@ public class IpSecService extends IIpSecService.Stub { * * @param context Binder context for this service */ - private IpSecService(Context context) { + public IpSecService(Context context) { this(context, new Dependencies()); } - static IpSecService create(Context context) - throws InterruptedException { - final IpSecService service = new IpSecService(context); - return service; - } - @NonNull private AppOpsManager getAppOpsManager() { AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); @@ -1054,26 +1048,6 @@ public class IpSecService extends IIpSecService.Stub { } } - /** Called by system server when system is ready. */ - public void systemReady() { - if (isNetdAlive()) { - Log.d(TAG, "IpSecService is ready"); - } else { - Log.wtf(TAG, "IpSecService not ready: failed to connect to NetD Native Service!"); - } - } - - synchronized boolean isNetdAlive() { - try { - if (mNetd == null) { - return false; - } - return mNetd.isAlive(); - } catch (RemoteException re) { - return false; - } - } - /** * Checks that the provided InetAddress is valid for use in an IPsec SA. The address must not be * a wildcard address and must be in a numeric form such as 1.2.3.4 or 2001::1. @@ -1896,7 +1870,6 @@ public class IpSecService extends IIpSecService.Stub { mContext.enforceCallingOrSelfPermission(DUMP, TAG); pw.println("IpSecService dump:"); - pw.println("NetdNativeService Connection: " + (isNetdAlive() ? "alive" : "dead")); pw.println(); pw.println("mUserResourceTracker:"); diff --git a/packages/ConnectivityT/service/src/com/android/server/NsdService.java b/packages/ConnectivityT/service/src/com/android/server/NsdService.java index 497107dbf989..ddf6d2c4ab15 100644 --- a/packages/ConnectivityT/service/src/com/android/server/NsdService.java +++ b/packages/ConnectivityT/service/src/com/android/server/NsdService.java @@ -19,6 +19,9 @@ package com.android.server; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; +import android.net.ConnectivityManager; +import android.net.LinkProperties; +import android.net.Network; import android.net.nsd.INsdManager; import android.net.nsd.INsdManagerCallback; import android.net.nsd.INsdServiceConnector; @@ -44,6 +47,9 @@ import com.android.net.module.util.DnsSdTxtRecord; import java.io.FileDescriptor; import java.io.PrintWriter; import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.net.UnknownHostException; import java.util.Arrays; import java.util.HashMap; import java.util.concurrent.CountDownLatch; @@ -60,6 +66,7 @@ public class NsdService extends INsdManager.Stub { private static final boolean DBG = true; private static final long CLEANUP_DELAY_MS = 10000; + private static final int IFACE_IDX_ANY = 0; private final Context mContext; private final NsdStateMachine mNsdStateMachine; @@ -297,7 +304,7 @@ public class NsdService extends INsdManager.Stub { maybeStartDaemon(); id = getUniqueId(); - if (discoverServices(id, args.serviceInfo.getServiceType())) { + if (discoverServices(id, args.serviceInfo)) { if (DBG) { Log.d(TAG, "Discover " + msg.arg2 + " " + id + args.serviceInfo.getServiceType()); @@ -430,13 +437,38 @@ public class NsdService extends INsdManager.Stub { } switch (code) { case NativeResponseCode.SERVICE_FOUND: - /* NNN uniqueId serviceName regType domain */ + /* NNN uniqueId serviceName regType domain interfaceIdx netId */ servInfo = new NsdServiceInfo(cooked[2], cooked[3]); + final int foundNetId; + try { + foundNetId = Integer.parseInt(cooked[6]); + } catch (NumberFormatException e) { + Log.wtf(TAG, "Invalid network received from mdnsd: " + cooked[6]); + break; + } + if (foundNetId == 0L) { + // Ignore services that do not have a Network: they are not usable + // by apps, as they would need privileged permissions to use + // interfaces that do not have an associated Network. + break; + } + servInfo.setNetwork(new Network(foundNetId)); clientInfo.onServiceFound(clientId, servInfo); break; case NativeResponseCode.SERVICE_LOST: - /* NNN uniqueId serviceName regType domain */ + /* NNN uniqueId serviceName regType domain interfaceIdx netId */ + final int lostNetId; + try { + lostNetId = Integer.parseInt(cooked[6]); + } catch (NumberFormatException e) { + Log.wtf(TAG, "Invalid network received from mdnsd: " + cooked[6]); + break; + } servInfo = new NsdServiceInfo(cooked[2], cooked[3]); + // The network could be null if it was torn down when the service is lost + // TODO: avoid returning null in that case, possibly by remembering found + // services on the same interface index and their network at the time + servInfo.setNetwork(lostNetId == 0 ? null : new Network(lostNetId)); clientInfo.onServiceLost(clientId, servInfo); break; case NativeResponseCode.SERVICE_DISCOVERY_FAILED: @@ -461,7 +493,7 @@ public class NsdService extends INsdManager.Stub { /* NNN regId errorCode */ break; case NativeResponseCode.SERVICE_RESOLVED: - /* NNN resolveId fullName hostName port txtlen txtdata */ + /* NNN resolveId fullName hostName port txtlen txtdata interfaceIdx */ int index = 0; while (index < cooked[2].length() && cooked[2].charAt(index) != '.') { if (cooked[2].charAt(index) == '\\') { @@ -473,6 +505,7 @@ public class NsdService extends INsdManager.Stub { Log.e(TAG, "Invalid service found " + raw); break; } + String name = cooked[2].substring(0, index); String rest = cooked[2].substring(index); String type = rest.replace(".local.", ""); @@ -483,12 +516,13 @@ public class NsdService extends INsdManager.Stub { clientInfo.mResolvedService.setServiceType(type); clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4])); clientInfo.mResolvedService.setTxtRecords(cooked[6]); + // Network will be added after SERVICE_GET_ADDR_SUCCESS stopResolveService(id); removeRequestMap(clientId, id, clientInfo); int id2 = getUniqueId(); - if (getAddrInfo(id2, cooked[3])) { + if (getAddrInfo(id2, cooked[3], cooked[7] /* interfaceIdx */)) { storeRequestMap(clientId, id2, clientInfo, NsdManager.RESOLVE_SERVICE); } else { clientInfo.onResolveServiceFailed( @@ -513,12 +547,31 @@ public class NsdService extends INsdManager.Stub { clientId, NsdManager.FAILURE_INTERNAL_ERROR); break; case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS: - /* NNN resolveId hostname ttl addr */ + /* NNN resolveId hostname ttl addr interfaceIdx netId */ + Network network = null; + try { + final int netId = Integer.parseInt(cooked[6]); + network = netId == 0L ? null : new Network(netId); + } catch (NumberFormatException e) { + Log.wtf(TAG, "Invalid network in GET_ADDR_SUCCESS: " + cooked[6], e); + } + + InetAddress serviceHost = null; try { - clientInfo.mResolvedService.setHost(InetAddress.getByName(cooked[4])); + serviceHost = InetAddress.getByName(cooked[4]); + } catch (UnknownHostException e) { + Log.wtf(TAG, "Invalid host in GET_ADDR_SUCCESS", e); + } + + // If the resolved service is on an interface without a network, consider it + // as a failure: it would not be usable by apps as they would need + // privileged permissions. + if (network != null && serviceHost != null) { + clientInfo.mResolvedService.setHost(serviceHost); + clientInfo.mResolvedService.setNetwork(network); clientInfo.onResolveServiceSucceeded( clientId, clientInfo.mResolvedService); - } catch (java.net.UnknownHostException e) { + } else { clientInfo.onResolveServiceFailed( clientId, NsdManager.FAILURE_INTERNAL_ERROR); } @@ -815,8 +868,15 @@ public class NsdService extends INsdManager.Stub { return mDaemon.execute("update", regId, t.size(), t.getRawData()); } - private boolean discoverServices(int discoveryId, String serviceType) { - return mDaemon.execute("discover", discoveryId, serviceType); + private boolean discoverServices(int discoveryId, NsdServiceInfo serviceInfo) { + final Network network = serviceInfo.getNetwork(); + final int discoverInterface = getNetworkInterfaceIndex(network); + if (network != null && discoverInterface == IFACE_IDX_ANY) { + Log.e(TAG, "Interface to discover service on not found"); + return false; + } + return mDaemon.execute("discover", discoveryId, serviceInfo.getServiceType(), + discoverInterface); } private boolean stopServiceDiscovery(int discoveryId) { @@ -824,17 +884,61 @@ public class NsdService extends INsdManager.Stub { } private boolean resolveService(int resolveId, NsdServiceInfo service) { - String name = service.getServiceName(); - String type = service.getServiceType(); - return mDaemon.execute("resolve", resolveId, name, type, "local."); + final String name = service.getServiceName(); + final String type = service.getServiceType(); + final Network network = service.getNetwork(); + final int resolveInterface = getNetworkInterfaceIndex(network); + if (network != null && resolveInterface == IFACE_IDX_ANY) { + Log.e(TAG, "Interface to resolve service on not found"); + return false; + } + return mDaemon.execute("resolve", resolveId, name, type, "local.", resolveInterface); + } + + /** + * Guess the interface to use to resolve or discover a service on a specific network. + * + * This is an imperfect guess, as for example the network may be gone or not yet fully + * registered. This is fine as failing is correct if the network is gone, and a client + * attempting to resolve/discover on a network not yet setup would have a bad time anyway; also + * this is to support the legacy mdnsresponder implementation, which historically resolved + * services on an unspecified network. + */ + private int getNetworkInterfaceIndex(Network network) { + if (network == null) return IFACE_IDX_ANY; + + final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class); + if (cm == null) { + Log.wtf(TAG, "No ConnectivityManager for resolveService"); + return IFACE_IDX_ANY; + } + final LinkProperties lp = cm.getLinkProperties(network); + if (lp == null) return IFACE_IDX_ANY; + + // Only resolve on non-stacked interfaces + final NetworkInterface iface; + try { + iface = NetworkInterface.getByName(lp.getInterfaceName()); + } catch (SocketException e) { + Log.e(TAG, "Error querying interface", e); + return IFACE_IDX_ANY; + } + + if (iface == null) { + Log.e(TAG, "Interface not found: " + lp.getInterfaceName()); + return IFACE_IDX_ANY; + } + + return iface.getIndex(); } private boolean stopResolveService(int resolveId) { return mDaemon.execute("stop-resolve", resolveId); } - private boolean getAddrInfo(int resolveId, String hostname) { - return mDaemon.execute("getaddrinfo", resolveId, hostname); + private boolean getAddrInfo(int resolveId, String hostname, String interfaceIdx) { + // interfaceIdx is always obtained (as string) from the service resolved callback + return mDaemon.execute("getaddrinfo", resolveId, hostname, interfaceIdx); } private boolean stopGetAddrInfo(int resolveId) { diff --git a/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapKey.java b/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapKey.java new file mode 100644 index 000000000000..443e5b38475e --- /dev/null +++ b/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapKey.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2022 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 com.android.server.net; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +/** + * Key for cookie tag map. + */ +public class CookieTagMapKey extends Struct { + @Field(order = 0, type = Type.S64) + public final long socketCookie; + + public CookieTagMapKey(final long socketCookie) { + this.socketCookie = socketCookie; + } +} diff --git a/apex/media/aidl/private/android/media/IMediaSession2Service.aidl b/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapValue.java index 10ac1be0a36e..93b9195f92da 100644 --- a/apex/media/aidl/private/android/media/IMediaSession2Service.aidl +++ b/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapValue.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 The Android Open Source Project + * Copyright (C) 2022 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. @@ -14,19 +14,24 @@ * limitations under the License. */ -package android.media; +package com.android.server.net; -import android.os.Bundle; -import android.media.Controller2Link; +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; /** - * Interface from MediaController2 to MediaSession2Service. - * <p> - * Keep this interface oneway. Otherwise a malicious app may implement fake version of this, - * and holds calls from controller to make controller owner(s) frozen. - * @hide + * Value for cookie tag map. */ -oneway interface IMediaSession2Service { - void connect(in Controller2Link caller, int seq, in Bundle connectionRequest) = 0; - // Next Id : 1 +public class CookieTagMapValue extends Struct { + @Field(order = 0, type = Type.U32) + public final long uid; + + @Field(order = 1, type = Type.U32) + public final long tag; + + public CookieTagMapValue(final long uid, final long tag) { + this.uid = uid; + this.tag = tag; + } } diff --git a/packages/ConnectivityT/service/src/com/android/server/net/InterfaceMapValue.java b/packages/ConnectivityT/service/src/com/android/server/net/InterfaceMapValue.java index 061f323447b0..42c0044e666f 100644 --- a/packages/ConnectivityT/service/src/com/android/server/net/InterfaceMapValue.java +++ b/packages/ConnectivityT/service/src/com/android/server/net/InterfaceMapValue.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Android Open Source Project + * Copyright (C) 2022 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. diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java index 17f3455d20a2..151c90dd4155 100644 --- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java +++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java @@ -22,8 +22,6 @@ import static android.net.NetworkStats.TAG_ALL; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; -import static com.android.server.NetworkManagementSocketTagger.kernelToTag; - import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; @@ -56,6 +54,10 @@ import java.util.concurrent.ConcurrentHashMap; * @hide */ public class NetworkStatsFactory { + static { + System.loadLibrary("service-connectivity"); + } + private static final String TAG = "NetworkStatsFactory"; private static final boolean USE_NATIVE_PARSING = true; @@ -470,6 +472,19 @@ public class NetworkStatsFactory { } /** + * Convert {@code /proc/} tag format to {@link Integer}. Assumes incoming + * format like {@code 0x7fffffff00000000}. + */ + public static int kernelToTag(String string) { + int length = string.length(); + if (length > 10) { + return Long.decode(string.substring(0, length - 8)).intValue(); + } else { + return 0; + } + } + + /** * Parse statistics from file into given {@link NetworkStats} object. Values * are expected to monotonically increase since device boot. */ diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsObservers.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsObservers.java index 19536247b23b..fdfc893f57cb 100644 --- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsObservers.java +++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsObservers.java @@ -19,8 +19,11 @@ package com.android.server.net; import static android.app.usage.NetworkStatsManager.MIN_THRESHOLD_BYTES; import android.app.usage.NetworkStatsManager; +import android.content.Context; +import android.content.pm.PackageManager; import android.net.DataUsageRequest; import android.net.NetworkIdentitySet; +import android.net.NetworkStack; import android.net.NetworkStats; import android.net.NetworkStatsAccess; import android.net.NetworkStatsCollection; @@ -74,9 +77,9 @@ class NetworkStatsObservers { * * @return the normalized request wrapped within {@link RequestInfo}. */ - public DataUsageRequest register(DataUsageRequest inputRequest, IUsageCallback callback, - int callingUid, @NetworkStatsAccess.Level int accessLevel) { - DataUsageRequest request = buildRequest(inputRequest, callingUid); + public DataUsageRequest register(Context context, DataUsageRequest inputRequest, + IUsageCallback callback, int callingUid, @NetworkStatsAccess.Level int accessLevel) { + DataUsageRequest request = buildRequest(context, inputRequest, callingUid); RequestInfo requestInfo = buildRequestInfo(request, callback, callingUid, accessLevel); @@ -194,10 +197,13 @@ class NetworkStatsObservers { } } - private DataUsageRequest buildRequest(DataUsageRequest request, int callingUid) { - // For non-system uid, cap the minimum threshold to a safe default to avoid too - // many callbacks. - long thresholdInBytes = (callingUid == Process.SYSTEM_UID ? request.thresholdInBytes + private DataUsageRequest buildRequest(Context context, DataUsageRequest request, + int callingUid) { + // For non-NETWORK_STACK permission uid, cap the minimum threshold to a safe default to + // avoid too many callbacks. + final long thresholdInBytes = (context.checkPermission( + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, Process.myPid(), callingUid) + == PackageManager.PERMISSION_GRANTED ? request.thresholdInBytes : Math.max(MIN_THRESHOLD_BYTES, request.thresholdInBytes)); if (thresholdInBytes > request.thresholdInBytes) { Log.w(TAG, "Threshold was too low for " + request diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java index c371f0859aa1..a006cd597568 100644 --- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java +++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java @@ -471,9 +471,11 @@ public class NetworkStatsRecorder { public void dumpDebugLocked(ProtoOutputStream proto, long tag) { final long start = proto.start(tag); if (mPending != null) { - proto.write(NetworkStatsRecorderProto.PENDING_TOTAL_BYTES, mPending.getTotalBytes()); + proto.write(NetworkStatsRecorderProto.PENDING_TOTAL_BYTES_FIELD_NUMBER, + mPending.getTotalBytes()); } - getOrLoadCompleteLocked().dumpDebug(proto, NetworkStatsRecorderProto.COMPLETE_HISTORY); + getOrLoadCompleteLocked().dumpDebug(proto, + NetworkStatsRecorderProto.COMPLETE_HISTORY_FIELD_NUMBER); proto.end(start); } diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java index 9f3371b724cf..ef6f39a5c040 100644 --- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java +++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java @@ -51,6 +51,7 @@ import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_UID; import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_UID_TAG; import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_XT; import static android.os.Trace.TRACE_TAG_NETWORK; +import static android.system.OsConstants.ENOENT; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; @@ -62,6 +63,7 @@ import static com.android.net.module.util.NetworkStatsUtils.LIMIT_GLOBAL_ALERT; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.TargetApi; import android.app.AlarmManager; import android.app.PendingIntent; import android.app.usage.NetworkStatsManager; @@ -102,6 +104,7 @@ import android.net.netstats.provider.INetworkStatsProvider; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.net.netstats.provider.NetworkStatsProvider; import android.os.Binder; +import android.os.Build; import android.os.DropBoxManager; import android.os.Environment; import android.os.Handler; @@ -120,7 +123,6 @@ import android.provider.Settings.Global; import android.service.NetworkInterfaceProto; import android.service.NetworkStatsServiceDumpProto; import android.system.ErrnoException; -import android.system.Os; import android.telephony.PhoneStateListener; import android.telephony.SubscriptionPlan; import android.text.TextUtils; @@ -169,7 +171,12 @@ import java.util.concurrent.TimeUnit; * Collect and persist detailed network statistics, and provide this data to * other system services. */ +@TargetApi(Build.VERSION_CODES.TIRAMISU) public class NetworkStatsService extends INetworkStatsService.Stub { + static { + System.loadLibrary("service-connectivity"); + } + static final String TAG = "NetworkStats"; static final boolean LOGD = Log.isLoggable(TAG, Log.DEBUG); static final boolean LOGV = Log.isLoggable(TAG, Log.VERBOSE); @@ -214,6 +221,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // This is current path but may be changed soon. private static final String UID_COUNTERSET_MAP_PATH = "/sys/fs/bpf/map_netd_uid_counterset_map"; + private static final String COOKIE_TAG_MAP_PATH = + "/sys/fs/bpf/map_netd_cookie_tag_map"; + private static final String APP_UID_STATS_MAP_PATH = + "/sys/fs/bpf/map_netd_app_uid_stats_map"; + private static final String STATS_MAP_A_PATH = + "/sys/fs/bpf/map_netd_stats_map_A"; + private static final String STATS_MAP_B_PATH = + "/sys/fs/bpf/map_netd_stats_map_B"; private final Context mContext; private final NetworkStatsFactory mStatsFactory; @@ -341,6 +356,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ private SparseIntArray mActiveUidCounterSet = new SparseIntArray(); private final IBpfMap<U32, U8> mUidCounterSetMap; + private final IBpfMap<CookieTagMapKey, CookieTagMapValue> mCookieTagMap; + private final IBpfMap<StatsMapKey, StatsMapValue> mStatsMapA; + private final IBpfMap<StatsMapKey, StatsMapValue> mStatsMapB; + private final IBpfMap<UidStatsMapKey, StatsMapValue> mAppUidStatsMap; /** Data layer operation counters for splicing into other structures. */ private NetworkStats mUidOperations = new NetworkStats(0L, 10); @@ -474,6 +493,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mInterfaceMapUpdater = mDeps.makeBpfInterfaceMapUpdater(mContext, mHandler); mInterfaceMapUpdater.start(); mUidCounterSetMap = mDeps.getUidCounterSetMap(); + mCookieTagMap = mDeps.getCookieTagMap(); + mStatsMapA = mDeps.getStatsMapA(); + mStatsMapB = mDeps.getStatsMapB(); + mAppUidStatsMap = mDeps.getAppUidStatsMap(); } /** @@ -547,8 +570,48 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - public TagStatsDeleter getTagStatsDeleter() { - return NetworkStatsService::nativeDeleteTagData; + /** Gets the cookie tag map */ + public IBpfMap<CookieTagMapKey, CookieTagMapValue> getCookieTagMap() { + try { + return new BpfMap<CookieTagMapKey, CookieTagMapValue>(COOKIE_TAG_MAP_PATH, + BpfMap.BPF_F_RDWR, CookieTagMapKey.class, CookieTagMapValue.class); + } catch (ErrnoException e) { + Log.wtf(TAG, "Cannot create cookie tag map: " + e); + return null; + } + } + + /** Gets stats map A */ + public IBpfMap<StatsMapKey, StatsMapValue> getStatsMapA() { + try { + return new BpfMap<StatsMapKey, StatsMapValue>(STATS_MAP_A_PATH, + BpfMap.BPF_F_RDWR, StatsMapKey.class, StatsMapValue.class); + } catch (ErrnoException e) { + Log.wtf(TAG, "Cannot create stats map A: " + e); + return null; + } + } + + /** Gets stats map B */ + public IBpfMap<StatsMapKey, StatsMapValue> getStatsMapB() { + try { + return new BpfMap<StatsMapKey, StatsMapValue>(STATS_MAP_B_PATH, + BpfMap.BPF_F_RDWR, StatsMapKey.class, StatsMapValue.class); + } catch (ErrnoException e) { + Log.wtf(TAG, "Cannot create stats map B: " + e); + return null; + } + } + + /** Gets the uid stats map */ + public IBpfMap<UidStatsMapKey, StatsMapValue> getAppUidStatsMap() { + try { + return new BpfMap<UidStatsMapKey, StatsMapValue>(APP_UID_STATS_MAP_PATH, + BpfMap.BPF_F_RDWR, UidStatsMapKey.class, StatsMapValue.class); + } catch (ErrnoException e) { + Log.wtf(TAG, "Cannot create app uid stats map: " + e); + return null; + } } } @@ -1060,7 +1123,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStats getUidStatsForTransport(int transport) { - enforceAnyPermissionOf(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); + PermissionUtils.enforceNetworkStackPermission(mContext); try { final String[] relevantIfaces = transport == TRANSPORT_WIFI ? mWifiIfaces : mMobileIfaces; @@ -1222,7 +1285,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { DataUsageRequest normalizedRequest; final long token = Binder.clearCallingIdentity(); try { - normalizedRequest = mStatsObservers.register( + normalizedRequest = mStatsObservers.register(mContext, request, callback, callingUid, accessLevel); } finally { Binder.restoreCallingIdentity(token); @@ -1477,10 +1540,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { NetworkCapabilities.NET_CAPABILITY_IMS) && !ident.isMetered()) { // Copy the identify from IMS one but mark it as metered. - NetworkIdentity vtIdent = new NetworkIdentity(ident.getType(), - ident.getRatType(), ident.getSubscriberId(), ident.getWifiNetworkKey(), - ident.isRoaming(), true /* metered */, - true /* onDefaultNetwork */, ident.getOemManaged()); + NetworkIdentity vtIdent = new NetworkIdentity.Builder() + .setType(ident.getType()) + .setRatType(ident.getRatType()) + .setSubscriberId(ident.getSubscriberId()) + .setWifiNetworkKey(ident.getWifiNetworkKey()) + .setRoaming(ident.isRoaming()).setMetered(true) + .setDefaultNetwork(true) + .setOemManaged(ident.getOemManaged()) + .setSubId(ident.getSubId()).build(); final String ifaceVt = IFACE_VT + getSubIdForMobile(snapshot); findOrCreateNetworkIdentitySet(mActiveIfaces, ifaceVt).add(vtIdent); findOrCreateNetworkIdentitySet(mActiveUidIfaces, ifaceVt).add(vtIdent); @@ -1790,6 +1858,69 @@ public class NetworkStatsService extends INetworkStatsService.Stub { currentTime); } + // deleteKernelTagData can ignore ENOENT; otherwise we should log an error + private void logErrorIfNotErrNoent(final ErrnoException e, final String msg) { + if (e.errno != ENOENT) Log.e(TAG, msg, e); + } + + private <K extends StatsMapKey, V extends StatsMapValue> void deleteStatsMapTagData( + IBpfMap<K, V> statsMap, int uid) { + try { + statsMap.forEach((key, value) -> { + if (key.uid == uid) { + try { + statsMap.deleteEntry(key); + } catch (ErrnoException e) { + logErrorIfNotErrNoent(e, "Failed to delete data(uid = " + key.uid + ")"); + } + } + }); + } catch (ErrnoException e) { + Log.e(TAG, "FAILED to delete tag data from stats map", e); + } + } + + /** + * Deletes uid tag data from CookieTagMap, StatsMapA, StatsMapB, and UidStatsMap + * @param uid + */ + private void deleteKernelTagData(int uid) { + try { + mCookieTagMap.forEach((key, value) -> { + // If SkDestroyListener deletes the socket tag while this code is running, + // forEach will either restart iteration from the beginning or return null, + // depending on when the deletion happens. + // If it returns null, continue iteration to delete the data and in fact it would + // just iterate from first key because BpfMap#getNextKey would return first key + // if the current key is not exist. + if (value != null && value.uid == uid) { + try { + mCookieTagMap.deleteEntry(key); + } catch (ErrnoException e) { + logErrorIfNotErrNoent(e, "Failed to delete data(cookie = " + key + ")"); + } + } + }); + } catch (ErrnoException e) { + Log.e(TAG, "Failed to delete tag data from cookie tag map", e); + } + + deleteStatsMapTagData(mStatsMapA, uid); + deleteStatsMapTagData(mStatsMapB, uid); + + try { + mUidCounterSetMap.deleteEntry(new U32(uid)); + } catch (ErrnoException e) { + logErrorIfNotErrNoent(e, "Failed to delete tag data from uid counter set map"); + } + + try { + mAppUidStatsMap.deleteEntry(new UidStatsMapKey(uid)); + } catch (ErrnoException e) { + logErrorIfNotErrNoent(e, "Failed to delete tag data from app uid stats map"); + } + } + /** * Clean up {@link #mUidRecorder} after UID is removed. */ @@ -1805,10 +1936,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // Clear kernel stats associated with UID for (int uid : uids) { - final int ret = mDeps.getTagStatsDeleter().deleteTagData(uid); - if (ret < 0) { - Log.w(TAG, "problem clearing counters for uid " + uid + ": " + Os.strerror(-ret)); - } + deleteKernelTagData(uid); } } @@ -2004,12 +2132,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // TODO Right now it writes all history. Should it limit to the "since-boot" log? - dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_INTERFACES, mActiveIfaces); - dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_UID_INTERFACES, mActiveUidIfaces); - mDevRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS); - mXtRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.XT_STATS); - mUidRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_STATS); - mUidTagRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_TAG_STATS); + dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_INTERFACES_FIELD_NUMBER, + mActiveIfaces); + dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_UID_INTERFACES_FIELD_NUMBER, + mActiveUidIfaces); + mDevRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS_FIELD_NUMBER); + mXtRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.XT_STATS_FIELD_NUMBER); + mUidRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_STATS_FIELD_NUMBER); + mUidTagRecorder.dumpDebugLocked(proto, + NetworkStatsServiceDumpProto.UID_TAG_STATS_FIELD_NUMBER); proto.flush(); } @@ -2019,8 +2150,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { for (int i = 0; i < ifaces.size(); i++) { final long start = proto.start(tag); - proto.write(NetworkInterfaceProto.INTERFACE, ifaces.keyAt(i)); - ifaces.valueAt(i).dumpDebug(proto, NetworkInterfaceProto.IDENTITIES); + proto.write(NetworkInterfaceProto.INTERFACE_FIELD_NUMBER, ifaces.keyAt(i)); + ifaces.valueAt(i).dumpDebug(proto, NetworkInterfaceProto.IDENTITIES_FIELD_NUMBER); proto.end(start); } @@ -2387,12 +2518,4 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static native long nativeGetTotalStat(int type); private static native long nativeGetIfaceStat(String iface, int type); private static native long nativeGetUidStat(int uid, int type); - - // TODO: use BpfNetMaps to delete tag data and remove this. - @VisibleForTesting - interface TagStatsDeleter { - int deleteTagData(int uid); - } - - private static native int nativeDeleteTagData(int uid); } diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java index 5bba0b17aa42..65ccd2007299 100644 --- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -23,7 +23,9 @@ import static android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NS import static android.telephony.TelephonyManager.NETWORK_TYPE_LTE; import android.annotation.NonNull; +import android.annotation.TargetApi; import android.content.Context; +import android.os.Build; import android.telephony.SubscriptionManager; import android.telephony.TelephonyCallback; import android.telephony.TelephonyDisplayInfo; @@ -43,6 +45,7 @@ import java.util.concurrent.Executor; /** * Helper class that watches for events that are triggered per subscription. */ +@TargetApi(Build.VERSION_CODES.TIRAMISU) public class NetworkStatsSubscriptionsMonitor extends SubscriptionManager.OnSubscriptionsChangedListener { diff --git a/packages/ConnectivityT/service/src/com/android/server/net/StatsMapKey.java b/packages/ConnectivityT/service/src/com/android/server/net/StatsMapKey.java new file mode 100644 index 000000000000..ea8d83638347 --- /dev/null +++ b/packages/ConnectivityT/service/src/com/android/server/net/StatsMapKey.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2022 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 com.android.server.net; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +/** + * Key for both stats maps. + */ +public class StatsMapKey extends Struct { + @Field(order = 0, type = Type.U32) + public final long uid; + + @Field(order = 1, type = Type.U32) + public final long tag; + + @Field(order = 2, type = Type.U32) + public final long counterSet; + + @Field(order = 3, type = Type.U32) + public final long ifaceIndex; + + public StatsMapKey(final long uid, final long tag, final long counterSet, + final long ifaceIndex) { + this.uid = uid; + this.tag = tag; + this.counterSet = counterSet; + this.ifaceIndex = ifaceIndex; + } +} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/StatsMapValue.java b/packages/ConnectivityT/service/src/com/android/server/net/StatsMapValue.java new file mode 100644 index 000000000000..48f26ce686e2 --- /dev/null +++ b/packages/ConnectivityT/service/src/com/android/server/net/StatsMapValue.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2022 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 com.android.server.net; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +/** + * Value used for both stats maps and uid stats map. + */ +public class StatsMapValue extends Struct { + @Field(order = 0, type = Type.U63) + public final long rxPackets; + + @Field(order = 1, type = Type.U63) + public final long rxBytes; + + @Field(order = 2, type = Type.U63) + public final long txPackets; + + @Field(order = 3, type = Type.U63) + public final long txBytes; + + public StatsMapValue(final long rxPackets, final long rxBytes, final long txPackets, + final long txBytes) { + this.rxPackets = rxPackets; + this.rxBytes = rxBytes; + this.txPackets = txPackets; + this.txBytes = txBytes; + } +} diff --git a/apex/media/aidl/stable/android/media/Session2Token.aidl b/packages/ConnectivityT/service/src/com/android/server/net/UidStatsMapKey.java index c5980e9e77fd..2849f94c9383 100644 --- a/apex/media/aidl/stable/android/media/Session2Token.aidl +++ b/packages/ConnectivityT/service/src/com/android/server/net/UidStatsMapKey.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 The Android Open Source Project + * Copyright (C) 2022 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. @@ -14,6 +14,20 @@ * limitations under the License. */ -package android.media; +package com.android.server.net; -parcelable Session2Token; +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +/** + * Key for uid stats map. + */ +public class UidStatsMapKey extends Struct { + @Field(order = 0, type = Type.U32) + public final long uid; + + public UidStatsMapKey(final long uid) { + this.uid = uid; + } +} diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/SparseInputStream.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/SparseInputStream.java index 72230b4062e1..4117d0f07e0f 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/SparseInputStream.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/SparseInputStream.java @@ -177,7 +177,7 @@ public class SparseInputStream extends InputStream { ret = 0; break; case SparseChunk.FILL: - ret = mCur.fill[(4 - ((int) mLeft & 0x3)) & 0x3]; + ret = Byte.toUnsignedInt(mCur.fill[(4 - ((int) mLeft & 0x3)) & 0x3]); break; default: throw new IOException("Unsupported Chunk:" + mCur.toString()); diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java index 99e3160fcbe3..df19c67f00e5 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java @@ -173,8 +173,10 @@ public class A2dpProfile implements LocalBluetoothProfile { } public BluetoothDevice getActiveDevice() { - if (mService == null) return null; - return mService.getActiveDevice(); + if (mBluetoothAdapter == null) return null; + final List<BluetoothDevice> activeDevices = mBluetoothAdapter + .getActiveDevices(BluetoothProfile.A2DP); + return (activeDevices.size() > 0) ? activeDevices.get(0) : null; } @Override @@ -221,7 +223,7 @@ public class A2dpProfile implements LocalBluetoothProfile { } public boolean supportsHighQualityAudio(BluetoothDevice device) { - BluetoothDevice bluetoothDevice = (device != null) ? device : mService.getActiveDevice(); + BluetoothDevice bluetoothDevice = (device != null) ? device : getActiveDevice(); if (bluetoothDevice == null) { return false; } @@ -234,7 +236,7 @@ public class A2dpProfile implements LocalBluetoothProfile { */ @RequiresApi(Build.VERSION_CODES.TIRAMISU) public boolean isHighQualityAudioEnabled(BluetoothDevice device) { - BluetoothDevice bluetoothDevice = (device != null) ? device : mService.getActiveDevice(); + BluetoothDevice bluetoothDevice = (device != null) ? device : getActiveDevice(); if (bluetoothDevice == null) { return false; } @@ -260,7 +262,7 @@ public class A2dpProfile implements LocalBluetoothProfile { } public void setHighQualityAudioEnabled(BluetoothDevice device, boolean enabled) { - BluetoothDevice bluetoothDevice = (device != null) ? device : mService.getActiveDevice(); + BluetoothDevice bluetoothDevice = (device != null) ? device : getActiveDevice(); if (bluetoothDevice == null) { return; } @@ -286,7 +288,7 @@ public class A2dpProfile implements LocalBluetoothProfile { */ @RequiresApi(Build.VERSION_CODES.TIRAMISU) public String getHighQualityAudioOptionLabel(BluetoothDevice device) { - BluetoothDevice bluetoothDevice = (device != null) ? device : mService.getActiveDevice(); + BluetoothDevice bluetoothDevice = (device != null) ? device : getActiveDevice(); int unknownCodecId = R.string.bluetooth_profile_a2dp_high_quality_unknown_codec; if (bluetoothDevice == null || !supportsHighQualityAudio(device) || getConnectionStatus(device) != BluetoothProfile.STATE_CONNECTED) { diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index ddee433d3997..233e798c8578 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -500,6 +500,17 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> } /** + * Get identity address from remote device + * @return {@link BluetoothDevice#getIdentityAddress()} if + * {@link BluetoothDevice#getIdentityAddress()} is not null otherwise return + * {@link BluetoothDevice#getAddress()} + */ + public String getIdentityAddress() { + final String identityAddress = mDevice.getIdentityAddress(); + return TextUtils.isEmpty(identityAddress) ? getAddress() : identityAddress; + } + + /** * Get name from remote device * @return {@link BluetoothDevice#getAlias()} if * {@link BluetoothDevice#getAlias()} is not null otherwise return diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java index 9dd329ed7cd7..7e5c1240cc63 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java @@ -132,17 +132,12 @@ public class HeadsetProfile implements LocalBluetoothProfile { } public BluetoothDevice getActiveDevice() { - if (mService == null) { + if (mBluetoothAdapter == null) { return null; } - return mService.getActiveDevice(); - } - - public boolean isAudioOn() { - if (mService == null) { - return false; - } - return mService.isAudioOn(); + final List<BluetoothDevice> activeDevices = mBluetoothAdapter + .getActiveDevices(BluetoothProfile.HEADSET); + return (activeDevices.size() > 0) ? activeDevices.get(0) : null; } public int getAudioState(BluetoothDevice device) { diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java index a1fba4a018e2..ff1368adad82 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java @@ -168,8 +168,10 @@ public class HearingAidProfile implements LocalBluetoothProfile { } public List<BluetoothDevice> getActiveDevices() { - if (mService == null) return new ArrayList<>(); - return mService.getActiveDevices(); + if (mBluetoothAdapter == null) { + return new ArrayList<>(); + } + return mBluetoothAdapter.getActiveDevices(BluetoothProfile.HEARING_AID); } @Override diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java index 209507ac7088..db6d41ef692d 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java @@ -21,12 +21,12 @@ import static android.bluetooth.BluetoothAdapter.ACTIVE_DEVICE_ALL; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; -import android.bluetooth.BluetoothLeAudio; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothCodecConfig; import android.bluetooth.BluetoothCodecStatus; import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothLeAudio; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothUuid; import android.content.Context; @@ -177,10 +177,10 @@ public class LeAudioProfile implements LocalBluetoothProfile { } public List<BluetoothDevice> getActiveDevices() { - if (mService == null) { + if (mBluetoothAdapter == null) { return new ArrayList<>(); } - return mService.getActiveDevices(); + return mBluetoothAdapter.getActiveDevices(BluetoothProfile.LE_AUDIO); } @Override diff --git a/packages/SettingsLib/src/com/android/settingslib/devicestate/OWNERS b/packages/SettingsLib/src/com/android/settingslib/devicestate/OWNERS new file mode 100644 index 000000000000..98f41234feb1 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/devicestate/OWNERS @@ -0,0 +1,3 @@ +# Default reviewers for this and subdirectories. +alexflo@google.com +chrisgollner@google.com diff --git a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java index b4c95e6ee2df..c7eb68240c5b 100644 --- a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java +++ b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java @@ -39,6 +39,8 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.SortedMap; +import java.util.TreeMap; import java.util.zip.GZIPInputStream; /** @@ -54,6 +56,7 @@ class LicenseHtmlGeneratorFromXml { private static final String TAG_FILE_NAME = "file-name"; private static final String TAG_FILE_CONTENT = "file-content"; private static final String ATTR_CONTENT_ID = "contentId"; + private static final String ATTR_LIBRARY_NAME = "lib"; private static final String HTML_HEAD_STRING = "<html><head>\n" @@ -67,8 +70,12 @@ class LicenseHtmlGeneratorFromXml { + "</style>\n" + "</head>" + "<body topmargin=\"0\" leftmargin=\"0\" rightmargin=\"0\" bottommargin=\"0\">\n" - + "<div class=\"toc\">\n" - + "<ul>"; + + "<div class=\"toc\">"; + private static final String LIBRARY_HEAD_STRING = + "<strong>Libraries</strong>\n<ul class=\"libraries\">"; + private static final String LIBRARY_TAIL_STRING = "</ul>\n<strong>Files</strong>"; + + private static final String FILES_HEAD_STRING = "<ul class=\"files\">"; private static final String HTML_MIDDLE_STRING = "</ul>\n" @@ -81,12 +88,14 @@ class LicenseHtmlGeneratorFromXml { private final List<File> mXmlFiles; /* - * A map from a file name to a content id (MD5 sum of file content) for its license. - * For example, "/system/priv-app/TeleService/TeleService.apk" maps to + * A map from a file name to a library name (may be empty) to a content id (MD5 sum of file + * content) for its license. + * For example, "/system/priv-app/TeleService/TeleService.apk" maps to "service/Telephony" to * "9645f39e9db895a4aa6e02cb57294595". Here "9645f39e9db895a4aa6e02cb57294595" is a MD5 sum * of the content of packages/services/Telephony/MODULE_LICENSE_APACHE2. */ - private final Map<String, Set<String>> mFileNameToContentIdMap = new HashMap(); + private final Map<String, Map<String, Set<String>>> mFileNameToLibraryToContentIdMap = + new HashMap(); /* * A map from a content id (MD5 sum of file content) to a license file content. @@ -98,7 +107,7 @@ class LicenseHtmlGeneratorFromXml { static class ContentIdAndFileNames { final String mContentId; - final List<String> mFileNameList = new ArrayList(); + final Map<String, List<String>> mLibraryToFileNameMap = new TreeMap(); ContentIdAndFileNames(String contentId) { mContentId = contentId; @@ -120,7 +129,7 @@ class LicenseHtmlGeneratorFromXml { parse(xmlFile); } - if (mFileNameToContentIdMap.isEmpty() || mContentIdToFileContentMap.isEmpty()) { + if (mFileNameToLibraryToContentIdMap.isEmpty() || mContentIdToFileContentMap.isEmpty()) { return false; } @@ -128,7 +137,7 @@ class LicenseHtmlGeneratorFromXml { try { writer = new PrintWriter(outputFile); - generateHtml(mFileNameToContentIdMap, mContentIdToFileContentMap, writer, + generateHtml(mFileNameToLibraryToContentIdMap, mContentIdToFileContentMap, writer, noticeHeader); writer.flush(); @@ -157,7 +166,7 @@ class LicenseHtmlGeneratorFromXml { in = new FileReader(xmlFile); } - parse(in, mFileNameToContentIdMap, mContentIdToFileContentMap); + parse(in, mFileNameToLibraryToContentIdMap, mContentIdToFileContentMap); in.close(); } catch (XmlPullParserException | IOException e) { @@ -180,7 +189,8 @@ class LicenseHtmlGeneratorFromXml { * * <licenses> * <file-name contentId="content_id_of_license1">file1</file-name> - * <file-name contentId="content_id_of_license2">file2</file-name> + * <file-name contentId="content_id_of_license2" lib="name of library">file2</file-name> + * <file-name contentId="content_id_of_license2" lib="another library">file2</file-name> * ... * <file-content contentId="content_id_of_license1">license1 file contents</file-content> * <file-content contentId="content_id_of_license2">license2 file contents</file-content> @@ -188,10 +198,12 @@ class LicenseHtmlGeneratorFromXml { * </licenses> */ @VisibleForTesting - static void parse(InputStreamReader in, Map<String, Set<String>> outFileNameToContentIdMap, + static void parse(InputStreamReader in, + Map<String, Map<String, Set<String>>> outFileNameToLibraryToContentIdMap, Map<String, String> outContentIdToFileContentMap) throws XmlPullParserException, IOException { - Map<String, Set<String>> fileNameToContentIdMap = new HashMap<String, Set<String>>(); + Map<String, Map<String, Set<String>>> fileNameToLibraryToContentIdMap = + new HashMap<String, Map<String, Set<String>>>(); Map<String, String> contentIdToFileContentMap = new HashMap<String, String>(); XmlPullParser parser = Xml.newPullParser(); @@ -205,12 +217,15 @@ class LicenseHtmlGeneratorFromXml { if (state == XmlPullParser.START_TAG) { if (TAG_FILE_NAME.equals(parser.getName())) { String contentId = parser.getAttributeValue("", ATTR_CONTENT_ID); + String libraryName = parser.getAttributeValue("", ATTR_LIBRARY_NAME); if (!TextUtils.isEmpty(contentId)) { String fileName = readText(parser).trim(); if (!TextUtils.isEmpty(fileName)) { - Set<String> contentIds = - fileNameToContentIdMap.computeIfAbsent( - fileName, k -> new HashSet<>()); + Map<String, Set<String>> libs = + fileNameToLibraryToContentIdMap.computeIfAbsent( + fileName, k -> new HashMap<>()); + Set<String> contentIds = libs.computeIfAbsent( + libraryName, k -> new HashSet<>()); contentIds.add(contentId); } } @@ -229,11 +244,17 @@ class LicenseHtmlGeneratorFromXml { state = parser.next(); } - for (Map.Entry<String, Set<String>> entry : fileNameToContentIdMap.entrySet()) { - outFileNameToContentIdMap.merge( - entry.getKey(), entry.getValue(), (s1, s2) -> { - s1.addAll(s2); - return s1; + for (Map.Entry<String, Map<String, Set<String>>> mapEntry : + fileNameToLibraryToContentIdMap.entrySet()) { + outFileNameToLibraryToContentIdMap.merge( + mapEntry.getKey(), mapEntry.getValue(), (m1, m2) -> { + for (Map.Entry<String, Set<String>> entry : m2.entrySet()) { + m1.merge(entry.getKey(), entry.getValue(), (s1, s2) -> { + s1.addAll(s2); + return s1; + }); + } + return m1; }); } outContentIdToFileContentMap.putAll(contentIdToFileContentMap); @@ -251,13 +272,28 @@ class LicenseHtmlGeneratorFromXml { } @VisibleForTesting - static void generateHtml(Map<String, Set<String>> fileNameToContentIdMap, + static void generateHtml(Map<String, Map<String, Set<String>>> fileNameToLibraryToContentIdMap, Map<String, String> contentIdToFileContentMap, PrintWriter writer, String noticeHeader) { List<String> fileNameList = new ArrayList(); - fileNameList.addAll(fileNameToContentIdMap.keySet()); + fileNameList.addAll(fileNameToLibraryToContentIdMap.keySet()); Collections.sort(fileNameList); + SortedMap<String, Set<String>> libraryToContentIdMap = new TreeMap(); + for (Map<String, Set<String>> libraryToContentValue : + fileNameToLibraryToContentIdMap.values()) { + for (Map.Entry<String, Set<String>> entry : libraryToContentValue.entrySet()) { + if (TextUtils.isEmpty(entry.getKey())) { + continue; + } + libraryToContentIdMap.merge( + entry.getKey(), entry.getValue(), (s1, s2) -> { + s1.addAll(s2); + return s1; + }); + } + } + writer.println(HTML_HEAD_STRING); if (!TextUtils.isEmpty(noticeHeader)) { @@ -268,21 +304,58 @@ class LicenseHtmlGeneratorFromXml { Map<String, Integer> contentIdToOrderMap = new HashMap(); List<ContentIdAndFileNames> contentIdAndFileNamesList = new ArrayList(); + if (!libraryToContentIdMap.isEmpty()) { + writer.println(LIBRARY_HEAD_STRING); + for (Map.Entry<String, Set<String>> entry: libraryToContentIdMap.entrySet()) { + String libraryName = entry.getKey(); + for (String contentId : entry.getValue()) { + // Assigns an id to a newly referred license file content. + if (!contentIdToOrderMap.containsKey(contentId)) { + contentIdToOrderMap.put(contentId, count); + + // An index in contentIdAndFileNamesList is the order of each element. + contentIdAndFileNamesList.add(new ContentIdAndFileNames(contentId)); + count++; + } + int id = contentIdToOrderMap.get(contentId); + writer.format("<li><a href=\"#id%d\">%s</a></li>\n", id, libraryName); + } + } + writer.println(LIBRARY_TAIL_STRING); + } + + writer.println(FILES_HEAD_STRING); + // Prints all the file list with a link to its license file content. for (String fileName : fileNameList) { - for (String contentId : fileNameToContentIdMap.get(fileName)) { - // Assigns an id to a newly referred license file content. - if (!contentIdToOrderMap.containsKey(contentId)) { - contentIdToOrderMap.put(contentId, count); - - // An index in contentIdAndFileNamesList is the order of each element. - contentIdAndFileNamesList.add(new ContentIdAndFileNames(contentId)); - count++; + for (Map.Entry<String, Set<String>> libToContentId : + fileNameToLibraryToContentIdMap.get(fileName).entrySet()) { + String libraryName = libToContentId.getKey(); + if (libraryName == null) { + libraryName = ""; } + for (String contentId : libToContentId.getValue()) { + // Assigns an id to a newly referred license file content. + if (!contentIdToOrderMap.containsKey(contentId)) { + contentIdToOrderMap.put(contentId, count); + + // An index in contentIdAndFileNamesList is the order of each element. + contentIdAndFileNamesList.add(new ContentIdAndFileNames(contentId)); + count++; + } - int id = contentIdToOrderMap.get(contentId); - contentIdAndFileNamesList.get(id).mFileNameList.add(fileName); - writer.format("<li><a href=\"#id%d\">%s</a></li>\n", id, fileName); + int id = contentIdToOrderMap.get(contentId); + ContentIdAndFileNames elem = contentIdAndFileNamesList.get(id); + List<String> files = elem.mLibraryToFileNameMap.computeIfAbsent( + libraryName, k -> new ArrayList()); + files.add(fileName); + if (TextUtils.isEmpty(libraryName)) { + writer.format("<li><a href=\"#id%d\">%s</a></li>\n", id, fileName); + } else { + writer.format("<li><a href=\"#id%d\">%s - %s</a></li>\n", + id, fileName, libraryName); + } + } } } @@ -292,19 +365,27 @@ class LicenseHtmlGeneratorFromXml { // Prints all contents of the license files in order of id. for (ContentIdAndFileNames contentIdAndFileNames : contentIdAndFileNamesList) { writer.format("<tr id=\"id%d\"><td class=\"same-license\">\n", count); - writer.println("<div class=\"label\">Notices for file(s):</div>"); - writer.println("<div class=\"file-list\">"); - for (String fileName : contentIdAndFileNames.mFileNameList) { - writer.format("%s <br/>\n", fileName); + for (Map.Entry<String, List<String>> libraryFiles : + contentIdAndFileNames.mLibraryToFileNameMap.entrySet()) { + String libraryName = libraryFiles.getKey(); + if (TextUtils.isEmpty(libraryName)) { + writer.println("<div class=\"label\">Notices for file(s):</div>"); + } else { + writer.format("<div class=\"label\"><strong>%s</strong> used by:</div>\n", + libraryName); + } + writer.println("<div class=\"file-list\">"); + for (String fileName : libraryFiles.getValue()) { + writer.format("%s <br/>\n", fileName); + } + writer.println("</div><!-- file-list -->"); + count++; } - writer.println("</div><!-- file-list -->"); writer.println("<pre class=\"license-text\">"); writer.println(contentIdToFileContentMap.get( contentIdAndFileNames.mContentId)); writer.println("</pre><!-- license-text -->"); writer.println("</td></tr><!-- same-license -->"); - - count++; } writer.println(HTML_REAR_STRING); diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/OWNERS b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/OWNERS new file mode 100644 index 000000000000..98f41234feb1 --- /dev/null +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/OWNERS @@ -0,0 +1,3 @@ +# Default reviewers for this and subdirectories. +alexflo@google.com +chrisgollner@google.com diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java index f167721f94bf..bb6b293b0c27 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java @@ -60,6 +60,8 @@ public class A2dpProfileTest { private BluetoothDevice mDevice; @Mock private BluetoothA2dp mBluetoothA2dp; + @Mock + private BluetoothAdapter mBluetoothAdapter; private BluetoothProfile.ServiceListener mServiceListener; private A2dpProfile mProfile; @@ -72,7 +74,8 @@ public class A2dpProfileTest { mProfile = new A2dpProfile(mContext, mDeviceManager, mProfileManager); mServiceListener = mShadowBluetoothAdapter.getServiceListener(); mServiceListener.onServiceConnected(BluetoothProfile.A2DP, mBluetoothA2dp); - when(mBluetoothA2dp.getActiveDevice()).thenReturn(mDevice); + when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.A2DP))) + .thenReturn(Arrays.asList(mDevice)); } @Test @@ -203,9 +206,8 @@ public class A2dpProfileTest { when(config.isMandatoryCodec()).thenReturn(false); when(config.getCodecType()).thenReturn(4); - when(config.getCodecName()).thenReturn("LDAC"); assertThat(mProfile.getHighQualityAudioOptionLabel(mDevice)).isEqualTo( - String.format(KNOWN_CODEC_LABEL, config.getCodecName())); + String.format(KNOWN_CODEC_LABEL, "LDAC")); } @Test diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java index d53a3e896868..298ee90d311d 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java @@ -28,6 +28,7 @@ import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothUuid; import android.content.Context; +import android.os.Parcel; import android.os.ParcelUuid; import org.junit.Before; @@ -60,9 +61,9 @@ public class CachedBluetoothDeviceManagerTest { private final static Map<Integer, ParcelUuid> CAP_GROUP2 = Map.of(2, BluetoothUuid.CAP); private final BluetoothClass DEVICE_CLASS_1 = - new BluetoothClass(BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES); + createBtClass(BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES); private final BluetoothClass DEVICE_CLASS_2 = - new BluetoothClass(BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE); + createBtClass(BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE); @Mock private LocalBluetoothProfileManager mLocalProfileManager; @Mock @@ -92,6 +93,16 @@ public class CachedBluetoothDeviceManagerTest { private HearingAidDeviceManager mHearingAidDeviceManager; private Context mContext; + private BluetoothClass createBtClass(int deviceClass) { + Parcel p = Parcel.obtain(); + p.writeInt(deviceClass); + p.setDataPosition(0); // reset position of parcel before passing to constructor + + BluetoothClass bluetoothClass = BluetoothClass.CREATOR.createFromParcel(p); + p.recycle(); + return bluetoothClass; + } + @Before public void setUp() { MockitoAnnotations.initMocks(this); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HeadsetProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HeadsetProfileTest.java index 30182c476855..f5ce6647e531 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HeadsetProfileTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HeadsetProfileTest.java @@ -55,15 +55,6 @@ public class HeadsetProfileTest { } @Test - public void bluetoothProfile_shouldReturnTheAudioStatusFromBlueToothHeadsetService() { - when(mService.isAudioOn()).thenReturn(true); - assertThat(mProfile.isAudioOn()).isTrue(); - - when(mService.isAudioOn()).thenReturn(false); - assertThat(mProfile.isAudioOn()).isFalse(); - } - - @Test public void testHeadsetProfile_shouldReturnAudioState() { when(mService.getAudioState(mBluetoothDevice)). thenReturn(BluetoothHeadset.STATE_AUDIO_DISCONNECTED); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java index 7be176a37bb4..a8e607549ab1 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java @@ -28,6 +28,7 @@ import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHearingAid; import android.bluetooth.BluetoothProfile; import android.content.Context; +import android.os.Parcel; import org.junit.Before; import org.junit.Test; @@ -48,7 +49,7 @@ public class HearingAidDeviceManagerTest { private final static String DEVICE_ADDRESS_1 = "AA:BB:CC:DD:EE:11"; private final static String DEVICE_ADDRESS_2 = "AA:BB:CC:DD:EE:22"; private final BluetoothClass DEVICE_CLASS = - new BluetoothClass(BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE); + createBtClass(BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE); @Mock private LocalBluetoothProfileManager mLocalProfileManager; @Mock @@ -67,6 +68,16 @@ public class HearingAidDeviceManagerTest { private HearingAidDeviceManager mHearingAidDeviceManager; private Context mContext; + private BluetoothClass createBtClass(int deviceClass) { + Parcel p = Parcel.obtain(); + p.writeInt(deviceClass); + p.setDataPosition(0); // reset position of parcel before passing to constructor + + BluetoothClass bluetoothClass = BluetoothClass.CREATOR.createFromParcel(p); + p.recycle(); + return bluetoothClass; + } + @Before public void setUp() { MockitoAnnotations.initMocks(this); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java index e87461f85762..09b0d7f56e18 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java @@ -36,7 +36,7 @@ import java.util.Set; @RunWith(RobolectricTestRunner.class) public class LicenseHtmlGeneratorFromXmlTest { - private static final String VALILD_XML_STRING = + private static final String VALID_OLD_XML_STRING = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + "<licenses>\n" + "<file-name contentId=\"0\">/file0</file-name>\n" @@ -44,7 +44,15 @@ public class LicenseHtmlGeneratorFromXmlTest { + "<file-content contentId=\"0\"><![CDATA[license content #0]]></file-content>\n" + "</licenses>"; - private static final String INVALILD_XML_STRING = + private static final String VALID_NEW_XML_STRING = + "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + + "<licenses>\n" + + "<file-name contentId=\"0\" lib=\"libA\">/file0</file-name>\n" + + "<file-name contentId=\"0\" lib=\"libB\">/file1</file-name>\n" + + "<file-content contentId=\"0\"><![CDATA[license content #0]]></file-content>\n" + + "</licenses>"; + + private static final String INVALID_XML_STRING = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + "<licenses2>\n" + "<file-name contentId=\"0\">/file0</file-name>\n" @@ -64,13 +72,13 @@ public class LicenseHtmlGeneratorFromXmlTest { + "</style>\n" + "</head>" + "<body topmargin=\"0\" leftmargin=\"0\" rightmargin=\"0\" bottommargin=\"0\">\n" - + "<div class=\"toc\">\n" - + "<ul>\n"; + + "<div class=\"toc\">\n"; private static final String HTML_CUSTOM_HEADING = "Custom heading"; - private static final String HTML_BODY_STRING = - "<li><a href=\"#id0\">/file0</a></li>\n" + private static final String HTML_OLD_BODY_STRING = + "<ul class=\"files\">\n" + + "<li><a href=\"#id0\">/file0</a></li>\n" + "<li><a href=\"#id1\">/file0</a></li>\n" + "<li><a href=\"#id0\">/file1</a></li>\n" + "</ul>\n" @@ -97,66 +105,184 @@ public class LicenseHtmlGeneratorFromXmlTest { + "</td></tr><!-- same-license -->\n" + "</table></body></html>\n"; - private static final String EXPECTED_HTML_STRING = HTML_HEAD_STRING + HTML_BODY_STRING; + private static final String HTML_NEW_BODY_STRING = + "<strong>Libraries</strong>\n" + + "<ul class=\"libraries\">\n" + + "<li><a href=\"#id0\">libA</a></li>\n" + + "<li><a href=\"#id1\">libB</a></li>\n" + + "</ul>\n" + + "<strong>Files</strong>\n" + + "<ul class=\"files\">\n" + + "<li><a href=\"#id0\">/file0 - libA</a></li>\n" + + "<li><a href=\"#id1\">/file0 - libB</a></li>\n" + + "<li><a href=\"#id0\">/file1 - libA</a></li>\n" + + "</ul>\n" + + "</div><!-- table of contents -->\n" + + "<table cellpadding=\"0\" cellspacing=\"0\" border=\"0\">\n" + + "<tr id=\"id0\"><td class=\"same-license\">\n" + + "<div class=\"label\"><strong>libA</strong> used by:</div>\n" + + "<div class=\"file-list\">\n" + + "/file0 <br/>\n" + + "/file1 <br/>\n" + + "</div><!-- file-list -->\n" + + "<pre class=\"license-text\">\n" + + "license content #0\n" + + "</pre><!-- license-text -->\n" + + "</td></tr><!-- same-license -->\n" + + "<tr id=\"id1\"><td class=\"same-license\">\n" + + "<div class=\"label\"><strong>libB</strong> used by:</div>\n" + + "<div class=\"file-list\">\n" + + "/file0 <br/>\n" + + "</div><!-- file-list -->\n" + + "<pre class=\"license-text\">\n" + + "license content #1\n" + + "</pre><!-- license-text -->\n" + + "</td></tr><!-- same-license -->\n" + + "</table></body></html>\n"; + + private static final String EXPECTED_OLD_HTML_STRING = HTML_HEAD_STRING + HTML_OLD_BODY_STRING; - private static final String EXPECTED_HTML_STRING_WITH_CUSTOM_HEADING = - HTML_HEAD_STRING + HTML_CUSTOM_HEADING + "\n" + HTML_BODY_STRING; + private static final String EXPECTED_NEW_HTML_STRING = HTML_HEAD_STRING + HTML_NEW_BODY_STRING; + + private static final String EXPECTED_OLD_HTML_STRING_WITH_CUSTOM_HEADING = + HTML_HEAD_STRING + HTML_CUSTOM_HEADING + "\n" + HTML_OLD_BODY_STRING; + + private static final String EXPECTED_NEW_HTML_STRING_WITH_CUSTOM_HEADING = + HTML_HEAD_STRING + HTML_CUSTOM_HEADING + "\n" + HTML_NEW_BODY_STRING; @Test public void testParseValidXmlStream() throws XmlPullParserException, IOException { - Map<String, Set<String>> fileNameToContentIdMap = new HashMap<>(); + Map<String, Map<String, Set<String>>> fileNameToLibraryToContentIdMap = new HashMap<>(); + Map<String, String> contentIdToFileContentMap = new HashMap<>(); + + LicenseHtmlGeneratorFromXml.parse( + new InputStreamReader(new ByteArrayInputStream(VALID_OLD_XML_STRING.getBytes())), + fileNameToLibraryToContentIdMap, contentIdToFileContentMap); + + assertThat(fileNameToLibraryToContentIdMap).hasSize(2); + assertThat(fileNameToLibraryToContentIdMap.get("/file0")).hasSize(1); + assertThat(fileNameToLibraryToContentIdMap.get("/file1")).hasSize(1); + assertThat(fileNameToLibraryToContentIdMap.get("/file0").get(null)).containsExactly("0"); + assertThat(fileNameToLibraryToContentIdMap.get("/file1").get(null)).containsExactly("0"); + assertThat(contentIdToFileContentMap.size()).isEqualTo(1); + assertThat(contentIdToFileContentMap.get("0")).isEqualTo("license content #0"); + } + + @Test + public void testParseNewValidXmlStream() throws XmlPullParserException, IOException { + Map<String, Map<String, Set<String>>> fileNameToLibraryToContentIdMap = new HashMap<>(); Map<String, String> contentIdToFileContentMap = new HashMap<>(); LicenseHtmlGeneratorFromXml.parse( - new InputStreamReader(new ByteArrayInputStream(VALILD_XML_STRING.getBytes())), - fileNameToContentIdMap, contentIdToFileContentMap); - assertThat(fileNameToContentIdMap.size()).isEqualTo(2); - assertThat(fileNameToContentIdMap.get("/file0")).containsExactly("0"); - assertThat(fileNameToContentIdMap.get("/file1")).containsExactly("0"); + new InputStreamReader(new ByteArrayInputStream(VALID_NEW_XML_STRING.getBytes())), + fileNameToLibraryToContentIdMap, contentIdToFileContentMap); + + assertThat(fileNameToLibraryToContentIdMap).hasSize(2); + assertThat(fileNameToLibraryToContentIdMap.get("/file0")).hasSize(1); + assertThat(fileNameToLibraryToContentIdMap.get("/file1")).hasSize(1); + assertThat(fileNameToLibraryToContentIdMap.get("/file0").get("libA")).containsExactly("0"); + assertThat(fileNameToLibraryToContentIdMap.get("/file1").get("libB")).containsExactly("0"); assertThat(contentIdToFileContentMap.size()).isEqualTo(1); assertThat(contentIdToFileContentMap.get("0")).isEqualTo("license content #0"); } @Test(expected = XmlPullParserException.class) public void testParseInvalidXmlStream() throws XmlPullParserException, IOException { - Map<String, Set<String>> fileNameToContentIdMap = new HashMap<>(); + Map<String, Map<String, Set<String>>> fileNameToLibraryToContentIdMap = new HashMap<>(); Map<String, String> contentIdToFileContentMap = new HashMap<>(); LicenseHtmlGeneratorFromXml.parse( - new InputStreamReader(new ByteArrayInputStream(INVALILD_XML_STRING.getBytes())), - fileNameToContentIdMap, contentIdToFileContentMap); + new InputStreamReader(new ByteArrayInputStream(INVALID_XML_STRING.getBytes())), + fileNameToLibraryToContentIdMap, contentIdToFileContentMap); } @Test public void testGenerateHtml() { - Map<String, Set<String>> fileNameToContentIdMap = new HashMap<>(); + Map<String, Map<String, Set<String>>> fileNameToLibraryToContentIdMap = new HashMap<>(); + Map<String, String> contentIdToFileContentMap = new HashMap<>(); + Map<String, Set<String>> toBoth = new HashMap<>(); + Map<String, Set<String>> toOne = new HashMap<>(); + + toBoth.put("", new HashSet<String>(Arrays.asList("0", "1"))); + toOne.put("", new HashSet<String>(Arrays.asList("0"))); + + fileNameToLibraryToContentIdMap.put("/file0", toBoth); + fileNameToLibraryToContentIdMap.put("/file1", toOne); + contentIdToFileContentMap.put("0", "license content #0"); + contentIdToFileContentMap.put("1", "license content #1"); + + StringWriter output = new StringWriter(); + LicenseHtmlGeneratorFromXml.generateHtml( + fileNameToLibraryToContentIdMap, contentIdToFileContentMap, + new PrintWriter(output), ""); + assertThat(output.toString()).isEqualTo(EXPECTED_OLD_HTML_STRING); + } + + @Test + public void testGenerateNewHtml() { + Map<String, Map<String, Set<String>>> fileNameToLibraryToContentIdMap = new HashMap<>(); Map<String, String> contentIdToFileContentMap = new HashMap<>(); + Map<String, Set<String>> toBoth = new HashMap<>(); + Map<String, Set<String>> toOne = new HashMap<>(); + + toBoth.put("libA", new HashSet<String>(Arrays.asList("0"))); + toBoth.put("libB", new HashSet<String>(Arrays.asList("1"))); + toOne.put("libA", new HashSet<String>(Arrays.asList("0"))); - fileNameToContentIdMap.put("/file0", new HashSet<String>(Arrays.asList("0", "1"))); - fileNameToContentIdMap.put("/file1", new HashSet<String>(Arrays.asList("0"))); + fileNameToLibraryToContentIdMap.put("/file0", toBoth); + fileNameToLibraryToContentIdMap.put("/file1", toOne); contentIdToFileContentMap.put("0", "license content #0"); contentIdToFileContentMap.put("1", "license content #1"); StringWriter output = new StringWriter(); LicenseHtmlGeneratorFromXml.generateHtml( - fileNameToContentIdMap, contentIdToFileContentMap, new PrintWriter(output), ""); - assertThat(output.toString()).isEqualTo(EXPECTED_HTML_STRING); + fileNameToLibraryToContentIdMap, contentIdToFileContentMap, + new PrintWriter(output), ""); + assertThat(output.toString()).isEqualTo(EXPECTED_NEW_HTML_STRING); } @Test public void testGenerateHtmlWithCustomHeading() { - Map<String, Set<String>> fileNameToContentIdMap = new HashMap<>(); + Map<String, Map<String, Set<String>>> fileNameToLibraryToContentIdMap = new HashMap<>(); + Map<String, String> contentIdToFileContentMap = new HashMap<>(); + Map<String, Set<String>> toBoth = new HashMap<>(); + Map<String, Set<String>> toOne = new HashMap<>(); + + toBoth.put("", new HashSet<String>(Arrays.asList("0", "1"))); + toOne.put("", new HashSet<String>(Arrays.asList("0"))); + + fileNameToLibraryToContentIdMap.put("/file0", toBoth); + fileNameToLibraryToContentIdMap.put("/file1", toOne); + contentIdToFileContentMap.put("0", "license content #0"); + contentIdToFileContentMap.put("1", "license content #1"); + + StringWriter output = new StringWriter(); + LicenseHtmlGeneratorFromXml.generateHtml( + fileNameToLibraryToContentIdMap, contentIdToFileContentMap, + new PrintWriter(output), HTML_CUSTOM_HEADING); + assertThat(output.toString()).isEqualTo(EXPECTED_OLD_HTML_STRING_WITH_CUSTOM_HEADING); + } + + @Test + public void testGenerateNewHtmlWithCustomHeading() { + Map<String, Map<String, Set<String>>> fileNameToLibraryToContentIdMap = new HashMap<>(); Map<String, String> contentIdToFileContentMap = new HashMap<>(); + Map<String, Set<String>> toBoth = new HashMap<>(); + Map<String, Set<String>> toOne = new HashMap<>(); + + toBoth.put("libA", new HashSet<String>(Arrays.asList("0"))); + toBoth.put("libB", new HashSet<String>(Arrays.asList("1"))); + toOne.put("libA", new HashSet<String>(Arrays.asList("0"))); - fileNameToContentIdMap.put("/file0", new HashSet<String>(Arrays.asList("0", "1"))); - fileNameToContentIdMap.put("/file1", new HashSet<String>(Arrays.asList("0"))); + fileNameToLibraryToContentIdMap.put("/file0", toBoth); + fileNameToLibraryToContentIdMap.put("/file1", toOne); contentIdToFileContentMap.put("0", "license content #0"); contentIdToFileContentMap.put("1", "license content #1"); StringWriter output = new StringWriter(); LicenseHtmlGeneratorFromXml.generateHtml( - fileNameToContentIdMap, contentIdToFileContentMap, new PrintWriter(output), - HTML_CUSTOM_HEADING); - assertThat(output.toString()).isEqualTo(EXPECTED_HTML_STRING_WITH_CUSTOM_HEADING); + fileNameToLibraryToContentIdMap, contentIdToFileContentMap, + new PrintWriter(output), HTML_CUSTOM_HEADING); + assertThat(output.toString()).isEqualTo(EXPECTED_NEW_HTML_STRING_WITH_CUSTOM_HEADING); } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java index 6f7f73a3e79b..c122a37d0f79 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java @@ -31,6 +31,7 @@ import android.bluetooth.BluetoothDevice; import android.content.Context; import android.media.MediaRoute2Info; import android.media.MediaRouter2Manager; +import android.os.Parcel; import com.android.settingslib.bluetooth.A2dpProfile; import com.android.settingslib.bluetooth.CachedBluetoothDevice; @@ -65,9 +66,9 @@ public class MediaDeviceTest { private static final String ROUTER_ID_3 = "RouterId_3"; private static final String TEST_PACKAGE_NAME = "com.test.playmusic"; private final BluetoothClass mHeadreeClass = - new BluetoothClass(BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES); + createBtClass(BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES); private final BluetoothClass mCarkitClass = - new BluetoothClass(BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO); + createBtClass(BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO); @Mock private BluetoothDevice mDevice1; @@ -118,6 +119,16 @@ public class MediaDeviceTest { private List<MediaDevice> mMediaDevices = new ArrayList<>(); private PhoneMediaDevice mPhoneMediaDevice; + private BluetoothClass createBtClass(int deviceClass) { + Parcel p = Parcel.obtain(); + p.writeInt(deviceClass); + p.setDataPosition(0); // reset position of parcel before passing to constructor + + BluetoothClass bluetoothClass = BluetoothClass.CREATOR.createFromParcel(p); + p.recycle(); + return bluetoothClass; + } + @Before public void setUp() { MockitoAnnotations.initMocks(this); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageUtilsTest.java index b0a647e0dd2f..95f7ef41b10b 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageUtilsTest.java @@ -81,8 +81,8 @@ public class DataUsageUtilsTest { when(mSubscriptionManager.isActiveSubscriptionId(SUB_ID)).thenReturn(false); final NetworkTemplate networkTemplate = DataUsageUtils.getMobileTemplate(mContext, SUB_ID); - assertThat(networkTemplate.matchesSubscriberId(SUBSCRIBER_ID)).isTrue(); - assertThat(networkTemplate.matchesSubscriberId(SUBSCRIBER_ID_2)).isFalse(); + assertThat(networkTemplate.getSubscriberIds().contains(SUBSCRIBER_ID)).isTrue(); + assertThat(networkTemplate.getSubscriberIds().contains(SUBSCRIBER_ID_2)).isFalse(); } @Test @@ -94,8 +94,8 @@ public class DataUsageUtilsTest { .thenReturn(new String[] {SUBSCRIBER_ID}); final NetworkTemplate networkTemplate = DataUsageUtils.getMobileTemplate(mContext, SUB_ID); - assertThat(networkTemplate.matchesSubscriberId(SUBSCRIBER_ID)).isTrue(); - assertThat(networkTemplate.matchesSubscriberId(SUBSCRIBER_ID_2)).isFalse(); + assertThat(networkTemplate.getSubscriberIds().contains(SUBSCRIBER_ID)).isTrue(); + assertThat(networkTemplate.getSubscriberIds().contains(SUBSCRIBER_ID_2)).isFalse(); } @Test @@ -107,7 +107,7 @@ public class DataUsageUtilsTest { .thenReturn(new String[] {SUBSCRIBER_ID, SUBSCRIBER_ID_2}); final NetworkTemplate networkTemplate = DataUsageUtils.getMobileTemplate(mContext, SUB_ID); - assertThat(networkTemplate.matchesSubscriberId(SUBSCRIBER_ID)).isTrue(); - assertThat(networkTemplate.matchesSubscriberId(SUBSCRIBER_ID_2)).isTrue(); + assertThat(networkTemplate.getSubscriberIds().contains(SUBSCRIBER_ID)).isTrue(); + assertThat(networkTemplate.getSubscriberIds().contains(SUBSCRIBER_ID_2)).isTrue(); } } diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowBluetoothAdapter.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowBluetoothAdapter.java index 3b7fbc73522f..c7e96bcdb856 100644 --- a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowBluetoothAdapter.java +++ b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowBluetoothAdapter.java @@ -69,7 +69,7 @@ public class ShadowBluetoothAdapter extends org.robolectric.shadows.ShadowBlueto } @Implementation - protected boolean removeActiveDevice(@BluetoothAdapter.ActiveDeviceUse int profiles) { + protected boolean removeActiveDevice(int profiles) { if (profiles != ACTIVE_DEVICE_AUDIO && profiles != ACTIVE_DEVICE_PHONE_CALL && profiles != ACTIVE_DEVICE_ALL) { return false; @@ -78,8 +78,7 @@ public class ShadowBluetoothAdapter extends org.robolectric.shadows.ShadowBlueto } @Implementation - protected boolean setActiveDevice(BluetoothDevice device, - @BluetoothAdapter.ActiveDeviceUse int profiles) { + protected boolean setActiveDevice(BluetoothDevice device, int profiles) { if (device == null) { return false; } diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 5b2e8ae3e7de..ca4dcbbf230e 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -190,6 +190,9 @@ <uses-permission android:name="android.permission.REVOKE_RUNTIME_PERMISSIONS" /> <uses-permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS" /> <uses-permission android:name="android.permission.WHITELIST_RESTRICTED_PERMISSIONS" /> + <!-- Permission required for processes that don't own the focused window to switch + touch mode state --> + <uses-permission android:name="android.permission.MODIFY_TOUCH_MODE_STATE" /> <!-- Permission required to test onPermissionsChangedListener --> <uses-permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS" /> <uses-permission android:name="android.permission.SET_KEYBOARD_LAYOUT" /> @@ -504,7 +507,11 @@ <!-- Permission needed for CTS test - WifiManagerTest --> <uses-permission android:name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS" /> <uses-permission android:name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" /> + <uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" /> <uses-permission android:name="android.permission.OVERRIDE_WIFI_CONFIG" /> + <!-- Permission needed for CTS test - ConcurrencyTest#testP2pExternalApprover + P2P external approver API sets require MANAGE_WIFI_AUTO_JOIN permission. --> + <uses-permission android:name="android.permission.MANAGE_WIFI_AUTO_JOIN" /> <!-- Permission required for CTS tests to enable/disable rate limiting toasts. --> <uses-permission android:name="android.permission.MANAGE_TOAST_RATE_LIMITING" /> @@ -532,6 +539,7 @@ <!-- Permissions required for CTS test - TrustTestCases --> <uses-permission android:name="android.permission.PROVIDE_TRUST_AGENT" /> <uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" /> + <uses-permission android:name="android.permission.TRUST_LISTENER" /> <!-- Permission required for CTS test - CtsGameManagerTestCases --> <uses-permission android:name="android.permission.MANAGE_GAME_MODE" /> @@ -551,6 +559,9 @@ <uses-permission android:name="android.permission.MANAGE_APP_HIBERNATION"/> + <!-- Permission required for CTS test - MediaCodecResourceTest --> + <uses-permission android:name="android.permission.MEDIA_RESOURCE_OVERRIDE_PID" /> + <!-- Permission required for CTS test - ResourceObserverNativeTest --> <uses-permission android:name="android.permission.REGISTER_MEDIA_RESOURCE_OBSERVER" /> diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt index d3d6e03c9bc7..6f30ac3901e1 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt @@ -18,6 +18,7 @@ package com.android.systemui.controls.ui import android.annotation.MainThread import android.app.Dialog +import android.app.PendingIntent import android.content.Context import android.content.Intent import android.content.pm.PackageManager @@ -88,7 +89,7 @@ class ControlActionCoordinatorImpl @Inject constructor( bouncerOrRun(createAction(cvh.cws.ci.controlId, { cvh.layout.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK) if (cvh.usePanel()) { - showDetail(cvh, control.getAppIntent().getIntent()) + showDetail(cvh, control.getAppIntent()) } else { cvh.action(CommandAction(templateId)) } @@ -116,7 +117,7 @@ class ControlActionCoordinatorImpl @Inject constructor( // Long press snould only be called when there is valid control state, otherwise ignore cvh.cws.control?.let { cvh.layout.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) - showDetail(cvh, it.getAppIntent().getIntent()) + showDetail(cvh, it.getAppIntent()) } }, false /* blockable */)) } @@ -167,10 +168,10 @@ class ControlActionCoordinatorImpl @Inject constructor( bgExecutor.execute { vibrator.vibrate(effect) } } - private fun showDetail(cvh: ControlViewHolder, intent: Intent) { + private fun showDetail(cvh: ControlViewHolder, pendingIntent: PendingIntent) { bgExecutor.execute { val activities: List<ResolveInfo> = context.packageManager.queryIntentActivities( - intent, + pendingIntent.getIntent(), PackageManager.MATCH_DEFAULT_ONLY ) @@ -178,7 +179,7 @@ class ControlActionCoordinatorImpl @Inject constructor( // make sure the intent is valid before attempting to open the dialog if (activities.isNotEmpty() && taskViewFactory.isPresent) { taskViewFactory.get().create(context, uiExecutor, { - dialog = DetailDialog(activityContext, it, intent, cvh).also { + dialog = DetailDialog(activityContext, it, pendingIntent, cvh).also { it.setOnDismissListener { _ -> dialog = null } it.show() } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt index 8a47a36de8c4..4758ab04e2e5 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt @@ -43,7 +43,7 @@ import com.android.wm.shell.TaskView class DetailDialog( val activityContext: Context?, val taskView: TaskView, - val intent: Intent, + val pendingIntent: PendingIntent, val cvh: ControlViewHolder ) : Dialog( activityContext ?: cvh.context, @@ -59,6 +59,14 @@ class DetailDialog( var detailTaskId = INVALID_TASK_ID + private val fillInIntent = Intent().apply { + putExtra(EXTRA_USE_PANEL, true) + + // Apply flags to make behaviour match documentLaunchMode=always. + addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT) + addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK) + } + fun removeDetailTask() { if (detailTaskId == INVALID_TASK_ID) return ActivityTaskManager.getInstance().removeTask(detailTaskId) @@ -67,13 +75,6 @@ class DetailDialog( val stateCallback = object : TaskView.Listener { override fun onInitialized() { - val launchIntent = Intent(intent) - launchIntent.putExtra(EXTRA_USE_PANEL, true) - - // Apply flags to make behaviour match documentLaunchMode=always. - launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT) - launchIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK) - val options = activityContext?.let { ActivityOptions.makeCustomAnimation( it, @@ -82,9 +83,8 @@ class DetailDialog( ) } ?: ActivityOptions.makeBasic() taskView.startActivity( - PendingIntent.getActivity(context, 0, launchIntent, - PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE), - null /* fillInIntent */, + pendingIntent, + fillInIntent, options, getTaskViewBounds() ) @@ -97,6 +97,9 @@ class DetailDialog( override fun onTaskCreated(taskId: Int, name: ComponentName?) { detailTaskId = taskId + requireViewById<ViewGroup>(R.id.controls_activity_view).apply { + setAlpha(1f) + } } override fun onReleased() { @@ -121,6 +124,7 @@ class DetailDialog( requireViewById<ViewGroup>(R.id.controls_activity_view).apply { addView(taskView) + setAlpha(0f) } requireViewById<ImageView>(R.id.control_detail_close).apply { @@ -134,7 +138,7 @@ class DetailDialog( removeDetailTask() dismiss() context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) - v.context.startActivity(intent) + pendingIntent.send() } } diff --git a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseDialog.kt b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseDialog.kt index c50365f1bf38..71c5fad5322e 100644 --- a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseDialog.kt @@ -15,7 +15,8 @@ import com.android.systemui.statusbar.phone.SystemUIDialog class SensorUseDialog( context: Context, val sensor: Int, - val clickListener: DialogInterface.OnClickListener + val clickListener: DialogInterface.OnClickListener, + val dismissListener: DialogInterface.OnDismissListener ) : SystemUIDialog(context) { // TODO move to onCreate (b/200815309) @@ -69,6 +70,8 @@ class SensorUseDialog( context.getString(com.android.internal.R.string .cancel), clickListener) + setOnDismissListener(dismissListener) + setCancelable(false) } } diff --git a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt index b0071d92481d..dae375ad7cc7 100644 --- a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt @@ -50,7 +50,7 @@ class SensorUseStartedActivity @Inject constructor( private val keyguardStateController: KeyguardStateController, private val keyguardDismissUtil: KeyguardDismissUtil, @Background private val bgHandler: Handler -) : Activity(), DialogInterface.OnClickListener { +) : Activity(), DialogInterface.OnClickListener, DialogInterface.OnDismissListener { companion object { private val LOG_TAG = SensorUseStartedActivity::class.java.simpleName @@ -120,7 +120,7 @@ class SensorUseStartedActivity @Inject constructor( } } - mDialog = SensorUseDialog(this, sensor, this) + mDialog = SensorUseDialog(this, sensor, this, this) mDialog!!.show() } @@ -212,4 +212,8 @@ class SensorUseStartedActivity @Inject constructor( .suppressSensorPrivacyReminders(sensor, suppressed) } } + + override fun onDismiss(dialog: DialogInterface?) { + finish() + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java index e58ea7b8b5f3..eddc347dad45 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java @@ -234,7 +234,7 @@ public class InstantAppNotifier extends SystemUI ApplicationInfo appInfo = pm.getApplicationInfo( pkg, PackageManager.MATCH_UNINSTALLED_PACKAGES, info.userId); - if (appInfo.isInstantApp()) { + if (appInfo != null && appInfo.isInstantApp()) { postInstantAppNotif( pkg, info.userId, diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java index cd6a77836304..70e4fb523637 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java @@ -33,7 +33,6 @@ import android.media.AudioManager; import android.media.AudioSystem; import android.media.IAudioService; import android.media.IVolumeController; -import android.media.MediaRoute2Info; import android.media.MediaRouter2Manager; import android.media.RoutingSessionInfo; import android.media.VolumePolicy; @@ -462,11 +461,15 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa private boolean checkRoutedToBluetoothW(int stream) { boolean changed = false; if (stream == AudioManager.STREAM_MUSIC) { + // Note: Here we didn't use DEVICE_OUT_BLE_SPEAKER and DEVICE_OUT_BLE_BROADCAST + // Since their values overlap with DEVICE_OUT_EARPIECE and DEVICE_OUT_SPEAKER. + // Anyway, we can check BLE devices by using just DEVICE_OUT_BLE_HEADSET. final boolean routedToBluetooth = (mAudio.getDevicesForStream(AudioManager.STREAM_MUSIC) & (AudioManager.DEVICE_OUT_BLUETOOTH_A2DP | AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | - AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) != 0; + AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | + AudioManager.DEVICE_OUT_BLE_HEADSET)) != 0; changed |= updateStreamRoutedToBluetoothW(stream, routedToBluetooth); } return changed; diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt new file mode 100644 index 000000000000..87b9172dcefc --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2021 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 com.android.systemui.controls.ui + +import android.app.PendingIntent +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.wm.shell.TaskView +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.eq +import org.mockito.Mock +import org.mockito.Mockito.any +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper +class DetailDialogTest : SysuiTestCase() { + + @Mock + private lateinit var taskView: TaskView + @Mock + private lateinit var controlViewHolder: ControlViewHolder + @Mock + private lateinit var pendingIntent: PendingIntent + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + } + + @Test + fun testPendingIntentIsUnModified() { + // GIVEN the dialog is created with a PendingIntent + val dialog = createDialog(pendingIntent) + + // WHEN the TaskView is initialized + dialog.stateCallback.onInitialized() + + // THEN the PendingIntent used to call startActivity is unmodified by systemui + verify(taskView).startActivity(eq(pendingIntent), any(), any(), any()) + } + + private fun createDialog(pendingIntent: PendingIntent): DetailDialog { + return DetailDialog( + mContext, + taskView, + pendingIntent, + controlViewHolder + ) + } +} diff --git a/services/Android.bp b/services/Android.bp index 8947393849c1..e73032198343 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -42,7 +42,9 @@ system_optimized_java_defaults { SYSTEM_OPTIMIZE_JAVA: { optimize: { enabled: true, - optimize: true, + // TODO(b/210510433): Enable optimizations after improving + // retracing infra. + optimize: false, shrink: true, proguard_flags_files: ["proguard.flags"], }, @@ -176,10 +178,6 @@ cc_library_shared { name: "libandroid_servers", defaults: ["libservices.core-libs"], whole_static_libs: ["libservices.core"], - required: [ - // TODO: remove after NetworkStatsService is moved to the mainline module. - "libcom_android_net_module_util_jni", - ], } platform_compat_config { diff --git a/services/autofill/OWNERS b/services/autofill/OWNERS index c52751d79227..edfb2112198a 100644 --- a/services/autofill/OWNERS +++ b/services/autofill/OWNERS @@ -1 +1 @@ -include /core/java/android/service/autofill/OWNERS +include /core/java/android/view/autofill/OWNERS diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java index 30de4b416410..f6d05fa468e1 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java @@ -1569,7 +1569,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind } @Override - public void onDeviceDisconnected(BluetoothDevice device, @DisconnectReason int reason) { + public void onDeviceDisconnected(BluetoothDevice device, int reason) { Slog.d(LOG_TAG, device.getAddress() + " disconnected w/ reason: (" + reason + ") " + BluetoothAdapter.BluetoothConnectionCallback.disconnectReasonText(reason)); CompanionDeviceManagerService.this.onDeviceDisconnected(device.getAddress()); diff --git a/services/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java index 48f5b51a8404..26d76a848a02 100644 --- a/services/core/java/com/android/server/BootReceiver.java +++ b/services/core/java/com/android/server/BootReceiver.java @@ -51,15 +51,12 @@ import com.android.internal.util.XmlUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; -import java.io.BufferedReader; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStreamReader; -import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.regex.Matcher; @@ -128,11 +125,9 @@ public class BootReceiver extends BroadcastReceiver { // Location of ftrace pipe for notifications from kernel memory tools like KFENCE and KASAN. private static final String ERROR_REPORT_TRACE_PIPE = "/sys/kernel/tracing/instances/bootreceiver/trace_pipe"; - // Stop after sending this many reports. See http://b/182159975. + // Stop after sending too many reports. See http://b/182159975. private static final int MAX_ERROR_REPORTS = 8; private static int sSentReports = 0; - // Avoid reporing the same bug from processDmesg() twice. - private static String sLastReportedBug = null; @Override public void onReceive(final Context context, Intent intent) { @@ -175,7 +170,8 @@ public class BootReceiver extends BroadcastReceiver { * We read from /sys/kernel/tracing/instances/bootreceiver/trace_pipe (set up by the * system), which will print an ftrace event when a memory corruption is detected in the * kernel. - * When an error is detected, we run the dmesg shell command and process its output. + * When an error is detected, we set the dmesg.start system property to notify dmesgd + * about a new error. */ OnFileDescriptorEventListener traceCallback = new OnFileDescriptorEventListener() { final int mBufferSize = 1024; @@ -191,8 +187,7 @@ public class BootReceiver extends BroadcastReceiver { * line, but to be on the safe side we keep reading until the buffer * contains a '\n' character. In the unlikely case of a very buggy kernel * the buffer may contain multiple tracing events that cannot be attributed - * to particular error reports. In that case the latest error report - * residing in dmesg is picked. + * to particular error reports. dmesgd will take care of all errors. */ try { int nbytes = Os.read(fd, mTraceBuffer, 0, mBufferSize); @@ -201,10 +196,13 @@ public class BootReceiver extends BroadcastReceiver { if (readStr.indexOf("\n") == -1) { return OnFileDescriptorEventListener.EVENT_INPUT; } - processDmesg(context); + if (sSentReports < MAX_ERROR_REPORTS) { + SystemProperties.set("dmesgd.start", "1"); + sSentReports++; + } } } catch (Exception e) { - Slog.wtf(TAG, "Error processing dmesg output", e); + Slog.wtf(TAG, "Error watching for trace events", e); return 0; // Unregister the handler. } return OnFileDescriptorEventListener.EVENT_INPUT; @@ -216,157 +214,6 @@ public class BootReceiver extends BroadcastReceiver { } - /** - * Check whether it is safe to collect this dmesg line or not. - * - * We only consider lines belonging to KASAN or KFENCE reports, but those may still contain - * user information, namely the process name: - * - * [ 69.547684] [ T6006]c7 6006 CPU: 7 PID: 6006 Comm: sh Tainted: G S C O ... - * - * hardware information: - * - * [ 69.558923] [ T6006]c7 6006 Hardware name: <REDACTED> - * - * or register dump (in KASAN reports only): - * - * ... RIP: 0033:0x7f96443109da - * ... RSP: 002b:00007ffcf0b51b08 EFLAGS: 00000202 ORIG_RAX: 00000000000000af - * ... RAX: ffffffffffffffda RBX: 000055dc3ee521a0 RCX: 00007f96443109da - * - * (on x86_64) - * - * ... pc : lpm_cpuidle_enter+0x258/0x384 - * ... lr : lpm_cpuidle_enter+0x1d4/0x384 - * ... sp : ffffff800820bea0 - * ... x29: ffffff800820bea0 x28: ffffffc2305f3ce0 - * ... ... - * ... x9 : 0000000000000001 x8 : 0000000000000000 - * (on ARM64) - * - * We therefore omit the lines that contain "Comm:", "Hardware name:", or match the general - * purpose register regexp. - * - * @param line single line of `dmesg` output. - * @return updated line with sensitive data removed, or null if the line must be skipped. - */ - public static String stripSensitiveData(String line) { - /* - * General purpose register names begin with "R" on x86_64 and "x" on ARM64. The letter is - * followed by two symbols (numbers, letters or spaces) and a colon, which is followed by a - * 16-digit hex number. The optional "_" prefix accounts for ORIG_RAX on x86. - */ - final String registerRegex = "[ _][Rx]..: [0-9a-f]{16}"; - final Pattern registerPattern = Pattern.compile(registerRegex); - - final String corruptionRegex = "Detected corrupted memory at 0x[0-9a-f]+"; - final Pattern corruptionPattern = Pattern.compile(corruptionRegex); - - if (line.contains("Comm: ") || line.contains("Hardware name: ")) return null; - if (registerPattern.matcher(line).find()) return null; - - Matcher cm = corruptionPattern.matcher(line); - if (cm.find()) return cm.group(0); - return line; - } - - /* - * Search dmesg output for the last error report from KFENCE or KASAN and copy it to Dropbox. - * - * Example report printed by the kernel (redacted to fit into 100 column limit): - * [ 69.236673] [ T6006]c7 6006 ========================================================= - * [ 69.245688] [ T6006]c7 6006 BUG: KFENCE: out-of-bounds in kfence_handle_page_fault - * [ 69.245688] [ T6006]c7 6006 - * [ 69.257816] [ T6006]c7 6006 Out-of-bounds access at 0xffffffca75c45000 (...) - * [ 69.267102] [ T6006]c7 6006 kfence_handle_page_fault+0x1bc/0x208 - * [ 69.273536] [ T6006]c7 6006 __do_kernel_fault+0xa8/0x11c - * ... - * [ 69.355427] [ T6006]c7 6006 kfence-#2 [0xffffffca75c46f30-0xffffffca75c46fff, ... - * [ 69.366938] [ T6006]c7 6006 __d_alloc+0x3c/0x1b4 - * [ 69.371946] [ T6006]c7 6006 d_alloc_parallel+0x48/0x538 - * [ 69.377578] [ T6006]c7 6006 __lookup_slow+0x60/0x15c - * ... - * [ 69.547684] [ T6006]c7 6006 CPU: 7 PID: 6006 Comm: sh Tainted: G S C O ... - * [ 69.558923] [ T6006]c7 6006 Hardware name: <REDACTED> - * [ 69.567059] [ T6006]c7 6006 ========================================================= - * - * We rely on the kernel printing task/CPU ID for every log line (CONFIG_PRINTK_CALLER=y). - * E.g. for the above report the task ID is T6006. Report lines may interleave with lines - * printed by other kernel tasks, which will have different task IDs, so in order to collect - * the report we: - * - find the next occurrence of the "BUG: " line in the kernel log, parse it to obtain the - * task ID and the tool name; - * - scan the rest of dmesg output and pick every line that has the same task ID, until we - * encounter a horizontal ruler, i.e.: - * [ 69.567059] [ T6006]c7 6006 ====================================================== - * - add that line to the error report, unless it contains sensitive information (see - * logLinePotentiallySensitive()) - * - repeat the above steps till the last report is found. - */ - private void processDmesg(Context ctx) throws IOException { - if (sSentReports == MAX_ERROR_REPORTS) return; - /* - * Only SYSTEM_KASAN_ERROR_REPORT and SYSTEM_KFENCE_ERROR_REPORT are supported at the - * moment. - */ - final String[] bugTypes = new String[] { "KASAN", "KFENCE" }; - final String tsRegex = "^\\[[^]]+\\] "; - final String bugRegex = - tsRegex + "\\[([^]]+)\\].*BUG: (" + String.join("|", bugTypes) + "):"; - final Pattern bugPattern = Pattern.compile(bugRegex); - - Process p = new ProcessBuilder("/system/bin/timeout", "-k", "90s", "60s", - "dmesg").redirectErrorStream(true).start(); - BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); - String line = null; - String task = null; - String tool = null; - String bugTitle = null; - Pattern reportPattern = null; - ArrayList<String> currentReport = null; - String lastReport = null; - - while ((line = reader.readLine()) != null) { - if (currentReport == null) { - Matcher bm = bugPattern.matcher(line); - if (!bm.find()) continue; - task = bm.group(1); - tool = bm.group(2); - bugTitle = line; - currentReport = new ArrayList<String>(); - currentReport.add(line); - String reportRegex = tsRegex + "\\[" + task + "\\].*"; - reportPattern = Pattern.compile(reportRegex); - continue; - } - Matcher rm = reportPattern.matcher(line); - if (!rm.matches()) continue; - if ((line = stripSensitiveData(line)) == null) continue; - if (line.contains("================================")) { - lastReport = String.join("\n", currentReport); - currentReport = null; - continue; - } - currentReport.add(line); - } - if (lastReport == null) { - Slog.w(TAG, "Could not find report in dmesg."); - return; - } - - // Avoid sending the same bug report twice. - if (bugTitle.equals(sLastReportedBug)) return; - - final String reportTag = "SYSTEM_" + tool + "_ERROR_REPORT"; - final DropBoxManager db = ctx.getSystemService(DropBoxManager.class); - final String headers = getCurrentBootHeaders(); - final String reportText = headers + lastReport; - - addTextToDropBox(db, reportTag, reportText, "/dev/kmsg", LOG_SIZE); - sLastReportedBug = bugTitle; - sSentReports++; - } - private void removeOldUpdatePackages(Context context) { Downloads.removeAllDownloadsByPackage(context, OLD_UPDATER_PACKAGE, OLD_UPDATER_CLASS); } @@ -484,7 +331,9 @@ public class BootReceiver extends BroadcastReceiver { HashMap<String, Long> timestamps = readTimestamps(); try { if (proto) { - db.addFile(TAG_TOMBSTONE_PROTO, tombstone, 0); + if (recordFileTimestamp(tombstone, timestamps)) { + db.addFile(TAG_TOMBSTONE_PROTO, tombstone, 0); + } } else { final String headers = getBootHeadersToLogAndUpdate(); addFileToDropBox(db, timestamps, headers, tombstone.getPath(), LOG_SIZE, @@ -526,16 +375,10 @@ public class BootReceiver extends BroadcastReceiver { if (db == null || !db.isTagEnabled(tag)) return; // Logging disabled File file = new File(filename); - long fileTime = file.lastModified(); - if (fileTime <= 0) return; // File does not exist - - if (timestamps.containsKey(filename) && timestamps.get(filename) == fileTime) { - return; // Already logged this particular file + if (!recordFileTimestamp(file, timestamps)) { + return; } - timestamps.put(filename, fileTime); - - String fileContents = FileUtils.readTextFile(file, maxSize, TAG_TRUNCATED); String text = headers + fileContents + footers; // Create an additional report for system server native crashes, with a special tag. @@ -548,6 +391,19 @@ public class BootReceiver extends BroadcastReceiver { addTextToDropBox(db, tag, text, filename, maxSize); } + private static boolean recordFileTimestamp(File file, HashMap<String, Long> timestamps) { + final long fileTime = file.lastModified(); + if (fileTime <= 0) return false; // File does not exist + + final String filename = file.getPath(); + if (timestamps.containsKey(filename) && timestamps.get(filename) == fileTime) { + return false; // Already logged this particular file + } + + timestamps.put(filename, fileTime); + return true; + } + private static void addTextToDropBox(DropBoxManager db, String tag, String text, String filename, int maxSize) { Slog.i(TAG, "Copying " + filename + " to DropBox (" + tag + ")"); diff --git a/services/core/java/com/android/server/DiskStatsService.java b/services/core/java/com/android/server/DiskStatsService.java index 8ea3dd64697e..1095ba31069f 100644 --- a/services/core/java/com/android/server/DiskStatsService.java +++ b/services/core/java/com/android/server/DiskStatsService.java @@ -125,6 +125,8 @@ public class DiskStatsService extends Binder { DiskStatsFreeSpaceProto.FOLDER_CACHE); reportFreeSpace(new File("/system"), "System", pw, proto, DiskStatsFreeSpaceProto.FOLDER_SYSTEM); + reportFreeSpace(Environment.getMetadataDirectory(), "Metadata", pw, proto, + DiskStatsFreeSpaceProto.FOLDER_METADATA); boolean fileBased = StorageManager.isFileEncryptedNativeOnly(); boolean blockBased = fileBased ? false : StorageManager.isBlockEncrypted(); diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java index e29e894a5cc0..e924012c8892 100644 --- a/services/core/java/com/android/server/DynamicSystemService.java +++ b/services/core/java/com/android/server/DynamicSystemService.java @@ -16,8 +16,9 @@ package com.android.server; +import android.annotation.EnforcePermission; +import android.annotation.RequiresNoPermission; import android.content.Context; -import android.content.pm.PackageManager; import android.gsi.AvbPublicKey; import android.gsi.GsiProgress; import android.gsi.IGsiService; @@ -53,20 +54,12 @@ public class DynamicSystemService extends IDynamicSystemService.Stub { } private IGsiService getGsiService() { - checkPermission(); if (mGsiService != null) { return mGsiService; } return IGsiService.Stub.asInterface(ServiceManager.waitForService("gsiservice")); } - private void checkPermission() { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires MANAGE_DYNAMIC_SYSTEM permission"); - } - } - class GsiServiceCallback extends IGsiServiceCallback.Stub { // 0 for success private int mResult = -1; @@ -82,6 +75,7 @@ public class DynamicSystemService extends IDynamicSystemService.Stub { } @Override + @EnforcePermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) public boolean startInstallation(String dsuSlot) throws RemoteException { IGsiService service = getGsiService(); mGsiService = service; @@ -124,6 +118,7 @@ public class DynamicSystemService extends IDynamicSystemService.Stub { } @Override + @EnforcePermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) public boolean createPartition(String name, long size, boolean readOnly) throws RemoteException { IGsiService service = getGsiService(); @@ -135,6 +130,7 @@ public class DynamicSystemService extends IDynamicSystemService.Stub { } @Override + @EnforcePermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) public boolean closePartition() throws RemoteException { IGsiService service = getGsiService(); if (service.closePartition() != 0) { @@ -145,6 +141,7 @@ public class DynamicSystemService extends IDynamicSystemService.Stub { } @Override + @EnforcePermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) public boolean finishInstallation() throws RemoteException { IGsiService service = getGsiService(); if (service.closeInstall() != 0) { @@ -155,21 +152,25 @@ public class DynamicSystemService extends IDynamicSystemService.Stub { } @Override + @EnforcePermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) public GsiProgress getInstallationProgress() throws RemoteException { return getGsiService().getInstallProgress(); } @Override + @EnforcePermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) public boolean abort() throws RemoteException { return getGsiService().cancelGsiInstall(); } @Override + @RequiresNoPermission public boolean isInUse() { return SystemProperties.getBoolean("ro.gsid.image_running", false); } @Override + @RequiresNoPermission public boolean isInstalled() { boolean installed = SystemProperties.getBoolean("gsid.image_installed", false); Slog.i(TAG, "isInstalled(): " + installed); @@ -177,11 +178,13 @@ public class DynamicSystemService extends IDynamicSystemService.Stub { } @Override + @EnforcePermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) public boolean isEnabled() throws RemoteException { return getGsiService().isGsiEnabled(); } @Override + @EnforcePermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) public boolean remove() throws RemoteException { try { GsiServiceCallback callback = new GsiServiceCallback(); @@ -197,6 +200,7 @@ public class DynamicSystemService extends IDynamicSystemService.Stub { } @Override + @EnforcePermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) public boolean setEnable(boolean enable, boolean oneShot) throws RemoteException { IGsiService gsiService = getGsiService(); if (enable) { @@ -220,6 +224,7 @@ public class DynamicSystemService extends IDynamicSystemService.Stub { } @Override + @EnforcePermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) public boolean setAshmem(ParcelFileDescriptor ashmem, long size) { try { return getGsiService().setGsiAshmem(ashmem, size); @@ -229,6 +234,7 @@ public class DynamicSystemService extends IDynamicSystemService.Stub { } @Override + @EnforcePermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) public boolean submitFromAshmem(long size) { try { return getGsiService().commitGsiChunkFromAshmem(size); @@ -238,6 +244,7 @@ public class DynamicSystemService extends IDynamicSystemService.Stub { } @Override + @EnforcePermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) public boolean getAvbPublicKey(AvbPublicKey dst) { try { return getGsiService().getAvbPublicKey(dst) == 0; @@ -247,6 +254,7 @@ public class DynamicSystemService extends IDynamicSystemService.Stub { } @Override + @EnforcePermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) public long suggestScratchSize() throws RemoteException { return getGsiService().suggestScratchSize(); } diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 39ac5effe6fa..b59cd4c0f212 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -21,6 +21,7 @@ import static android.Manifest.permission.NETWORK_SETTINGS; import static android.Manifest.permission.OBSERVE_NETWORK_POLICY; import static android.Manifest.permission.SHUTDOWN; import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE; +import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY; import static android.net.ConnectivityManager.FIREWALL_CHAIN_POWERSAVE; import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED; import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY; @@ -30,6 +31,7 @@ import static android.net.INetd.FIREWALL_DENYLIST; import static android.net.INetd.FIREWALL_RULE_ALLOW; import static android.net.INetd.FIREWALL_RULE_DENY; import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE; +import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_LOW_POWER_STANDBY; import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_POWERSAVE; import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_RESTRICTED; import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY; @@ -206,6 +208,11 @@ public class NetworkManagementService extends INetworkManagementService.Stub { */ @GuardedBy("mRulesLock") private SparseIntArray mUidFirewallRestrictedRules = new SparseIntArray(); + /** + * Contains the per-UID firewall rules that are used when Low Power Standby is enabled. + */ + @GuardedBy("mRulesLock") + private SparseIntArray mUidFirewallLowPowerStandbyRules = new SparseIntArray(); /** Set of states for the child firewall chains. True if the chain is active. */ @GuardedBy("mRulesLock") final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray(); @@ -506,12 +513,14 @@ public class NetworkManagementService extends INetworkManagementService.Stub { syncFirewallChainLocked(FIREWALL_CHAIN_DOZABLE, "dozable "); syncFirewallChainLocked(FIREWALL_CHAIN_POWERSAVE, "powersave "); syncFirewallChainLocked(FIREWALL_CHAIN_RESTRICTED, "restricted "); + syncFirewallChainLocked(FIREWALL_CHAIN_LOW_POWER_STANDBY, "low power standby "); final int[] chains = { FIREWALL_CHAIN_STANDBY, FIREWALL_CHAIN_DOZABLE, FIREWALL_CHAIN_POWERSAVE, - FIREWALL_CHAIN_RESTRICTED + FIREWALL_CHAIN_RESTRICTED, + FIREWALL_CHAIN_LOW_POWER_STANDBY }; for (int chain : chains) { @@ -1438,6 +1447,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub { return FIREWALL_CHAIN_NAME_POWERSAVE; case FIREWALL_CHAIN_RESTRICTED: return FIREWALL_CHAIN_NAME_RESTRICTED; + case FIREWALL_CHAIN_LOW_POWER_STANDBY: + return FIREWALL_CHAIN_NAME_LOW_POWER_STANDBY; default: throw new IllegalArgumentException("Bad child chain: " + chain); } @@ -1453,6 +1464,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub { return FIREWALL_ALLOWLIST; case FIREWALL_CHAIN_RESTRICTED: return FIREWALL_ALLOWLIST; + case FIREWALL_CHAIN_LOW_POWER_STANDBY: + return FIREWALL_ALLOWLIST; default: return isFirewallEnabled() ? FIREWALL_ALLOWLIST : FIREWALL_DENYLIST; } @@ -1571,6 +1584,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub { return mUidFirewallPowerSaveRules; case FIREWALL_CHAIN_RESTRICTED: return mUidFirewallRestrictedRules; + case FIREWALL_CHAIN_LOW_POWER_STANDBY: + return mUidFirewallLowPowerStandbyRules; case FIREWALL_CHAIN_NONE: return mUidFirewallRules; default: @@ -1626,6 +1641,11 @@ public class NetworkManagementService extends INetworkManagementService.Stub { pw.println(getFirewallChainState(FIREWALL_CHAIN_RESTRICTED)); dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_RESTRICTED, mUidFirewallRestrictedRules); + + pw.print("UID firewall low power standby chain enabled: "); + pw.println(getFirewallChainState(FIREWALL_CHAIN_LOW_POWER_STANDBY)); + dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_LOW_POWER_STANDBY, + mUidFirewallLowPowerStandbyRules); } pw.print("Firewall enabled: "); pw.println(mFirewallEnabled); @@ -1749,6 +1769,11 @@ public class NetworkManagementService extends INetworkManagementService.Stub { if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of restricted mode"); return true; } + if (getFirewallChainState(FIREWALL_CHAIN_LOW_POWER_STANDBY) + && mUidFirewallLowPowerStandbyRules.get(uid) != FIREWALL_RULE_ALLOW) { + if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of low power standby"); + return true; + } if (mUidRejectOnMetered.get(uid)) { if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of no metered data" + " in the background"); diff --git a/services/core/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java index ff2308c35b9f..1e534b7c1515 100644 --- a/services/core/java/com/android/server/NetworkTimeUpdateService.java +++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java @@ -16,6 +16,7 @@ package com.android.server; +import android.annotation.NonNull; import android.app.AlarmManager; import android.app.PendingIntent; import android.app.timedetector.NetworkTimeSuggestion; @@ -35,11 +36,15 @@ import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.os.PowerManager; +import android.os.ResultReceiver; +import android.os.ShellCallback; import android.os.SystemClock; import android.os.TimestampedValue; import android.provider.Settings; +import android.util.LocalLog; import android.util.Log; import android.util.NtpTrustedTime; +import android.util.NtpTrustedTime.TimeResult; import android.util.TimeUtils; import com.android.internal.util.DumpUtils; @@ -95,6 +100,13 @@ public class NetworkTimeUpdateService extends Binder { // connection to happen. private int mTryAgainCounter; + /** + * A log that records the decisions to fetch a network time update. + * This is logged in bug reports to assist with debugging issues with network time suggestions. + */ + @NonNull + private final LocalLog mLocalLog = new LocalLog(30, false /* useLocalTimestamps */); + public NetworkTimeUpdateService(Context context) { mContext = context; mTime = NtpTrustedTime.getInstance(context); @@ -143,6 +155,42 @@ public class NetworkTimeUpdateService extends Binder { }, new IntentFilter(ACTION_POLL)); } + /** + * Clears the cached NTP time. For use during tests to simulate when no NTP time is available. + * + * <p>This operation takes place in the calling thread rather than the service's handler thread. + */ + void clearTimeForTests() { + mContext.enforceCallingPermission( + android.Manifest.permission.SET_TIME, "clear latest network time"); + + mTime.clearCachedTimeResult(); + + mLocalLog.log("clearTimeForTests"); + } + + /** + * Forces the service to refresh the NTP time. + * + * <p>This operation takes place in the calling thread rather than the service's handler thread. + * This method does not affect currently scheduled refreshes. If the NTP request is successful + * it will make an (asynchronously handled) suggestion to the time detector. + */ + boolean forceRefreshForTests() { + mContext.enforceCallingPermission( + android.Manifest.permission.SET_TIME, "force network time refresh"); + + boolean success = mTime.forceRefresh(); + mLocalLog.log("forceRefreshForTests: success=" + success); + + if (success) { + makeNetworkTimeSuggestion(mTime.getCachedTimeResult(), + "Origin: NetworkTimeUpdateService: forceRefreshForTests"); + } + + return success; + } + private void onPollNetworkTime(int event) { // If we don't have any default network, don't bother. if (mDefaultNetwork == null) return; @@ -155,24 +203,37 @@ public class NetworkTimeUpdateService extends Binder { } private void onPollNetworkTimeUnderWakeLock(int event) { + long currentElapsedRealtimeMillis = SystemClock.elapsedRealtime(); // Force an NTP fix when outdated NtpTrustedTime.TimeResult cachedNtpResult = mTime.getCachedTimeResult(); - if (cachedNtpResult == null || cachedNtpResult.getAgeMillis() >= mPollingIntervalMs) { + if (cachedNtpResult == null || cachedNtpResult.getAgeMillis(currentElapsedRealtimeMillis) + >= mPollingIntervalMs) { if (DBG) Log.d(TAG, "Stale NTP fix; forcing refresh"); - mTime.forceRefresh(); + boolean isSuccessful = mTime.forceRefresh(); + if (isSuccessful) { + mTryAgainCounter = 0; + } else { + String logMsg = "forceRefresh() returned false: cachedNtpResult=" + cachedNtpResult + + ", currentElapsedRealtimeMillis=" + currentElapsedRealtimeMillis; + + if (DBG) { + Log.d(TAG, logMsg); + } + mLocalLog.log(logMsg); + } + cachedNtpResult = mTime.getCachedTimeResult(); } - if (cachedNtpResult != null && cachedNtpResult.getAgeMillis() < mPollingIntervalMs) { + if (cachedNtpResult != null + && cachedNtpResult.getAgeMillis(currentElapsedRealtimeMillis) + < mPollingIntervalMs) { // Obtained fresh fix; schedule next normal update - resetAlarm(mPollingIntervalMs); - - // Suggest the time to the time detector. It may choose use it to set the system clock. - TimestampedValue<Long> timeSignal = new TimestampedValue<>( - cachedNtpResult.getElapsedRealtimeMillis(), cachedNtpResult.getTimeMillis()); - NetworkTimeSuggestion timeSuggestion = new NetworkTimeSuggestion(timeSignal); - timeSuggestion.addDebugInfo("Origin: NetworkTimeUpdateService. event=" + event); - mTimeDetector.suggestNetworkTime(timeSuggestion); + resetAlarm(mPollingIntervalMs + - cachedNtpResult.getAgeMillis(currentElapsedRealtimeMillis)); + + makeNetworkTimeSuggestion(cachedNtpResult, + "Origin: NetworkTimeUpdateService. event=" + event); } else { // No fresh fix; schedule retry mTryAgainCounter++; @@ -180,12 +241,26 @@ public class NetworkTimeUpdateService extends Binder { resetAlarm(mPollingIntervalShorterMs); } else { // Try much later + String logMsg = "mTryAgainTimesMax exceeded, cachedNtpResult=" + cachedNtpResult; + if (DBG) { + Log.d(TAG, logMsg); + } + mLocalLog.log(logMsg); mTryAgainCounter = 0; resetAlarm(mPollingIntervalMs); } } } + /** Suggests the time to the time detector. It may choose use it to set the system clock. */ + private void makeNetworkTimeSuggestion(TimeResult ntpResult, String debugInfo) { + TimestampedValue<Long> timeSignal = new TimestampedValue<>( + ntpResult.getElapsedRealtimeMillis(), ntpResult.getTimeMillis()); + NetworkTimeSuggestion timeSuggestion = new NetworkTimeSuggestion(timeSignal); + timeSuggestion.addDebugInfo(debugInfo); + mTimeDetector.suggestNetworkTime(timeSuggestion); + } + /** * Cancel old alarm and starts a new one for the specified interval. * @@ -285,6 +360,15 @@ public class NetworkTimeUpdateService extends Binder { if (ntpResult != null) { pw.println("NTP result age: " + ntpResult.getAgeMillis()); } + pw.println("Local logs:"); + mLocalLog.dump(fd, pw, args); pw.println(); } + + @Override + public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, + String[] args, ShellCallback callback, ResultReceiver resultReceiver) { + new NetworkTimeUpdateServiceShellCommand(this).exec( + this, in, out, err, args, callback, resultReceiver); + } } diff --git a/services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java b/services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java new file mode 100644 index 000000000000..dc93023d82c5 --- /dev/null +++ b/services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2022 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 com.android.server; + +import android.annotation.NonNull; +import android.os.ShellCommand; + +import java.io.PrintWriter; +import java.util.Objects; + +/** Implements the shell command interface for {@link NetworkTimeUpdateService}. */ +class NetworkTimeUpdateServiceShellCommand extends ShellCommand { + + /** + * The name of the service. + */ + private static final String SHELL_COMMAND_SERVICE_NAME = "network_time_update_service"; + + /** + * A shell command that clears the time signal received from the network. + */ + private static final String SHELL_COMMAND_CLEAR_TIME = "clear_time"; + + /** + * A shell command that forces the time signal to be refreshed from the network. + */ + private static final String SHELL_COMMAND_FORCE_REFRESH = "force_refresh"; + + @NonNull + private final NetworkTimeUpdateService mNetworkTimeUpdateService; + + NetworkTimeUpdateServiceShellCommand(NetworkTimeUpdateService networkTimeUpdateService) { + mNetworkTimeUpdateService = Objects.requireNonNull(networkTimeUpdateService); + } + + @Override + public int onCommand(String cmd) { + if (cmd == null) { + return handleDefaultCommands(cmd); + } + + switch (cmd) { + case SHELL_COMMAND_CLEAR_TIME: + return runClearTime(); + case SHELL_COMMAND_FORCE_REFRESH: + return runForceRefresh(); + default: { + return handleDefaultCommands(cmd); + } + } + } + + private int runClearTime() { + mNetworkTimeUpdateService.clearTimeForTests(); + return 0; + } + + private int runForceRefresh() { + boolean success = mNetworkTimeUpdateService.forceRefreshForTests(); + getOutPrintWriter().println(success); + return 0; + } + + @Override + public void onHelp() { + final PrintWriter pw = getOutPrintWriter(); + pw.printf("Network Time Update Service (%s) commands:\n", SHELL_COMMAND_SERVICE_NAME); + pw.printf(" help\n"); + pw.printf(" Print this help text.\n"); + pw.printf(" %s\n", SHELL_COMMAND_CLEAR_TIME); + pw.printf(" Clears the latest time.\n"); + pw.printf(" %s\n", SHELL_COMMAND_FORCE_REFRESH); + pw.printf(" Refreshes the latest time. Prints whether it was successful.\n"); + pw.println(); + } +} diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS index 71b463a4db8c..f4b8f5ddda66 100644 --- a/services/core/java/com/android/server/OWNERS +++ b/services/core/java/com/android/server/OWNERS @@ -23,14 +23,13 @@ per-file *Alarm* = file:/apex/jobscheduler/OWNERS per-file *AppOp* = file:/core/java/android/permission/OWNERS per-file *Battery* = file:/BATTERY_STATS_OWNERS per-file *Binder* = file:/core/java/com/android/internal/os/BINDER_OWNERS -per-file *Bluetooth* = file:/core/java/android/bluetooth/OWNERS per-file *Gnss* = file:/services/core/java/com/android/server/location/OWNERS per-file **IpSec* = file:/services/core/java/com/android/server/net/OWNERS per-file **IpSec* = file:/services/core/java/com/android/server/vcn/OWNERS per-file *Location* = file:/services/core/java/com/android/server/location/OWNERS per-file *Network* = file:/services/core/java/com/android/server/net/OWNERS per-file *Storage* = file:/core/java/android/os/storage/OWNERS -per-file *TimeUpdate* = file:/core/java/android/app/timezone/OWNERS +per-file *TimeUpdate* = file:/services/core/java/com/android/server/timezonedetector/OWNERS per-file DynamicSystemService.java = file:/packages/DynamicSystemInstallationService/OWNERS per-file GestureLauncherService.java = file:platform/packages/apps/EmergencyInfo:/OWNERS per-file MmsServiceBroker.java = file:/telephony/OWNERS diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java index 3cc8e7672557..f36d11eac8f2 100644 --- a/services/core/java/com/android/server/SystemServiceManager.java +++ b/services/core/java/com/android/server/SystemServiceManager.java @@ -20,6 +20,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; import android.content.pm.UserInfo; import android.os.Environment; import android.os.SystemClock; @@ -34,6 +36,7 @@ import com.android.internal.os.SystemServerClassLoaderFactory; import com.android.internal.util.Preconditions; import com.android.server.SystemService.TargetUser; import com.android.server.am.EventLogTags; +import com.android.server.pm.ApexManager; import com.android.server.pm.UserManagerInternal; import com.android.server.utils.TimingsTraceAndSlog; @@ -42,6 +45,8 @@ import dalvik.system.PathClassLoader; import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; /** @@ -114,12 +119,31 @@ public final class SystemServiceManager implements Dumpable { * @return The service instance. */ public SystemService startServiceFromJar(String className, String path) { - PathClassLoader pathClassLoader = SystemServerClassLoaderFactory.getOrCreateClassLoader( - path, this.getClass().getClassLoader()); + PathClassLoader pathClassLoader = + SystemServerClassLoaderFactory.getOrCreateClassLoader( + path, this.getClass().getClassLoader(), isJarInTestApex(path)); final Class<SystemService> serviceClass = loadClassFromLoader(className, pathClassLoader); return startService(serviceClass); } + /** + * Returns true if the jar is in a test APEX. + */ + private static boolean isJarInTestApex(String pathStr) { + Path path = Paths.get(pathStr); + if (path.getNameCount() >= 2 && path.getName(0).toString().equals("apex")) { + String apexModuleName = path.getName(1).toString(); + ApexManager apexManager = ApexManager.getInstance(); + String packageName = apexManager.getActivePackageNameForApexModuleName(apexModuleName); + PackageInfo packageInfo = apexManager.getPackageInfo( + packageName, ApexManager.MATCH_ACTIVE_PACKAGE); + if (packageInfo != null) { + return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_TEST_ONLY) != 0; + } + } + return false; + } + /* * Loads and initializes a class from the given classLoader. Returns the class. */ diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java index 6a7afd90dc96..2d328d8b0949 100644 --- a/services/core/java/com/android/server/VcnManagementService.java +++ b/services/core/java/com/android/server/VcnManagementService.java @@ -539,7 +539,13 @@ public class VcnManagementService extends IVcnManagementService.Stub { @GuardedBy("mLock") private void notifyAllPolicyListenersLocked() { for (final PolicyListenerBinderDeath policyListener : mRegisteredPolicyListeners.values()) { - Binder.withCleanCallingIdentity(() -> policyListener.mListener.onPolicyChanged()); + Binder.withCleanCallingIdentity(() -> { + try { + policyListener.mListener.onPolicyChanged(); + } catch (RemoteException e) { + logDbg("VcnStatusCallback threw on VCN status change", e); + } + }); } } @@ -548,8 +554,13 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull ParcelUuid subGroup, @VcnStatusCode int statusCode) { for (final VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) { if (isCallbackPermissioned(cbInfo, subGroup)) { - Binder.withCleanCallingIdentity( - () -> cbInfo.mCallback.onVcnStatusChanged(statusCode)); + Binder.withCleanCallingIdentity(() -> { + try { + cbInfo.mCallback.onVcnStatusChanged(statusCode); + } catch (RemoteException e) { + logDbg("VcnStatusCallback threw on VCN status change", e); + } + }); } } } @@ -1222,13 +1233,17 @@ public class VcnManagementService extends IVcnManagementService.Stub { // Notify all registered StatusCallbacks for this subGroup for (VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) { if (isCallbackPermissioned(cbInfo, mSubGroup)) { - Binder.withCleanCallingIdentity( - () -> - cbInfo.mCallback.onGatewayConnectionError( - gatewayConnectionName, - errorCode, - exceptionClass, - exceptionMessage)); + Binder.withCleanCallingIdentity(() -> { + try { + cbInfo.mCallback.onGatewayConnectionError( + gatewayConnectionName, + errorCode, + exceptionClass, + exceptionMessage); + } catch (RemoteException e) { + logDbg("VcnStatusCallback threw on VCN status change", e); + } + }); } } } diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java index b48e21e4e2c6..7b8cce54c8a7 100644 --- a/services/core/java/com/android/server/VpnManagerService.java +++ b/services/core/java/com/android/server/VpnManagerService.java @@ -340,17 +340,18 @@ public class VpnManagerService extends IVpnManager.Stub { * <p>This is designed to serve the VpnManager only; settings-based VPN profiles are managed * exclusively by the Settings app, and passed into the platform at startup time. * + * @return A unique key corresponding to this session. * @throws IllegalArgumentException if no profile was found for the given package name. * @hide */ @Override - public void startVpnProfile(@NonNull String packageName) { + public String startVpnProfile(@NonNull String packageName) { final int callingUid = Binder.getCallingUid(); verifyCallingUidAndPackage(packageName, callingUid); final int user = UserHandle.getUserId(callingUid); synchronized (mVpns) { throwIfLockdownEnabled(); - mVpns.get(user).startVpnProfile(packageName); + return mVpns.get(user).startVpnProfile(packageName); } } diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java index 6230919d8d2d..583fb8950ccf 100644 --- a/services/core/java/com/android/server/am/CachedAppOptimizer.java +++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java @@ -191,7 +191,9 @@ public final class CachedAppOptimizer { } else if (KEY_COMPACT_THROTTLE_1.equals(name) || KEY_COMPACT_THROTTLE_2.equals(name) || KEY_COMPACT_THROTTLE_3.equals(name) - || KEY_COMPACT_THROTTLE_4.equals(name)) { + || KEY_COMPACT_THROTTLE_4.equals(name) + || KEY_COMPACT_THROTTLE_5.equals(name) + || KEY_COMPACT_THROTTLE_6.equals(name)) { updateCompactionThrottles(); } else if (KEY_COMPACT_STATSD_SAMPLE_RATE.equals(name)) { updateCompactStatsdSampleRate(); diff --git a/services/core/java/com/android/server/am/DataConnectionStats.java b/services/core/java/com/android/server/am/DataConnectionStats.java index 6e39a4c802d9..651e98c602d9 100644 --- a/services/core/java/com/android/server/am/DataConnectionStats.java +++ b/services/core/java/com/android/server/am/DataConnectionStats.java @@ -73,7 +73,8 @@ public class DataConnectionStats extends BroadcastReceiver { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_SIM_STATE_CHANGED); - mContext.registerReceiver(this, filter, null /* broadcastPermission */, mListenerHandler); + mContext.registerReceiver(this, filter, null /* broadcastPermission */, mListenerHandler, + Context.RECEIVER_NOT_EXPORTED); } @Override diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 2eb59b28c3e9..54987cf04a50 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -29,7 +29,7 @@ import android.media.AudioDeviceInfo; import android.media.AudioManager; import android.media.AudioRoutesInfo; import android.media.AudioSystem; -import android.media.BtProfileConnectionInfo; +import android.media.BluetoothProfileConnectionInfo; import android.media.IAudioRoutesObserver; import android.media.ICapturePresetDevicesRoleDispatcher; import android.media.ICommunicationDeviceDispatcher; @@ -517,12 +517,12 @@ import java.util.concurrent.atomic.AtomicBoolean; /*package*/ static final class BtDeviceChangedData { final @Nullable BluetoothDevice mNewDevice; final @Nullable BluetoothDevice mPreviousDevice; - final @NonNull BtProfileConnectionInfo mInfo; + final @NonNull BluetoothProfileConnectionInfo mInfo; final @NonNull String mEventSource; BtDeviceChangedData(@Nullable BluetoothDevice newDevice, @Nullable BluetoothDevice previousDevice, - @NonNull BtProfileConnectionInfo info, @NonNull String eventSource) { + @NonNull BluetoothProfileConnectionInfo info, @NonNull String eventSource) { mNewDevice = newDevice; mPreviousDevice = previousDevice; mInfo = info; @@ -554,9 +554,9 @@ import java.util.concurrent.atomic.AtomicBoolean; mDevice = device; mState = state; mProfile = d.mInfo.getProfile(); - mSupprNoisy = d.mInfo.getSuppressNoisyIntent(); + mSupprNoisy = d.mInfo.isSuppressNoisyIntent(); mVolume = d.mInfo.getVolume(); - mIsLeOutput = d.mInfo.getIsLeOutput(); + mIsLeOutput = d.mInfo.isLeOutput(); mEventSource = d.mEventSource; mAudioSystemDevice = audioDevice; mMusicDevice = AudioSystem.DEVICE_NONE; @@ -627,7 +627,7 @@ import java.util.concurrent.atomic.AtomicBoolean; audioDevice = AudioSystem.DEVICE_OUT_HEARING_AID; break; case BluetoothProfile.LE_AUDIO: - if (d.mInfo.getIsLeOutput()) { + if (d.mInfo.isLeOutput()) { audioDevice = AudioSystem.DEVICE_OUT_BLE_HEADSET; } else { audioDevice = AudioSystem.DEVICE_IN_BLE_HEADSET; diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index e00c8a39074a..4c56381bbeec 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -83,7 +83,7 @@ import android.media.AudioPlaybackConfiguration; import android.media.AudioRecordingConfiguration; import android.media.AudioRoutesInfo; import android.media.AudioSystem; -import android.media.BtProfileConnectionInfo; +import android.media.BluetoothProfileConnectionInfo; import android.media.IAudioFocusDispatcher; import android.media.IAudioModeDispatcher; import android.media.IAudioRoutesObserver; @@ -2817,8 +2817,9 @@ public class AudioService extends IAudioService.Stub int step; // skip a2dp absolute volume control request when the device - // is not an a2dp device - if (!AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device) + // is neither an a2dp device nor BLE device + if ((!AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device) + && !AudioSystem.DEVICE_OUT_ALL_BLE_SET.contains(device)) && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) { return; } @@ -2958,7 +2959,8 @@ public class AudioService extends IAudioService.Stub } if (device == AudioSystem.DEVICE_OUT_BLE_HEADSET - && streamType == getBluetoothContextualVolumeStream()) { + && streamType == getBluetoothContextualVolumeStream() + && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) { if (DEBUG_VOL) { Log.d(TAG, "adjustSreamVolume postSetLeAudioVolumeIndex index=" + newIndex + " stream=" + streamType); @@ -3559,8 +3561,9 @@ public class AudioService extends IAudioService.Stub int oldIndex; // skip a2dp absolute volume control request when the device - // is not an a2dp device - if (!AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device) + // is neither an a2dp device nor BLE device + if ((!AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device) + && !AudioSystem.DEVICE_OUT_ALL_BLE_SET.contains(device)) && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) { return; } @@ -3602,7 +3605,8 @@ public class AudioService extends IAudioService.Stub } if (device == AudioSystem.DEVICE_OUT_BLE_HEADSET - && streamType == getBluetoothContextualVolumeStream()) { + && streamType == getBluetoothContextualVolumeStream() + && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) { if (DEBUG_VOL) { Log.d(TAG, "adjustSreamVolume postSetLeAudioVolumeIndex index=" + index + " stream=" + streamType); @@ -6301,14 +6305,14 @@ public class AudioService extends IAudioService.Stub * See AudioManager.handleBluetoothActiveDeviceChanged(...) */ public void handleBluetoothActiveDeviceChanged(BluetoothDevice newDevice, - BluetoothDevice previousDevice, @NonNull BtProfileConnectionInfo info) { + BluetoothDevice previousDevice, @NonNull BluetoothProfileConnectionInfo info) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.BLUETOOTH_STACK) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Bluetooth is the only caller allowed"); } if (info == null) { - throw new IllegalArgumentException("Illegal null BtProfileConnectionInfo for device " - + previousDevice + " -> " + newDevice); + throw new IllegalArgumentException("Illegal null BluetoothProfileConnectionInfo for" + + " device " + previousDevice + " -> " + newDevice); } final int profile = info.getProfile(); if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java index 9273a5d5cf9c..4485c5b6d61a 100644 --- a/services/core/java/com/android/server/audio/BtHelper.java +++ b/services/core/java/com/android/server/audio/BtHelper.java @@ -31,7 +31,7 @@ import android.content.Intent; import android.media.AudioDeviceAttributes; import android.media.AudioManager; import android.media.AudioSystem; -import android.media.BtProfileConnectionInfo; +import android.media.BluetoothProfileConnectionInfo; import android.os.Binder; import android.os.UserHandle; import android.provider.Settings; @@ -102,8 +102,6 @@ public class BtHelper { /*package*/ static final int SCO_MODE_UNDEFINED = -1; // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall()) /*package*/ static final int SCO_MODE_VIRTUAL_CALL = 0; - // SCO audio mode is raw audio (BluetoothHeadset.connectAudio()) - private static final int SCO_MODE_RAW = 1; // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition()) private static final int SCO_MODE_VR = 2; // max valid SCO audio mode values @@ -122,8 +120,6 @@ public class BtHelper { return "SCO_MODE_UNDEFINED"; case SCO_MODE_VIRTUAL_CALL: return "SCO_MODE_VIRTUAL_CALL"; - case SCO_MODE_RAW: - return "SCO_MODE_RAW"; case SCO_MODE_VR: return "SCO_MODE_VR"; default: @@ -482,6 +478,8 @@ public class BtHelper { } if (profile == BluetoothProfile.A2DP) { mA2dp = (BluetoothA2dp) proxy; + } else if (profile == BluetoothProfile.HEARING_AID) { + mHearingAid = (BluetoothHearingAid) proxy; } else if (profile == BluetoothProfile.LE_AUDIO) { mLeAudio = (BluetoothLeAudio) proxy; } @@ -490,16 +488,16 @@ public class BtHelper { return; } final BluetoothDevice btDevice = deviceList.get(0); - final @BluetoothProfile.BtProfileState int state = - proxy.getConnectionState(btDevice); - if (state == BluetoothProfile.STATE_CONNECTED) { + if (proxy.getConnectionState(btDevice) == BluetoothProfile.STATE_CONNECTED) { mDeviceBroker.queueOnBluetoothActiveDeviceChanged( new AudioDeviceBroker.BtDeviceChangedData(btDevice, null, - new BtProfileConnectionInfo(profile), "mBluetoothProfileServiceListener")); + new BluetoothProfileConnectionInfo(profile), + "mBluetoothProfileServiceListener")); } else { mDeviceBroker.queueOnBluetoothActiveDeviceChanged( new AudioDeviceBroker.BtDeviceChangedData(null, btDevice, - new BtProfileConnectionInfo(profile), "mBluetoothProfileServiceListener")); + new BluetoothProfileConnectionInfo(profile), + "mBluetoothProfileServiceListener")); } } @@ -812,8 +810,6 @@ public class BtHelper { private static boolean disconnectBluetoothScoAudioHelper(BluetoothHeadset bluetoothHeadset, BluetoothDevice device, int scoAudioMode) { switch (scoAudioMode) { - case SCO_MODE_RAW: - return bluetoothHeadset.disconnectAudio(); case SCO_MODE_VIRTUAL_CALL: return bluetoothHeadset.stopScoUsingVirtualVoiceCall(); case SCO_MODE_VR: @@ -826,8 +822,6 @@ public class BtHelper { private static boolean connectBluetoothScoAudioHelper(BluetoothHeadset bluetoothHeadset, BluetoothDevice device, int scoAudioMode) { switch (scoAudioMode) { - case SCO_MODE_RAW: - return bluetoothHeadset.connectAudio(); case SCO_MODE_VIRTUAL_CALL: return bluetoothHeadset.startScoUsingVirtualVoiceCall(); case SCO_MODE_VR: diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java index 38df5f896000..a0c5aa364f0d 100644 --- a/services/core/java/com/android/server/clipboard/ClipboardService.java +++ b/services/core/java/com/android/server/clipboard/ClipboardService.java @@ -639,7 +639,7 @@ public class ClipboardService extends SystemService { clipboard.primaryClipListeners.getBroadcastItem(i) .dispatchPrimaryClipChanged(); } - } catch (RemoteException e) { + } catch (RemoteException | SecurityException e) { // The RemoteCallbackList will take care of removing // the dead object for us. } diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java index 603f20633cfb..108e7bcb23bb 100644 --- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java +++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java @@ -25,7 +25,6 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkPolicy.LIMIT_DISABLED; import static android.net.NetworkPolicy.WARNING_DISABLED; import static android.provider.Settings.Global.NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES; -import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static com.android.server.net.NetworkPolicyManagerInternal.QUOTA_TYPE_MULTIPATH; import static com.android.server.net.NetworkPolicyManagerService.OPPORTUNISTIC_QUOTA_UNKNOWN; @@ -191,6 +190,7 @@ public class MultipathPolicyTracker { class MultipathTracker { final Network network; final String subscriberId; + private final int mSubId; private long mQuota; /** Current multipath budget. Nonzero iff we have budget and a UsageCallback is armed. */ @@ -204,9 +204,8 @@ public class MultipathPolicyTracker { this.network = network; this.mNetworkCapabilities = new NetworkCapabilities(nc); NetworkSpecifier specifier = nc.getNetworkSpecifier(); - int subId = INVALID_SUBSCRIPTION_ID; if (specifier instanceof TelephonyNetworkSpecifier) { - subId = ((TelephonyNetworkSpecifier) specifier).getSubscriptionId(); + mSubId = ((TelephonyNetworkSpecifier) specifier).getSubscriptionId(); } else { throw new IllegalStateException(String.format( "Can't get subId from mobile network %s (%s)", @@ -217,14 +216,14 @@ public class MultipathPolicyTracker { if (tele == null) { throw new IllegalStateException(String.format("Missing TelephonyManager")); } - tele = tele.createForSubscriptionId(subId); + tele = tele.createForSubscriptionId(mSubId); if (tele == null) { throw new IllegalStateException(String.format( - "Can't get TelephonyManager for subId %d", subId)); + "Can't get TelephonyManager for subId %d", mSubId)); } subscriberId = Objects.requireNonNull(tele.getSubscriberId(), - "Null subscriber Id for subId " + subId); + "Null subscriber Id for subId " + mSubId); mNetworkTemplate = new NetworkTemplate.Builder(NetworkTemplate.MATCH_MOBILE) .setSubscriberIds(Set.of(subscriberId)) .setMeteredness(NetworkStats.METERED_YES) @@ -282,6 +281,7 @@ public class MultipathPolicyTracker { .setSubscriberId(subscriberId) .setRoaming(!nc.hasCapability(NET_CAPABILITY_NOT_ROAMING)) .setMetered(!nc.hasCapability(NET_CAPABILITY_NOT_METERED)) + .setSubId(mSubId) .build(); } diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 9a9c3ea05d19..30ae7d6b8d21 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -151,6 +151,7 @@ import java.util.Objects; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; +import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; @@ -203,6 +204,7 @@ public class Vpn { private final NetworkInfo mNetworkInfo; private int mLegacyState; @VisibleForTesting protected String mPackage; + private String mSessionKey; private int mOwnerUID; private boolean mIsPackageTargetingAtLeastQ; @VisibleForTesting @@ -1302,6 +1304,7 @@ public class Vpn { .setLegacyType(ConnectivityManager.TYPE_VPN) .setLegacyTypeName("VPN") .setBypassableVpn(mConfig.allowBypass && !mLockdown) + .setVpnRequiresValidation(mConfig.requiresInternetValidation) .build(); capsBuilder.setOwnerUid(mOwnerUID); @@ -2003,7 +2006,8 @@ public class Vpn { .setCategory(Notification.CATEGORY_SYSTEM) .setVisibility(Notification.VISIBILITY_PUBLIC) .setOngoing(true) - .setColor(mContext.getColor(R.color.system_notification_accent_color)); + .setColor(mContext.getColor( + android.R.color.system_notification_accent_color)); notificationManager.notify(TAG, SystemMessage.NOTE_VPN_DISCONNECTED, builder.build()); } finally { Binder.restoreCallingIdentity(token); @@ -2503,6 +2507,7 @@ public class Vpn { mProfile = profile; mIpSecManager = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE); mNetworkCallback = new VpnIkev2Utils.Ikev2VpnNetworkCallback(TAG, this); + mSessionKey = UUID.randomUUID().toString(); } @Override @@ -2824,6 +2829,7 @@ public class Vpn { */ private void disconnectVpnRunner() { mActiveNetwork = null; + mSessionKey = null; mIsRunning = false; resetIkeState(); @@ -3314,7 +3320,7 @@ public class Vpn { * * @param packageName the package name of the app provisioning this profile */ - public synchronized void startVpnProfile(@NonNull String packageName) { + public synchronized String startVpnProfile(@NonNull String packageName) { requireNonNull(packageName, "No package name provided"); enforceNotRestrictedUser(); @@ -3332,6 +3338,7 @@ public class Vpn { } startVpnProfilePrivileged(profile, packageName); + return mSessionKey; } finally { Binder.restoreCallingIdentity(token); } @@ -3363,6 +3370,7 @@ public class Vpn { } mConfig.startTime = SystemClock.elapsedRealtime(); mConfig.proxyInfo = profile.proxy; + mConfig.requiresInternetValidation = profile.requiresInternetValidation; switch (profile.type) { case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS: diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index c27293c3cc09..c12522b43f2a 100755 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -75,6 +75,8 @@ abstract class HdmiCecLocalDevice { protected int mLastKeycode = HdmiCecKeycode.UNSUPPORTED_KEYCODE; protected int mLastKeyRepeatCount = 0; + HdmiCecStandbyModeHandler mStandbyHandler; + // Stores recent changes to the active source in the CEC network. private final ArrayBlockingQueue<HdmiCecController.Dumpable> mActiveSourceHistory = new ArrayBlockingQueue<>(MAX_HDMI_ACTIVE_SOURCE_HISTORY); @@ -263,6 +265,11 @@ abstract class HdmiCecLocalDevice { if (dest != mAddress && dest != Constants.ADDR_BROADCAST) { return Constants.NOT_HANDLED; } + if (mService.isPowerStandby() + && !mService.isWakeUpMessageReceived() + && mStandbyHandler.handleCommand(message)) { + return Constants.HANDLED; + } // Cache incoming message if it is included in the list of cacheable opcodes. mCecMessageCache.cacheMessage(message); return onMessage(message); @@ -829,17 +836,12 @@ abstract class HdmiCecLocalDevice { protected int handleVendorCommandWithId(HdmiCecMessage message) { byte[] params = message.getParams(); int vendorId = HdmiUtils.threeBytesToInt(params); - if (vendorId == mService.getVendorId()) { - if (!mService.invokeVendorCommandListenersOnReceived( - mDeviceType, message.getSource(), message.getDestination(), params, true)) { - return Constants.ABORT_REFUSED; - } - } else if (message.getDestination() != Constants.ADDR_BROADCAST - && message.getSource() != Constants.ADDR_UNREGISTERED) { - Slog.v(TAG, "Wrong direct vendor command. Replying with <Feature Abort>"); - return Constants.ABORT_UNRECOGNIZED_OPCODE; - } else { + if (message.getDestination() == Constants.ADDR_BROADCAST + || message.getSource() == Constants.ADDR_UNREGISTERED) { Slog.v(TAG, "Wrong broadcast vendor command. Ignoring"); + } else if (!mService.invokeVendorCommandListenersOnReceived( + mDeviceType, message.getSource(), message.getDestination(), params, true)) { + return Constants.ABORT_REFUSED; } return Constants.HANDLED; } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java index 0bb128536b42..c549b5598b67 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java @@ -112,6 +112,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { mService.readBooleanSetting(Global.HDMI_CEC_SWITCH_ENABLED, false); mSystemAudioControlFeatureEnabled = mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, true); + mStandbyHandler = new HdmiCecStandbyModeHandler(service, this); } private static final String SHORT_AUDIO_DESCRIPTOR_CONFIG_PATH = "/vendor/etc/sadConfig.xml"; diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java index 37ee76b7c615..40718585c484 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java @@ -64,6 +64,7 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource { HdmiCecLocalDevicePlayback(HdmiControlService service) { super(service, HdmiDeviceInfo.DEVICE_PLAYBACK); + mStandbyHandler = new HdmiCecStandbyModeHandler(service, this); } @Override diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index 6e7a2a0eb229..3d218cffc5df 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -91,8 +91,6 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { @GuardedBy("mLock") private boolean mSystemAudioMute = false; - private final HdmiCecStandbyModeHandler mStandbyHandler; - // If true, do not do routing control/send active source for internal source. // Set to true when the device was woken up by <Text/Image View On>. private boolean mSkipRoutingControl; diff --git a/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java b/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java index 6f7473d60121..1c296e5b5640 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java @@ -16,6 +16,7 @@ package com.android.server.hdmi; +import android.hardware.hdmi.HdmiDeviceInfo; import android.util.SparseArray; /** @@ -56,7 +57,8 @@ public final class HdmiCecStandbyModeHandler { private final class AutoOnHandler implements CecMessageHandler { @Override public boolean handle(HdmiCecMessage message) { - if (!mTv.getAutoWakeup()) { + HdmiCecLocalDeviceTv tv = (HdmiCecLocalDeviceTv) mDevice; + if (!tv.getAutoWakeup()) { mAborterRefused.handle(message); return true; } @@ -78,7 +80,7 @@ public final class HdmiCecStandbyModeHandler { } private final HdmiControlService mService; - private final HdmiCecLocalDeviceTv mTv; + private final HdmiCecLocalDevice mDevice; private final SparseArray<CecMessageHandler> mCecMessageHandlers = new SparseArray<>(); private final CecMessageHandler mDefaultHandler = new Aborter( @@ -92,13 +94,7 @@ public final class HdmiCecStandbyModeHandler { private final UserControlProcessedHandler mUserControlProcessedHandler = new UserControlProcessedHandler(); - public HdmiCecStandbyModeHandler(HdmiControlService service, HdmiCecLocalDeviceTv tv) { - mService = service; - mTv = tv; - - addHandler(Constants.MESSAGE_IMAGE_VIEW_ON, mAutoOnHandler); - addHandler(Constants.MESSAGE_TEXT_VIEW_ON, mAutoOnHandler); - + private void addCommonHandlers() { addHandler(Constants.MESSAGE_ACTIVE_SOURCE, mBystander); addHandler(Constants.MESSAGE_REQUEST_ACTIVE_SOURCE, mBystander); addHandler(Constants.MESSAGE_ROUTING_CHANGE, mBystander); @@ -112,19 +108,6 @@ public final class HdmiCecStandbyModeHandler { addHandler(Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS, mBystander); addHandler(Constants.MESSAGE_REPORT_AUDIO_STATUS, mBystander); - // If TV supports the following messages during power-on, ignore them and do nothing, - // else reply with <Feature Abort>["Unrecognized Opcode"] - // <Deck Status>, <Tuner Device Status>, <Tuner Cleared Status>, <Timer Status> - addHandler(Constants.MESSAGE_RECORD_STATUS, mBystander); - - // If TV supports the following messages during power-on, reply with <Feature Abort>["Not - // in correct mode to respond"], else reply with <Feature Abort>["Unrecognized Opcode"] - // <Give Tuner Device Status>, <Select Digital Service>, <Tuner Step Decrement>, - // <Tuner Stem Increment>, <Menu Status>. - addHandler(Constants.MESSAGE_RECORD_TV_SCREEN, mAborterIncorrectMode); - addHandler(Constants.MESSAGE_INITIATE_ARC, mAborterIncorrectMode); - addHandler(Constants.MESSAGE_TERMINATE_ARC, mAborterIncorrectMode); - addHandler(Constants.MESSAGE_GIVE_PHYSICAL_ADDRESS, mBypasser); addHandler(Constants.MESSAGE_GET_MENU_LANGUAGE, mBypasser); addHandler(Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS, mBypasser); @@ -133,6 +116,7 @@ public final class HdmiCecStandbyModeHandler { addHandler(Constants.MESSAGE_SET_OSD_NAME, mBypasser); addHandler(Constants.MESSAGE_DEVICE_VENDOR_ID, mBypasser); addHandler(Constants.MESSAGE_REPORT_POWER_STATUS, mBypasser); + addHandler(Constants.MESSAGE_GIVE_FEATURES, mBypasser); addHandler(Constants.MESSAGE_USER_CONTROL_PRESSED, mUserControlProcessedHandler); @@ -144,6 +128,34 @@ public final class HdmiCecStandbyModeHandler { addHandler(Constants.MESSAGE_SET_SYSTEM_AUDIO_MODE, mAborterIncorrectMode); } + private void addTvHandlers() { + addHandler(Constants.MESSAGE_IMAGE_VIEW_ON, mAutoOnHandler); + addHandler(Constants.MESSAGE_TEXT_VIEW_ON, mAutoOnHandler); + + // If TV supports the following messages during power-on, ignore them and do nothing, + // else reply with <Feature Abort>["Unrecognized Opcode"] + // <Deck Status>, <Tuner Device Status>, <Tuner Cleared Status>, <Timer Status> + addHandler(Constants.MESSAGE_RECORD_STATUS, mBystander); + + // If TV supports the following messages during power-on, reply with <Feature Abort>["Not + // in correct mode to respond"], else reply with <Feature Abort>["Unrecognized Opcode"] + // <Give Tuner Device Status>, <Select Digital Service>, <Tuner Step Decrement>, + // <Tuner Stem Increment>, <Menu Status>. + addHandler(Constants.MESSAGE_RECORD_TV_SCREEN, mAborterIncorrectMode); + addHandler(Constants.MESSAGE_INITIATE_ARC, mAborterIncorrectMode); + addHandler(Constants.MESSAGE_TERMINATE_ARC, mAborterIncorrectMode); + } + + public HdmiCecStandbyModeHandler(HdmiControlService service, HdmiCecLocalDevice device) { + mService = service; + mDevice = device; + + addCommonHandlers(); + if (mDevice.getType() == HdmiDeviceInfo.DEVICE_TV) { + addTvHandlers(); + } + } + private void addHandler(int opcode, CecMessageHandler handler) { mCecMessageHandlers.put(opcode, handler); } diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index a571dc06db97..8dadf5a8d20d 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -1582,11 +1582,11 @@ public class HdmiControlService extends SystemService { class VendorCommandListenerRecord implements IBinder.DeathRecipient { private final IHdmiVendorCommandListener mListener; - private final int mDeviceType; + private final int mVendorId; - public VendorCommandListenerRecord(IHdmiVendorCommandListener listener, int deviceType) { + VendorCommandListenerRecord(IHdmiVendorCommandListener listener, int vendorId) { mListener = listener; - mDeviceType = deviceType; + mVendorId = vendorId; } @Override @@ -2077,10 +2077,10 @@ public class HdmiControlService extends SystemService { } @Override - public void addVendorCommandListener(final IHdmiVendorCommandListener listener, - final int deviceType) { + public void addVendorCommandListener( + final IHdmiVendorCommandListener listener, final int vendorId) { initBinderCall(); - HdmiControlService.this.addVendorCommandListener(listener, deviceType); + HdmiControlService.this.addVendorCommandListener(listener, vendorId); } @Override @@ -3219,8 +3219,9 @@ public class HdmiControlService extends SystemService { } } - private void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) { - VendorCommandListenerRecord record = new VendorCommandListenerRecord(listener, deviceType); + @VisibleForTesting + void addVendorCommandListener(IHdmiVendorCommandListener listener, int vendorId) { + VendorCommandListenerRecord record = new VendorCommandListenerRecord(listener, vendorId); try { listener.asBinder().linkToDeath(record, 0); } catch (RemoteException e) { @@ -3239,8 +3240,14 @@ public class HdmiControlService extends SystemService { return false; } for (VendorCommandListenerRecord record : mVendorCommandListenerRecords) { - if (record.mDeviceType != deviceType) { - continue; + if (hasVendorId) { + int vendorId = + ((params[0] & 0xFF) << 16) + + ((params[1] & 0xFF) << 8) + + (params[2] & 0xFF); + if (record.mVendorId != vendorId) { + continue; + } } try { record.mListener.onReceived(srcAddress, destAddress, params, hasVendorId); diff --git a/services/core/java/com/android/server/infra/OWNERS b/services/core/java/com/android/server/infra/OWNERS new file mode 100644 index 000000000000..0466d8a88053 --- /dev/null +++ b/services/core/java/com/android/server/infra/OWNERS @@ -0,0 +1,3 @@ +# Bug component: 655446 + +include /core/java/android/service/cloudsearch/OWNERS diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 3e52f5e07e62..5b7f5c85c1bb 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -2837,7 +2837,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return; } final IBinder targetWindow = mImeTargetWindowMap.get(startInputToken); - if (targetWindow != null && mLastImeTargetWindow != targetWindow) { + if (targetWindow != null) { mWindowManagerInternal.updateInputMethodTargetWindow(token, targetWindow); } mLastImeTargetWindow = targetWindow; diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java b/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java index a102406cc131..1203769cb72b 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java @@ -262,7 +262,7 @@ public class LockSettingsStrongAuth { long nextAlarmTime = strongAuthTime + dpm.getRequiredStrongAuthTimeout(null, userId); // schedule a new alarm listener for the user - mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, nextAlarmTime, + mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextAlarmTime, STRONG_AUTH_TIMEOUT_ALARM_TAG, alarm, mHandler); } @@ -303,7 +303,7 @@ public class LockSettingsStrongAuth { alarm = new NonStrongBiometricTimeoutAlarmListener(userId); mNonStrongBiometricTimeoutAlarmListener.put(userId, alarm); // schedule a new alarm listener for the user - mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, nextAlarmTime, + mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextAlarmTime, NON_STRONG_BIOMETRIC_TIMEOUT_ALARM_TAG, alarm, mHandler); } @@ -394,7 +394,7 @@ public class LockSettingsStrongAuth { } // schedule a new alarm listener for the user if (DEBUG) Slog.d(TAG, "Schedule a new alarm for non-strong biometric idle timeout"); - mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, nextAlarmTime, + mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextAlarmTime, NON_STRONG_BIOMETRIC_IDLE_TIMEOUT_ALARM_TAG, alarm, mHandler); } diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 4822d6a62ac7..b482d1869c66 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -62,6 +62,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.NoSuchElementException; /** * This is the system implementation of a Session. Apps will interact with the @@ -792,7 +793,10 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR } for (ISessionControllerCallbackHolder holder : mControllerCallbackHolders) { try { + holder.mCallback.asBinder().unlinkToDeath(holder.mDeathMonitor, 0); holder.mCallback.onSessionDestroyed(); + } catch (NoSuchElementException e) { + logCallbackException("error unlinking to binder death", holder, e); } catch (DeadObjectException e) { logCallbackException("Removing dead callback in pushSessionDestroyed", holder, e); } catch (RemoteException e) { @@ -1375,12 +1379,22 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR return; } if (getControllerHolderIndexForCb(cb) < 0) { - mControllerCallbackHolders.add(new ISessionControllerCallbackHolder(cb, - packageName, Binder.getCallingUid())); + ISessionControllerCallbackHolder holder = new ISessionControllerCallbackHolder( + cb, packageName, Binder.getCallingUid(), () -> unregisterCallback(cb)); + mControllerCallbackHolders.add(holder); if (DEBUG) { Log.d(TAG, "registering controller callback " + cb + " from controller" + packageName); } + // Avoid callback leaks + try { + // cb is not referenced outside of the MediaSessionRecord, so the death + // handler won't prevent MediaSessionRecord to be garbage collected. + cb.asBinder().linkToDeath(holder.mDeathMonitor, 0); + } catch (RemoteException e) { + unregisterCallback(cb); + Log.w(TAG, "registerCallback failed to linkToDeath", e); + } } } } @@ -1390,6 +1404,12 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR synchronized (mLock) { int index = getControllerHolderIndexForCb(cb); if (index != -1) { + try { + cb.asBinder().unlinkToDeath( + mControllerCallbackHolders.get(index).mDeathMonitor, 0); + } catch (NoSuchElementException e) { + Log.w(TAG, "error unlinking to binder death", e); + } mControllerCallbackHolders.remove(index); } if (DEBUG) { @@ -1600,12 +1620,14 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR private final ISessionControllerCallback mCallback; private final String mPackageName; private final int mUid; + private final IBinder.DeathRecipient mDeathMonitor; ISessionControllerCallbackHolder(ISessionControllerCallback callback, String packageName, - int uid) { + int uid, IBinder.DeathRecipient deathMonitor) { mCallback = callback; mPackageName = packageName; mUid = uid; + mDeathMonitor = deathMonitor; } } diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java index 851ea3d01085..1b7d1ba59b06 100644 --- a/services/core/java/com/android/server/net/LockdownVpnTracker.java +++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java @@ -293,7 +293,7 @@ public class LockdownVpnTracker { .addAction(R.drawable.ic_menu_refresh, mContext.getString(R.string.reset), mResetIntent) .setColor(mContext.getColor( - com.android.internal.R.color.system_notification_accent_color)); + android.R.color.system_notification_accent_color)); mNotificationManager.notify(null /* tag */, SystemMessage.NOTE_VPN_STATUS, builder.build()); diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java index 81106b1a5ca7..33ac6cdb269e 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyLogger.java +++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java @@ -15,13 +15,17 @@ */ package com.android.server.net; -import static android.net.INetd.FIREWALL_CHAIN_DOZABLE; -import static android.net.INetd.FIREWALL_CHAIN_POWERSAVE; -import static android.net.INetd.FIREWALL_CHAIN_RESTRICTED; -import static android.net.INetd.FIREWALL_CHAIN_STANDBY; +import static android.net.ConnectivityManager.BLOCKED_REASON_NONE; +import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE; +import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY; +import static android.net.ConnectivityManager.FIREWALL_CHAIN_POWERSAVE; +import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED; +import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY; import static android.net.INetd.FIREWALL_RULE_ALLOW; import static android.net.INetd.FIREWALL_RULE_DENY; +import static android.net.NetworkPolicyManager.ALLOWED_REASON_NONE; import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE; +import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_LOW_POWER_STANDBY; import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_POWERSAVE; import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_RESTRICTED; import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY; @@ -29,6 +33,7 @@ import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT; import static android.os.PowerExemptionManager.reasonCodeToString; import static android.os.Process.INVALID_UID; +import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManager.ProcessCapability; import android.net.NetworkPolicyManager; @@ -81,13 +86,18 @@ public class NetworkPolicyLogger { private final Object mLock = new Object(); - void networkBlocked(int uid, UidBlockedState uidBlockedState) { + void networkBlocked(int uid, @Nullable UidBlockedState uidBlockedState) { synchronized (mLock) { if (LOGD || uid == mDebugUid) { Slog.d(TAG, "Blocked state of uid: " + uidBlockedState.toString()); } - mNetworkBlockedBuffer.networkBlocked(uid, uidBlockedState.blockedReasons, - uidBlockedState.allowedReasons, uidBlockedState.effectiveBlockedReasons); + if (uidBlockedState == null) { + mNetworkBlockedBuffer.networkBlocked(uid, BLOCKED_REASON_NONE, ALLOWED_REASON_NONE, + BLOCKED_REASON_NONE); + } else { + mNetworkBlockedBuffer.networkBlocked(uid, uidBlockedState.blockedReasons, + uidBlockedState.allowedReasons, uidBlockedState.effectiveBlockedReasons); + } } } @@ -320,6 +330,8 @@ public class NetworkPolicyLogger { return FIREWALL_CHAIN_NAME_POWERSAVE; case FIREWALL_CHAIN_RESTRICTED: return FIREWALL_CHAIN_NAME_RESTRICTED; + case FIREWALL_CHAIN_LOW_POWER_STANDBY: + return FIREWALL_CHAIN_NAME_LOW_POWER_STANDBY; default: return String.valueOf(chain); } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 6a00d06440b9..9f58f6540be0 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -61,7 +61,6 @@ import static android.net.INetd.FIREWALL_RULE_ALLOW; import static android.net.INetd.FIREWALL_RULE_DENY; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; -import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkPolicy.LIMIT_DISABLED; import static android.net.NetworkPolicy.SNOOZE_NEVER; import static android.net.NetworkPolicy.WARNING_DISABLED; @@ -173,11 +172,9 @@ import android.net.NetworkPolicy; import android.net.NetworkPolicyManager; import android.net.NetworkPolicyManager.UidState; import android.net.NetworkRequest; -import android.net.NetworkSpecifier; import android.net.NetworkStack; import android.net.NetworkStateSnapshot; import android.net.NetworkTemplate; -import android.net.TelephonyNetworkSpecifier; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiManager; import android.os.BestClock; @@ -284,6 +281,7 @@ import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.function.IntConsumer; @@ -1006,10 +1004,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler); // listen for stats updated callbacks for interested network types. + final Executor executor = new HandlerExecutor(mHandler); mNetworkStats.registerUsageCallback(new NetworkTemplate.Builder(MATCH_MOBILE).build(), - 0 /* thresholdBytes */, new HandlerExecutor(mHandler), mStatsCallback); + 0 /* thresholdBytes */, executor, mStatsCallback); mNetworkStats.registerUsageCallback(new NetworkTemplate.Builder(MATCH_WIFI).build(), - 0 /* thresholdBytes */, new HandlerExecutor(mHandler), mStatsCallback); + 0 /* thresholdBytes */, executor, mStatsCallback); // listen for restrict background changes from notifications final IntentFilter allowFilter = new IntentFilter(ACTION_ALLOW_BACKGROUND); @@ -1237,6 +1236,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * Used to determine if NetworkStatsService is ready. */ public boolean isAnyCallbackReceived() { + // Warning : threading for this member is broken. It should only be read + // and written on the handler thread ; furthermore, the constructor + // is called on a different thread, so this stops working if the default + // value is not false or if this member ever goes back to false after + // being set to true. + // TODO : fix threading for this member. return mIsAnyCallbackReceived; } }; @@ -1512,7 +1517,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { .setType(TYPE_MOBILE) .setSubscriberId(subscriberId) .setMetered(true) - .setDefaultNetwork(true).build(); + .setDefaultNetwork(true) + .setSubId(subId).build(); if (template.matches(probeIdent)) { return subId; } @@ -1749,7 +1755,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { .setType(TYPE_MOBILE) .setSubscriberId(subscriberId) .setMetered(true) - .setDefaultNetwork(true).build(); + .setDefaultNetwork(true) + .setSubId(subId).build(); for (int i = mNetworkPolicy.size() - 1; i >= 0; i--) { final NetworkTemplate template = mNetworkPolicy.keyAt(i); if (template.matches(probeIdent)) { @@ -1981,7 +1988,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { .setType(TYPE_MOBILE) .setSubscriberId(subscriberId) .setMetered(true) - .setDefaultNetwork(true).build(); + .setDefaultNetwork(true) + .setSubId(subId).build(); // Template is matched when subscriber id matches. if (template.matches(probeIdent)) { matchingSubIds.add(subId); @@ -2083,7 +2091,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mNetIdToSubId.clear(); final ArrayMap<NetworkStateSnapshot, NetworkIdentity> identified = new ArrayMap<>(); for (final NetworkStateSnapshot snapshot : snapshots) { - mNetIdToSubId.put(snapshot.getNetwork().getNetId(), parseSubId(snapshot)); + final int subId = snapshot.getSubId(); + mNetIdToSubId.put(snapshot.getNetwork().getNetId(), subId); // Policies matched by NPMS only match by subscriber ID or by network ID. final NetworkIdentity ident = new NetworkIdentity.Builder() @@ -2288,7 +2297,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { .setType(TYPE_MOBILE) .setSubscriberId(subscriberId) .setMetered(true) - .setDefaultNetwork(true).build(); + .setDefaultNetwork(true) + .setSubId(subId).build(); for (int i = mNetworkPolicy.size() - 1; i >= 0; i--) { final NetworkTemplate template = mNetworkPolicy.keyAt(i); if (template.matches(probeIdent)) { @@ -5807,17 +5817,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } - private int parseSubId(@NonNull NetworkStateSnapshot snapshot) { - int subId = INVALID_SUBSCRIPTION_ID; - if (snapshot.getNetworkCapabilities().hasTransport(TRANSPORT_CELLULAR)) { - NetworkSpecifier spec = snapshot.getNetworkCapabilities().getNetworkSpecifier(); - if (spec instanceof TelephonyNetworkSpecifier) { - subId = ((TelephonyNetworkSpecifier) spec).getSubscriptionId(); - } - } - return subId; - } - @GuardedBy("mNetworkPoliciesSecondLock") private int getSubIdLocked(Network network) { return mNetIdToSubId.get(network.getNetId(), INVALID_SUBSCRIPTION_ID); diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java index 31b186091f39..e7e691c9c654 100644 --- a/services/core/java/com/android/server/pm/ApexManager.java +++ b/services/core/java/com/android/server/pm/ApexManager.java @@ -343,6 +343,13 @@ public abstract class ApexManager { public abstract String getApexModuleNameForPackageName(String apexPackageName); /** + * Returns the package name of the active APEX whose name is {@code apexModuleName}. If not + * found, returns {@code null}. + */ + @Nullable + public abstract String getActivePackageNameForApexModuleName(String apexModuleName); + + /** * Copies the CE apex data directory for the given {@code userId} to a backup location, for use * in case of rollback. * @@ -467,6 +474,12 @@ public abstract class ApexManager { private ArrayMap<String, String> mPackageNameToApexModuleName; /** + * Reverse mapping of {@link #mPackageNameToApexModuleName}, for active packages only. + */ + @GuardedBy("mLock") + private ArrayMap<String, String> mApexModuleNameToActivePackageName; + + /** * Whether an APEX package is active or not. * * @param packageInfo the package to check @@ -534,6 +547,7 @@ public abstract class ApexManager { try { mAllPackagesCache = new ArrayList<>(); mPackageNameToApexModuleName = new ArrayMap<>(); + mApexModuleNameToActivePackageName = new ArrayMap<>(); allPkgs = waitForApexService().getAllPackages(); } catch (RemoteException re) { Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString()); @@ -580,6 +594,13 @@ public abstract class ApexManager { + packageInfo.packageName); } activePackagesSet.add(packageInfo.packageName); + if (mApexModuleNameToActivePackageName.containsKey(ai.moduleName)) { + throw new IllegalStateException( + "Two active packages have the same APEX module name: " + + ai.moduleName); + } + mApexModuleNameToActivePackageName.put( + ai.moduleName, packageInfo.packageName); } if (ai.isFactory) { // Don't throw when the duplicating APEX is VNDK APEX @@ -913,6 +934,16 @@ public abstract class ApexManager { } @Override + @Nullable + public String getActivePackageNameForApexModuleName(String apexModuleName) { + synchronized (mLock) { + Preconditions.checkState(mApexModuleNameToActivePackageName != null, + "APEX packages have not been scanned"); + return mApexModuleNameToActivePackageName.get(apexModuleName); + } + } + + @Override public boolean snapshotCeData(int userId, int rollbackId, String apexPackageName) { String apexModuleName; synchronized (mLock) { @@ -1330,6 +1361,12 @@ public abstract class ApexManager { } @Override + @Nullable + public String getActivePackageNameForApexModuleName(String apexModuleName) { + return null; + } + + @Override public boolean snapshotCeData(int userId, int rollbackId, String apexPackageName) { throw new UnsupportedOperationException(); } diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index 8fd545f271f3..5a5f9ef3b6aa 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -40,7 +40,6 @@ import com.android.server.SystemService; import dalvik.system.BlockGuard; import dalvik.system.VMRuntime; -import java.io.FileDescriptor; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -681,28 +680,6 @@ public class Installer extends SystemService { } } - public void installApkVerity(String filePath, FileDescriptor verityInput, int contentSize) - throws InstallerException { - if (!checkBeforeRemote()) return; - BlockGuard.getVmPolicy().onPathAccess(filePath); - try { - mInstalld.installApkVerity(filePath, verityInput, contentSize); - } catch (Exception e) { - throw InstallerException.from(e); - } - } - - public void assertFsverityRootHashMatches(String filePath, @NonNull byte[] expectedHash) - throws InstallerException { - if (!checkBeforeRemote()) return; - BlockGuard.getVmPolicy().onPathAccess(filePath); - try { - mInstalld.assertFsverityRootHashMatches(filePath, expectedHash); - } catch (Exception e) { - throw InstallerException.from(e); - } - } - public boolean reconcileSecondaryDexFile(String apkPath, String packageName, int uid, String[] isas, @Nullable String volumeUuid, int flags) throws InstallerException { for (int i = 0; i < isas.length; i++) { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index bc28cffbcbfc..bc6c306a109b 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -12118,14 +12118,14 @@ public class PackageManagerService extends IPackageManager.Stub * Returns if forced apk verification can be skipped for the whole package, including splits. */ private boolean canSkipForcedPackageVerification(AndroidPackage pkg) { - if (!canSkipForcedApkVerification(pkg.getBaseApkPath())) { + if (!VerityUtils.hasFsverity(pkg.getBaseApkPath())) { return false; } // TODO: Allow base and splits to be verified individually. String[] splitCodePaths = pkg.getSplitCodePaths(); if (!ArrayUtils.isEmpty(splitCodePaths)) { for (int i = 0; i < splitCodePaths.length; i++) { - if (!canSkipForcedApkVerification(splitCodePaths[i])) { + if (!VerityUtils.hasFsverity(splitCodePaths[i])) { return false; } } @@ -12134,33 +12134,6 @@ public class PackageManagerService extends IPackageManager.Stub } /** - * Returns if forced apk verification can be skipped, depending on current FSVerity setup and - * whether the apk contains signed root hash. Note that the signer's certificate still needs to - * match one in a trusted source, and should be done separately. - */ - private boolean canSkipForcedApkVerification(String apkPath) { - if (!PackageManagerServiceUtils.isLegacyApkVerityEnabled()) { - return VerityUtils.hasFsverity(apkPath); - } - - try { - final byte[] rootHashObserved = VerityUtils.generateApkVerityRootHash(apkPath); - if (rootHashObserved == null) { - return false; // APK does not contain Merkle tree root hash. - } - synchronized (mInstallLock) { - // Returns whether the observed root hash matches what kernel has. - mInstaller.assertFsverityRootHashMatches(apkPath, rootHashObserved); - return true; - } - } catch (InstallerException | IOException | DigestException | - NoSuchAlgorithmException e) { - Slog.w(TAG, "Error in fsverity check. Fallback to full apk verification.", e); - } - return false; - } - - /** * Adds a new package to the internal data structures during platform initialization. * <p>After adding, the package is known to the system and available for querying. * <p>For packages located on the device ROM [eg. packages located in /system, /vendor, @@ -12935,7 +12908,8 @@ public class PackageManagerService extends IPackageManager.Stub DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES | DexoptOptions.DEXOPT_BOOT_COMPLETE | (force ? DexoptOptions.DEXOPT_FORCE : 0); - return performDexOpt(new DexoptOptions(packageName, compilerFilter, flags)); + return performDexOpt(new DexoptOptions(packageName, REASON_CMDLINE, + compilerFilter, /* splitName */ null, flags)); } /*package*/ boolean performDexOpt(DexoptOptions options) { @@ -21192,9 +21166,7 @@ public class PackageManagerService extends IPackageManager.Stub */ private void setUpFsVerityIfPossible(AndroidPackage pkg) throws InstallerException, PrepareFailure, IOException, DigestException, NoSuchAlgorithmException { - final boolean standardMode = PackageManagerServiceUtils.isApkVerityEnabled(); - final boolean legacyMode = PackageManagerServiceUtils.isLegacyApkVerityEnabled(); - if (!standardMode && !legacyMode) { + if (!PackageManagerServiceUtils.isApkVerityEnabled()) { return; } @@ -21205,39 +21177,25 @@ public class PackageManagerService extends IPackageManager.Stub // Collect files we care for fs-verity setup. ArrayMap<String, String> fsverityCandidates = new ArrayMap<>(); - if (legacyMode) { - synchronized (mLock) { - final PackageSetting ps = mSettings.getPackageLPr(pkg.getPackageName()); - if (ps != null && ps.isPrivileged()) { - fsverityCandidates.put(pkg.getBaseApkPath(), null); - if (pkg.getSplitCodePaths() != null) { - for (String splitPath : pkg.getSplitCodePaths()) { - fsverityCandidates.put(splitPath, null); - } - } - } - } - } else { - // NB: These files will become only accessible if the signing key is loaded in kernel's - // .fs-verity keyring. - fsverityCandidates.put(pkg.getBaseApkPath(), - VerityUtils.getFsveritySignatureFilePath(pkg.getBaseApkPath())); + // NB: These files will become only accessible if the signing key is loaded in kernel's + // .fs-verity keyring. + fsverityCandidates.put(pkg.getBaseApkPath(), + VerityUtils.getFsveritySignatureFilePath(pkg.getBaseApkPath())); - final String dmPath = DexMetadataHelper.buildDexMetadataPathForApk( - pkg.getBaseApkPath()); - if (new File(dmPath).exists()) { - fsverityCandidates.put(dmPath, VerityUtils.getFsveritySignatureFilePath(dmPath)); - } + final String dmPath = DexMetadataHelper.buildDexMetadataPathForApk( + pkg.getBaseApkPath()); + if (new File(dmPath).exists()) { + fsverityCandidates.put(dmPath, VerityUtils.getFsveritySignatureFilePath(dmPath)); + } - if (pkg.getSplitCodePaths() != null) { - for (String path : pkg.getSplitCodePaths()) { - fsverityCandidates.put(path, VerityUtils.getFsveritySignatureFilePath(path)); + if (pkg.getSplitCodePaths() != null) { + for (String path : pkg.getSplitCodePaths()) { + fsverityCandidates.put(path, VerityUtils.getFsveritySignatureFilePath(path)); - final String splitDmPath = DexMetadataHelper.buildDexMetadataPathForApk(path); - if (new File(splitDmPath).exists()) { - fsverityCandidates.put(splitDmPath, - VerityUtils.getFsveritySignatureFilePath(splitDmPath)); - } + final String splitDmPath = DexMetadataHelper.buildDexMetadataPathForApk(path); + if (new File(splitDmPath).exists()) { + fsverityCandidates.put(splitDmPath, + VerityUtils.getFsveritySignatureFilePath(splitDmPath)); } } } @@ -21246,40 +21204,14 @@ public class PackageManagerService extends IPackageManager.Stub final String filePath = entry.getKey(); final String signaturePath = entry.getValue(); - if (!legacyMode) { - // fs-verity is optional for now. Only set up if signature is provided. - if (new File(signaturePath).exists() && !VerityUtils.hasFsverity(filePath)) { - try { - VerityUtils.setUpFsverity(filePath, signaturePath); - } catch (IOException e) { - throw new PrepareFailure(PackageManager.INSTALL_FAILED_BAD_SIGNATURE, - "Failed to enable fs-verity: " + e); - } - } - continue; - } - - // In legacy mode, fs-verity can only be enabled by process with CAP_SYS_ADMIN. - final VerityUtils.SetupResult result = VerityUtils.generateApkVeritySetupData(filePath); - if (result.isOk()) { - if (Build.IS_DEBUGGABLE) Slog.i(TAG, "Enabling verity to " + filePath); - final FileDescriptor fd = result.getUnownedFileDescriptor(); + // fs-verity is optional for now. Only set up if signature is provided. + if (new File(signaturePath).exists() && !VerityUtils.hasFsverity(filePath)) { try { - final byte[] rootHash = VerityUtils.generateApkVerityRootHash(filePath); - try { - // A file may already have fs-verity, e.g. when reused during a split - // install. If the measurement succeeds, no need to attempt to set up. - mInstaller.assertFsverityRootHashMatches(filePath, rootHash); - } catch (InstallerException e) { - mInstaller.installApkVerity(filePath, fd, result.getContentSize()); - mInstaller.assertFsverityRootHashMatches(filePath, rootHash); - } - } finally { - IoUtils.closeQuietly(fd); + VerityUtils.setUpFsverity(filePath, signaturePath); + } catch (IOException e) { + throw new PrepareFailure(PackageManager.INSTALL_FAILED_BAD_SIGNATURE, + "Failed to enable fs-verity: " + e); } - } else if (result.isFailed()) { - throw new PrepareFailure(PackageManager.INSTALL_FAILED_BAD_SIGNATURE, - "Failed to generate verity"); } } } diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java index 8b5abf3afe51..8970049d85cc 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java @@ -591,12 +591,6 @@ public class PackageManagerServiceUtils { /** Default is to not use fs-verity since it depends on kernel support. */ private static final int FSVERITY_DISABLED = 0; - /** - * Experimental implementation targeting priv apps, with Android specific kernel patches to - * extend fs-verity. - */ - private static final int FSVERITY_LEGACY = 1; - /** Standard fs-verity. */ private static final int FSVERITY_ENABLED = 2; @@ -607,10 +601,6 @@ public class PackageManagerServiceUtils { == FSVERITY_ENABLED; } - static boolean isLegacyApkVerityEnabled() { - return SystemProperties.getInt("ro.apk_verity.mode", FSVERITY_DISABLED) == FSVERITY_LEGACY; - } - /** Returns true to force apk verification if the package is considered privileged. */ static boolean isApkVerificationForced(@Nullable PackageSetting ps) { // TODO(b/154310064): re-enable. diff --git a/services/core/java/com/android/server/pm/parsing/library/ApexSharedLibraryUpdater.java b/services/core/java/com/android/server/pm/parsing/library/ApexSharedLibraryUpdater.java new file mode 100644 index 000000000000..0418afbf29ee --- /dev/null +++ b/services/core/java/com/android/server/pm/parsing/library/ApexSharedLibraryUpdater.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2021 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 com.android.server.pm.parsing.library; + +import android.util.ArrayMap; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.SystemConfig; +import com.android.server.pm.parsing.pkg.ParsedPackage; + +/** + * Updates packages to add or remove dependencies on shared libraries as per attributes + * in the library declaration + * + * @hide + */ +@VisibleForTesting +public class ApexSharedLibraryUpdater extends PackageSharedLibraryUpdater { + + /** + * ArrayMap like the one you find in {@link SystemConfig}. The keys are the library names. + */ + private final ArrayMap<String, SystemConfig.SharedLibraryEntry> mSharedLibraries; + + public ApexSharedLibraryUpdater( + ArrayMap<String, SystemConfig.SharedLibraryEntry> sharedLibraries) { + mSharedLibraries = sharedLibraries; + } + + @Override + public void updatePackage(ParsedPackage parsedPackage, boolean isUpdatedSystemApp) { + final int builtInLibCount = mSharedLibraries.size(); + for (int i = 0; i < builtInLibCount; i++) { + updateSharedLibraryForPackage(mSharedLibraries.valueAt(i), parsedPackage); + } + } + + private void updateSharedLibraryForPackage(SystemConfig.SharedLibraryEntry entry, + ParsedPackage parsedPackage) { + if (entry.onBootclasspathBefore != 0 + && parsedPackage.getTargetSdkVersion() < entry.onBootclasspathBefore) { + // this package targets an API where this library was in the BCP, so add + // the library transparently in case the package is using it + prefixRequiredLibrary(parsedPackage, entry.name); + } + + if (entry.canBeSafelyIgnored) { + // the library is now present in the BCP and always available; we don't need to add + // it a second time + removeLibrary(parsedPackage, entry.name); + } + } +} diff --git a/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java b/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java index 8a8a302734b1..d81e7d05fd73 100644 --- a/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java +++ b/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java @@ -25,6 +25,7 @@ import android.content.pm.PackageParser; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.SystemConfig; import com.android.server.pm.parsing.pkg.ParsedPackage; import java.util.ArrayList; @@ -63,6 +64,11 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater { boolean bootClassPathContainsATB = !addUpdaterForAndroidTestBase(packageUpdaters); + // ApexSharedLibraryUpdater should be the last one, to allow modifications introduced by + // mainline after dessert release. + packageUpdaters.add(new ApexSharedLibraryUpdater( + SystemConfig.getInstance().getSharedLibraries())); + PackageSharedLibraryUpdater[] updaterArray = packageUpdaters .toArray(new PackageSharedLibraryUpdater[0]); INSTANCE = new PackageBackwardCompatibility( @@ -106,6 +112,11 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater { private final PackageSharedLibraryUpdater[] mPackageUpdaters; + @VisibleForTesting + PackageSharedLibraryUpdater[] getPackageUpdaters() { + return mPackageUpdaters; + } + private PackageBackwardCompatibility( boolean bootClassPathContainsATB, PackageSharedLibraryUpdater[] packageUpdaters) { this.mBootClassPathContainsATB = bootClassPathContainsATB; diff --git a/services/core/java/com/android/server/policy/KeyCombinationManager.java b/services/core/java/com/android/server/policy/KeyCombinationManager.java index 268de3e2182b..68e078c519ba 100644 --- a/services/core/java/com/android/server/policy/KeyCombinationManager.java +++ b/services/core/java/com/android/server/policy/KeyCombinationManager.java @@ -17,11 +17,13 @@ package com.android.server.policy; import static android.view.KeyEvent.KEYCODE_POWER; +import android.os.Handler; import android.os.SystemClock; import android.util.Log; import android.util.SparseLongArray; import android.view.KeyEvent; +import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ToBooleanFunction; import java.io.PrintWriter; @@ -35,13 +37,18 @@ public class KeyCombinationManager { private static final String TAG = "KeyCombinationManager"; // Store the received down time of keycode. + @GuardedBy("mLock") private final SparseLongArray mDownTimes = new SparseLongArray(2); private final ArrayList<TwoKeysCombinationRule> mRules = new ArrayList(); // Selected rules according to current key down. + private final Object mLock = new Object(); + @GuardedBy("mLock") private final ArrayList<TwoKeysCombinationRule> mActiveRules = new ArrayList(); // The rule has been triggered by current keys. + @GuardedBy("mLock") private TwoKeysCombinationRule mTriggeredRule; + private final Handler mHandler = new Handler(); // Keys in a key combination must be pressed within this interval of each other. private static final long COMBINE_KEY_DELAY_MILLIS = 150; @@ -109,6 +116,12 @@ public class KeyCombinationManager { * Return true if any active rule could be triggered by the key event, otherwise false. */ boolean interceptKey(KeyEvent event, boolean interactive) { + synchronized (mLock) { + return interceptKeyLocked(event, interactive); + } + } + + private boolean interceptKeyLocked(KeyEvent event, boolean interactive) { final boolean down = event.getAction() == KeyEvent.ACTION_DOWN; final int keyCode = event.getKeyCode(); final int count = mActiveRules.size(); @@ -154,7 +167,7 @@ public class KeyCombinationManager { return false; } Log.v(TAG, "Performing combination rule : " + rule); - rule.execute(); + mHandler.post(rule::execute); mTriggeredRule = rule; return true; }); @@ -169,7 +182,7 @@ public class KeyCombinationManager { for (int index = count - 1; index >= 0; index--) { final TwoKeysCombinationRule rule = mActiveRules.get(index); if (rule.shouldInterceptKey(keyCode)) { - rule.cancel(); + mHandler.post(rule::cancel); mActiveRules.remove(index); } } @@ -181,31 +194,37 @@ public class KeyCombinationManager { * Return the interceptTimeout to tell InputDispatcher when is ready to deliver to window. */ long getKeyInterceptTimeout(int keyCode) { - if (forAllActiveRules((rule) -> rule.shouldInterceptKey(keyCode))) { - return mDownTimes.get(keyCode) + COMBINE_KEY_DELAY_MILLIS; + synchronized (mLock) { + if (forAllActiveRules((rule) -> rule.shouldInterceptKey(keyCode))) { + return mDownTimes.get(keyCode) + COMBINE_KEY_DELAY_MILLIS; + } + return 0; } - return 0; } /** * True if the key event had been handled. */ boolean isKeyConsumed(KeyEvent event) { - if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) != 0) { - return false; + synchronized (mLock) { + if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) != 0) { + return false; + } + return mTriggeredRule != null && mTriggeredRule.shouldInterceptKey(event.getKeyCode()); } - return mTriggeredRule != null && mTriggeredRule.shouldInterceptKey(event.getKeyCode()); } /** * True if power key is the candidate. */ boolean isPowerKeyIntercepted() { - if (forAllActiveRules((rule) -> rule.shouldInterceptKey(KEYCODE_POWER))) { - // return false if only if power key pressed. - return mDownTimes.size() > 1 || mDownTimes.get(KEYCODE_POWER) == 0; + synchronized (mLock) { + if (forAllActiveRules((rule) -> rule.shouldInterceptKey(KEYCODE_POWER))) { + // return false if only if power key pressed. + return mDownTimes.size() > 1 || mDownTimes.get(KEYCODE_POWER) == 0; + } + return false; } - return false; } /** diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java index 1fa948cef216..9cf38e3ca92f 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -2609,6 +2609,7 @@ public class StatsPullAtomService extends SystemService { StatFs statFsData = new StatFs(Environment.getDataDirectory().getAbsolutePath()); StatFs statFsSystem = new StatFs(Environment.getRootDirectory().getAbsolutePath()); StatFs statFsCache = new StatFs(Environment.getDownloadCacheDirectory().getAbsolutePath()); + StatFs metadataFsSystem = new StatFs(Environment.getMetadataDirectory().getAbsolutePath()); pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, FrameworkStatsLog.DIRECTORY_USAGE__DIRECTORY__DATA, statFsData.getAvailableBytes(), @@ -2621,6 +2622,10 @@ public class StatsPullAtomService extends SystemService { pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, FrameworkStatsLog.DIRECTORY_USAGE__DIRECTORY__SYSTEM, statFsSystem.getAvailableBytes(), statFsSystem.getTotalBytes())); + + pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, + FrameworkStatsLog.DIRECTORY_USAGE__DIRECTORY__METADATA, + metadataFsSystem.getAvailableBytes(), metadataFsSystem.getTotalBytes())); return StatsManager.PULL_SUCCESS; } diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java index 357c23222658..ae4d46c387b9 100644 --- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java +++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java @@ -69,7 +69,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { * Telephony and network suggestions older than this value are considered too old to be used. */ @VisibleForTesting - static final long MAX_UTC_TIME_AGE_MILLIS = + static final long MAX_SUGGESTION_TIME_AGE_MILLIS = TELEPHONY_BUCKET_COUNT * TELEPHONY_BUCKET_SIZE_MILLIS; /** @@ -204,9 +204,9 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { @Override public synchronized void suggestExternalTime(@NonNull ExternalTimeSuggestion timeSuggestion) { - final TimestampedValue<Long> newUtcTime = timeSuggestion.getUtcTime(); + final TimestampedValue<Long> newUnixEpochTime = timeSuggestion.getUnixEpochTime(); - if (!validateAutoSuggestionTime(newUtcTime, timeSuggestion)) { + if (!validateAutoSuggestionTime(newUnixEpochTime, timeSuggestion)) { return; } @@ -218,9 +218,9 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { @Override public synchronized void suggestGnssTime(@NonNull GnssTimeSuggestion timeSuggestion) { - final TimestampedValue<Long> newUtcTime = timeSuggestion.getUtcTime(); + final TimestampedValue<Long> newUnixEpochTime = timeSuggestion.getUnixEpochTime(); - if (!validateAutoSuggestionTime(newUtcTime, timeSuggestion)) { + if (!validateAutoSuggestionTime(newUnixEpochTime, timeSuggestion)) { return; } @@ -232,19 +232,19 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { @Override public synchronized boolean suggestManualTime(@NonNull ManualTimeSuggestion suggestion) { - final TimestampedValue<Long> newUtcTime = suggestion.getUtcTime(); + final TimestampedValue<Long> newUnixEpochTime = suggestion.getUnixEpochTime(); - if (!validateSuggestionTime(newUtcTime, suggestion)) { + if (!validateSuggestionTime(newUnixEpochTime, suggestion)) { return false; } String cause = "Manual time suggestion received: suggestion=" + suggestion; - return setSystemClockIfRequired(ORIGIN_MANUAL, newUtcTime, cause); + return setSystemClockIfRequired(ORIGIN_MANUAL, newUnixEpochTime, cause); } @Override public synchronized void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSuggestion) { - if (!validateAutoSuggestionTime(timeSuggestion.getUtcTime(), timeSuggestion)) { + if (!validateAutoSuggestionTime(timeSuggestion.getUnixEpochTime(), timeSuggestion)) { return; } @@ -274,11 +274,11 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { // unlike time zone, where a user may lose connectivity when boarding a flight and where we // do want to "forget" old signals. Suggestions that are too old are discarded later in the // detection algorithm. - if (timeSuggestion.getUtcTime() == null) { + if (timeSuggestion.getUnixEpochTime() == null) { return; } - if (!validateAutoSuggestionTime(timeSuggestion.getUtcTime(), timeSuggestion)) { + if (!validateAutoSuggestionTime(timeSuggestion.getUnixEpochTime(), timeSuggestion)) { return; } @@ -365,14 +365,14 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { @GuardedBy("this") private boolean storeTelephonySuggestion( @NonNull TelephonyTimeSuggestion suggestion) { - TimestampedValue<Long> newUtcTime = suggestion.getUtcTime(); + TimestampedValue<Long> newUnixEpochTime = suggestion.getUnixEpochTime(); int slotIndex = suggestion.getSlotIndex(); TelephonyTimeSuggestion previousSuggestion = mSuggestionBySlotIndex.get(slotIndex); if (previousSuggestion != null) { // We can log / discard suggestions with obvious issues with the reference time clock. - if (previousSuggestion.getUtcTime() == null - || previousSuggestion.getUtcTime().getValue() == null) { + if (previousSuggestion.getUnixEpochTime() == null + || previousSuggestion.getUnixEpochTime().getValue() == null) { // This should be impossible given we only store validated suggestions. Slog.w(LOG_TAG, "Previous suggestion is null or has a null time." + " previousSuggestion=" + previousSuggestion @@ -381,7 +381,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { } long referenceTimeDifference = TimestampedValue.referenceTimeDifference( - newUtcTime, previousSuggestion.getUtcTime()); + newUnixEpochTime, previousSuggestion.getUnixEpochTime()); if (referenceTimeDifference < 0) { // The reference time is before the previously received suggestion. Ignore it. Slog.w(LOG_TAG, "Out of order telephony suggestion received." @@ -398,15 +398,15 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { } private boolean validateSuggestionTime( - @NonNull TimestampedValue<Long> newUtcTime, @NonNull Object suggestion) { - if (newUtcTime.getValue() == null) { + @NonNull TimestampedValue<Long> newUnixEpochTime, @NonNull Object suggestion) { + if (newUnixEpochTime.getValue() == null) { Slog.w(LOG_TAG, "Suggested time value is null. suggestion=" + suggestion); return false; } // We can validate the suggestion against the reference time clock. long elapsedRealtimeMillis = mEnvironment.elapsedRealtimeMillis(); - if (elapsedRealtimeMillis < newUtcTime.getReferenceTimeMillis()) { + if (elapsedRealtimeMillis < newUnixEpochTime.getReferenceTimeMillis()) { // elapsedRealtime clock went backwards? Slog.w(LOG_TAG, "New reference time is in the future? Ignoring." + " elapsedRealtimeMillis=" + elapsedRealtimeMillis @@ -417,17 +417,17 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { } private boolean validateAutoSuggestionTime( - @NonNull TimestampedValue<Long> newUtcTime, @NonNull Object suggestion) { - return validateSuggestionTime(newUtcTime, suggestion) - && validateSuggestionAgainstLowerBound(newUtcTime, suggestion); + @NonNull TimestampedValue<Long> newUnixEpochTime, @NonNull Object suggestion) { + return validateSuggestionTime(newUnixEpochTime, suggestion) + && validateSuggestionAgainstLowerBound(newUnixEpochTime, suggestion); } private boolean validateSuggestionAgainstLowerBound( - @NonNull TimestampedValue<Long> newUtcTime, @NonNull Object suggestion) { + @NonNull TimestampedValue<Long> newUnixEpochTime, @NonNull Object suggestion) { Instant lowerBound = mEnvironment.autoTimeLowerBound(); // Suggestion is definitely wrong if it comes before lower time bound. - if (lowerBound.isAfter(Instant.ofEpochMilli(newUtcTime.getValue()))) { + if (lowerBound.isAfter(Instant.ofEpochMilli(newUnixEpochTime.getValue()))) { Slog.w(LOG_TAG, "Suggestion points to time before lower bound, skipping it. " + "suggestion=" + suggestion + ", lower bound=" + lowerBound); return false; @@ -446,12 +446,12 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { // Try the different origins one at a time. int[] originPriorities = mEnvironment.autoOriginPriorities(); for (int origin : originPriorities) { - TimestampedValue<Long> newUtcTime = null; + TimestampedValue<Long> newUnixEpochTime = null; String cause = null; if (origin == ORIGIN_TELEPHONY) { TelephonyTimeSuggestion bestTelephonySuggestion = findBestTelephonySuggestion(); if (bestTelephonySuggestion != null) { - newUtcTime = bestTelephonySuggestion.getUtcTime(); + newUnixEpochTime = bestTelephonySuggestion.getUnixEpochTime(); cause = "Found good telephony suggestion." + ", bestTelephonySuggestion=" + bestTelephonySuggestion + ", detectionReason=" + detectionReason; @@ -459,7 +459,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { } else if (origin == ORIGIN_NETWORK) { NetworkTimeSuggestion networkSuggestion = findLatestValidNetworkSuggestion(); if (networkSuggestion != null) { - newUtcTime = networkSuggestion.getUtcTime(); + newUnixEpochTime = networkSuggestion.getUnixEpochTime(); cause = "Found good network suggestion." + ", networkSuggestion=" + networkSuggestion + ", detectionReason=" + detectionReason; @@ -467,7 +467,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { } else if (origin == ORIGIN_GNSS) { GnssTimeSuggestion gnssTimeSuggestion = findLatestValidGnssSuggestion(); if (gnssTimeSuggestion != null) { - newUtcTime = gnssTimeSuggestion.getUtcTime(); + newUnixEpochTime = gnssTimeSuggestion.getUnixEpochTime(); cause = "Found good gnss suggestion." + ", gnssTimeSuggestion=" + gnssTimeSuggestion + ", detectionReason=" + detectionReason; @@ -475,7 +475,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { } else if (origin == ORIGIN_EXTERNAL) { ExternalTimeSuggestion externalTimeSuggestion = findLatestValidExternalSuggestion(); if (externalTimeSuggestion != null) { - newUtcTime = externalTimeSuggestion.getUtcTime(); + newUnixEpochTime = externalTimeSuggestion.getUnixEpochTime(); cause = "Found good external suggestion." + ", externalTimeSuggestion=" + externalTimeSuggestion + ", detectionReason=" + detectionReason; @@ -487,8 +487,8 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { } // Update the system clock if a good suggestion has been found. - if (newUtcTime != null) { - setSystemClockIfRequired(origin, newUtcTime, cause); + if (newUnixEpochTime != null) { + setSystemClockIfRequired(origin, newUnixEpochTime, cause); return; } } @@ -545,7 +545,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { Slog.w(LOG_TAG, "Latest suggestion unexpectedly null for slotIndex." + " slotIndex=" + slotIndex); continue; - } else if (candidateSuggestion.getUtcTime() == null) { + } else if (candidateSuggestion.getUnixEpochTime() == null) { // Unexpected - we do not store empty suggestions. Slog.w(LOG_TAG, "Latest suggestion unexpectedly empty. " + " candidateSuggestion=" + candidateSuggestion); @@ -579,8 +579,8 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { long elapsedRealtimeMillis, @NonNull TelephonyTimeSuggestion timeSuggestion) { // Validate first. - TimestampedValue<Long> utcTime = timeSuggestion.getUtcTime(); - if (!validateSuggestionUtcTime(elapsedRealtimeMillis, utcTime)) { + TimestampedValue<Long> unixEpochTime = timeSuggestion.getUnixEpochTime(); + if (!validateSuggestionUnixEpochTime(elapsedRealtimeMillis, unixEpochTime)) { Slog.w(LOG_TAG, "Existing suggestion found to be invalid" + " elapsedRealtimeMillis=" + elapsedRealtimeMillis + ", timeSuggestion=" + timeSuggestion); @@ -589,7 +589,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { // The score is based on the age since receipt. Suggestions are bucketed so two // suggestions in the same bucket from different slotIndexs are scored the same. - long ageMillis = elapsedRealtimeMillis - utcTime.getReferenceTimeMillis(); + long ageMillis = elapsedRealtimeMillis - unixEpochTime.getReferenceTimeMillis(); // Turn the age into a discrete value: 0 <= bucketIndex < TELEPHONY_BUCKET_COUNT. int bucketIndex = (int) (ageMillis / TELEPHONY_BUCKET_SIZE_MILLIS); @@ -611,9 +611,9 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { return null; } - TimestampedValue<Long> utcTime = networkSuggestion.getUtcTime(); + TimestampedValue<Long> unixEpochTime = networkSuggestion.getUnixEpochTime(); long elapsedRealTimeMillis = mEnvironment.elapsedRealtimeMillis(); - if (!validateSuggestionUtcTime(elapsedRealTimeMillis, utcTime)) { + if (!validateSuggestionUnixEpochTime(elapsedRealTimeMillis, unixEpochTime)) { // The latest suggestion is not valid, usually due to its age. return null; } @@ -631,9 +631,9 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { return null; } - TimestampedValue<Long> utcTime = gnssTimeSuggestion.getUtcTime(); + TimestampedValue<Long> unixEpochTime = gnssTimeSuggestion.getUnixEpochTime(); long elapsedRealTimeMillis = mEnvironment.elapsedRealtimeMillis(); - if (!validateSuggestionUtcTime(elapsedRealTimeMillis, utcTime)) { + if (!validateSuggestionUnixEpochTime(elapsedRealTimeMillis, unixEpochTime)) { // The latest suggestion is not valid, usually due to its age. return null; } @@ -651,9 +651,9 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { return null; } - TimestampedValue<Long> utcTime = externalTimeSuggestion.getUtcTime(); + TimestampedValue<Long> unixEpochTime = externalTimeSuggestion.getUnixEpochTime(); long elapsedRealTimeMillis = mEnvironment.elapsedRealtimeMillis(); - if (!validateSuggestionUtcTime(elapsedRealTimeMillis, utcTime)) { + if (!validateSuggestionUnixEpochTime(elapsedRealTimeMillis, unixEpochTime)) { // The latest suggestion is not valid, usually due to its age. return null; } @@ -844,9 +844,9 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { return mLastExternalSuggestion.get(); } - private static boolean validateSuggestionUtcTime( - long elapsedRealtimeMillis, TimestampedValue<Long> utcTime) { - long referenceTimeMillis = utcTime.getReferenceTimeMillis(); + private static boolean validateSuggestionUnixEpochTime( + long elapsedRealtimeMillis, TimestampedValue<Long> unixEpochTime) { + long referenceTimeMillis = unixEpochTime.getReferenceTimeMillis(); if (referenceTimeMillis > elapsedRealtimeMillis) { // Future reference times are ignored. They imply the reference time was wrong, or the // elapsed realtime clock used to derive it has gone backwards, neither of which are @@ -860,6 +860,6 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { // made and never replaced, it could also mean that the time detection code remains // opinionated using a bad invalid suggestion. This caps that edge case at MAX_AGE_MILLIS. long ageMillis = elapsedRealtimeMillis - referenceTimeMillis; - return ageMillis <= MAX_UTC_TIME_AGE_MILLIS; + return ageMillis <= MAX_SUGGESTION_TIME_AGE_MILLIS; } } diff --git a/services/core/java/com/android/server/timezonedetector/OWNERS b/services/core/java/com/android/server/timezonedetector/OWNERS index 029324246c91..485a0ddb06d8 100644 --- a/services/core/java/com/android/server/timezonedetector/OWNERS +++ b/services/core/java/com/android/server/timezonedetector/OWNERS @@ -3,5 +3,6 @@ # ultimately referenced by other OWNERS files for components maintained by the same team. nfuller@google.com jmorace@google.com +kanyinsola@google.com mingaleev@google.com narayan@google.com diff --git a/services/core/java/com/android/server/tracing/TracingServiceProxy.java b/services/core/java/com/android/server/tracing/TracingServiceProxy.java index 27c0beee9c27..10e868d06766 100644 --- a/services/core/java/com/android/server/tracing/TracingServiceProxy.java +++ b/services/core/java/com/android/server/tracing/TracingServiceProxy.java @@ -15,6 +15,13 @@ */ package com.android.server.tracing; +import static com.android.internal.util.FrameworkStatsLog.TRACING_SERVICE_REPORT_EVENT; +import static com.android.internal.util.FrameworkStatsLog.TRACING_SERVICE_REPORT_EVENT__EVENT__TRACING_SERVICE_REPORT_BEGIN; +import static com.android.internal.util.FrameworkStatsLog.TRACING_SERVICE_REPORT_EVENT__EVENT__TRACING_SERVICE_REPORT_BIND_PERM_INCORRECT; +import static com.android.internal.util.FrameworkStatsLog.TRACING_SERVICE_REPORT_EVENT__EVENT__TRACING_SERVICE_REPORT_SVC_COMM_ERROR; +import static com.android.internal.util.FrameworkStatsLog.TRACING_SERVICE_REPORT_EVENT__EVENT__TRACING_SERVICE_REPORT_SVC_HANDOFF; +import static com.android.internal.util.FrameworkStatsLog.TRACING_SERVICE_REPORT_EVENT__EVENT__TRACING_SERVICE_REPORT_SVC_PERM_MISSING; + import android.Manifest; import android.annotation.NonNull; import android.content.ComponentName; @@ -39,6 +46,7 @@ import android.util.LruCache; import android.util.Slog; import com.android.internal.infra.ServiceConnector; +import com.android.internal.util.FrameworkStatsLog; import com.android.server.SystemService; import java.io.IOException; @@ -71,6 +79,17 @@ public class TracingServiceProxy extends SystemService { private static final String INTENT_ACTION_NOTIFY_SESSION_STOLEN = "com.android.traceur.NOTIFY_SESSION_STOLEN"; + private static final int REPORT_BEGIN = + TRACING_SERVICE_REPORT_EVENT__EVENT__TRACING_SERVICE_REPORT_BEGIN; + private static final int REPORT_SVC_HANDOFF = + TRACING_SERVICE_REPORT_EVENT__EVENT__TRACING_SERVICE_REPORT_SVC_HANDOFF; + private static final int REPORT_BIND_PERM_INCORRECT = + TRACING_SERVICE_REPORT_EVENT__EVENT__TRACING_SERVICE_REPORT_BIND_PERM_INCORRECT; + private static final int REPORT_SVC_PERM_MISSING = + TRACING_SERVICE_REPORT_EVENT__EVENT__TRACING_SERVICE_REPORT_SVC_PERM_MISSING; + private static final int REPORT_SVC_COMM_ERROR = + TRACING_SERVICE_REPORT_EVENT__EVENT__TRACING_SERVICE_REPORT_SVC_COMM_ERROR; + private final Context mContext; private final PackageManager mPackageManager; private final LruCache<ComponentName, ServiceConnector<IMessenger>> mCachedReporterServices; @@ -134,17 +153,24 @@ public class TracingServiceProxy extends SystemService { } private void reportTrace(@NonNull TraceReportParams params) { + FrameworkStatsLog.write(TRACING_SERVICE_REPORT_EVENT, REPORT_BEGIN, + params.uuidLsb, params.uuidMsb); + // We don't need to do any permission checks on the caller because access // to this service is guarded by SELinux. ComponentName component = new ComponentName(params.reporterPackageName, params.reporterClassName); if (!hasBindServicePermission(component)) { + FrameworkStatsLog.write(TRACING_SERVICE_REPORT_EVENT, REPORT_BIND_PERM_INCORRECT, + params.uuidLsb, params.uuidMsb); return; } boolean hasDumpPermission = hasPermission(component, Manifest.permission.DUMP); boolean hasUsageStatsPermission = hasPermission(component, Manifest.permission.PACKAGE_USAGE_STATS); if (!hasDumpPermission || !hasUsageStatsPermission) { + FrameworkStatsLog.write(TRACING_SERVICE_REPORT_EVENT, REPORT_SVC_PERM_MISSING, + params.uuidLsb, params.uuidMsb); return; } final long ident = Binder.clearCallingIdentity(); @@ -178,8 +204,13 @@ public class TracingServiceProxy extends SystemService { message.what = TraceReportService.MSG_REPORT_TRACE; message.obj = params; messenger.send(message); + + FrameworkStatsLog.write(TRACING_SERVICE_REPORT_EVENT, REPORT_SVC_HANDOFF, + params.uuidLsb, params.uuidMsb); }).whenComplete((res, err) -> { if (err != null) { + FrameworkStatsLog.write(TRACING_SERVICE_REPORT_EVENT, REPORT_SVC_COMM_ERROR, + params.uuidLsb, params.uuidMsb); Slog.e(TAG, "Failed to report trace", err); } try { diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java index a17e79273e41..30e261725a73 100644 --- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -146,7 +146,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { filter.addAction(ACTION_CARRIER_CONFIG_CHANGED); filter.addAction(ACTION_MULTI_SIM_CONFIG_CHANGED); - mContext.registerReceiver(this, filter, null, mHandler); + mContext.registerReceiver(this, filter, null, mHandler, Context.RECEIVER_NOT_EXPORTED); mSubscriptionManager.addOnSubscriptionsChangedListener( executor, mSubscriptionChangedListener); mTelephonyManager.registerTelephonyCallback(executor, mActiveDataSubIdListener); diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java index 8b80b4a0b21e..597f7f284730 100644 --- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java +++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java @@ -78,6 +78,7 @@ import android.os.PowerManager.WakeLock; import android.os.Process; import android.os.SystemClock; import android.provider.Settings; +import android.telephony.TelephonyManager; import android.util.ArraySet; import android.util.Slog; @@ -163,6 +164,14 @@ import java.util.function.Consumer; public class VcnGatewayConnection extends StateMachine { private static final String TAG = VcnGatewayConnection.class.getSimpleName(); + // Matches DataConnection.NETWORK_TYPE private constant, and magic string from + // ConnectivityManager#getNetworkTypeName() + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final String NETWORK_INFO_NETWORK_TYPE_STRING = "MOBILE"; + + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final String NETWORK_INFO_EXTRA_INFO = "VCN"; + @VisibleForTesting(visibility = Visibility.PRIVATE) static final InetAddress DUMMY_ADDR = InetAddresses.parseNumericAddress("192.0.2.0"); @@ -1631,6 +1640,12 @@ public class VcnGatewayConnection extends StateMachine { final NetworkAgentConfig nac = new NetworkAgentConfig.Builder() .setLegacyType(ConnectivityManager.TYPE_MOBILE) + .setLegacyTypeName(NETWORK_INFO_NETWORK_TYPE_STRING) + .setLegacySubType(TelephonyManager.NETWORK_TYPE_UNKNOWN) + .setLegacySubTypeName( + TelephonyManager.getNetworkTypeName( + TelephonyManager.NETWORK_TYPE_UNKNOWN)) + .setLegacyExtraInfo(NETWORK_INFO_EXTRA_INFO) .build(); final VcnNetworkAgent agent = diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index b52e527b0556..b685d484db79 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -1038,6 +1038,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A pw.print(" forceNewConfig="); pw.println(forceNewConfig); pw.print(prefix); pw.print("mActivityType="); pw.println(activityTypeToString(getActivityType())); + pw.print(prefix); pw.print("mImeInsetsFrozenUntilStartInput="); + pw.println(mImeInsetsFrozenUntilStartInput); if (requestedVrComponent != null) { pw.print(prefix); pw.print("requestedVrComponent="); @@ -4932,6 +4934,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_STOPPED); break; case DESTROYED: + if (app != null && (mVisible || mVisibleRequested)) { + // The app may be died while visible (no PAUSED state). + mAtmService.updateBatteryStats(this, false); + } mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_DESTROYED); // Fall through. case DESTROYING: diff --git a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java index f61cc94b6181..a83a033985c5 100644 --- a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java +++ b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java @@ -65,7 +65,16 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl @Override public void binderDied() { synchronized (mGlobalLock) { - mOrganizersByFeatureIds.remove(mFeature).destroy(); + IDisplayAreaOrganizer featureOrganizer = getOrganizerByFeature(mFeature); + if (featureOrganizer != null) { + IBinder organizerBinder = featureOrganizer.asBinder(); + if (!organizerBinder.equals(mOrganizer.asBinder()) && + organizerBinder.isBinderAlive()) { + Slog.d(TAG, "Dead organizer replaced for feature=" + mFeature); + return; + } + mOrganizersByFeatureIds.remove(mFeature).destroy(); + } } } } @@ -172,7 +181,7 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl organizer.asBinder(), uid); mOrganizersByFeatureIds.entrySet().removeIf((entry) -> { final boolean matches = entry.getValue().mOrganizer.asBinder() - == organizer.asBinder(); + .equals(organizer.asBinder()); if (matches) { entry.getValue().destroy(); } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 9335846e7805..bb8d6ef8fb12 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -3969,11 +3969,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp * which controls the visibility and animation of the input method window. */ void updateImeInputAndControlTarget(WindowState target) { + if (target != null && target.mActivityRecord != null) { + target.mActivityRecord.mImeInsetsFrozenUntilStartInput = false; + } if (mImeInputTarget != target) { ProtoLog.i(WM_DEBUG_IME, "setInputMethodInputTarget %s", target); - if (target != null && target.mActivityRecord != null) { - target.mActivityRecord.mImeInsetsFrozenUntilStartInput = false; - } setImeInputTarget(target); updateImeControlTarget(); } diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index ee4c629189dc..152b4bcffc4e 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -42,13 +42,12 @@ import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ROOT_TASK; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; -import static java.lang.Integer.MIN_VALUE; - import android.annotation.ColorInt; import android.annotation.Nullable; import android.app.ActivityOptions; import android.app.WindowConfiguration; import android.content.res.Configuration; +import android.graphics.Color; import android.os.UserHandle; import android.util.IntArray; import android.util.Slog; @@ -83,9 +82,9 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { DisplayContent mDisplayContent; /** - * A color layer that serves as a solid color background to certain animations. + * Keeps track of the last set color layer so that it can be reset during surface migrations. */ - private SurfaceControl mColorBackgroundLayer; + private @ColorInt int mBackgroundColor = 0; /** * This counter is used to make sure we don't prematurely clear the background color in the @@ -367,6 +366,14 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { } @Override + void setInitialSurfaceControlProperties(SurfaceControl.Builder b) { + // We want an effect layer instead of the default container layer so that we can set a + // background color on it for task animations. + b.setEffectLayer(); + super.setInitialSurfaceControlProperties(b); + } + + @Override void addChild(WindowContainer child, int position) { if (child.asTaskDisplayArea() != null) { if (DEBUG_ROOT_TASK) { @@ -980,11 +987,6 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) { if (getParent() != null) { super.onParentChanged(newParent, oldParent, () -> { - mColorBackgroundLayer = makeChildSurface(null) - .setColorLayer() - .setName("colorBackgroundLayer") - .setCallsite("TaskDisplayArea.onParentChanged") - .build(); mAppAnimationLayer = makeChildSurface(null) .setName("animationLayer") .setCallsite("TaskDisplayArea.onParentChanged") @@ -1011,13 +1013,11 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { } else { super.onParentChanged(newParent, oldParent); mWmService.mTransactionFactory.get() - .remove(mColorBackgroundLayer) .remove(mAppAnimationLayer) .remove(mBoostedAppAnimationLayer) .remove(mHomeAppAnimationLayer) .remove(mSplitScreenDividerAnchor) .apply(); - mColorBackgroundLayer = null; mAppAnimationLayer = null; mBoostedAppAnimationLayer = null; mHomeAppAnimationLayer = null; @@ -1025,35 +1025,29 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { } } - void setBackgroundColor(@ColorInt int color) { - if (mColorBackgroundLayer == null) { - return; - } - - float r = ((color >> 16) & 0xff) / 255.0f; - float g = ((color >> 8) & 0xff) / 255.0f; - float b = ((color >> 0) & 0xff) / 255.0f; - float a = ((color >> 24) & 0xff) / 255.0f; - + void setBackgroundColor(@ColorInt int colorInt) { + mBackgroundColor = colorInt; + Color color = Color.valueOf(colorInt); mColorLayerCounter++; - getPendingTransaction().setLayer(mColorBackgroundLayer, MIN_VALUE) - .setColor(mColorBackgroundLayer, new float[]{r, g, b}) - .setAlpha(mColorBackgroundLayer, a) - .setWindowCrop(mColorBackgroundLayer, getSurfaceWidth(), getSurfaceHeight()) - .setPosition(mColorBackgroundLayer, 0, 0) - .show(mColorBackgroundLayer); - - scheduleAnimation(); + // Only apply the background color if the TDA is actually attached and has a valid surface + // to set the background color on. We still want to keep track of the background color state + // even if we are not showing it for when/if the TDA is reattached and gets a valid surface + if (mSurfaceControl != null) { + getPendingTransaction() + .setColor(mSurfaceControl, + new float[]{color.red(), color.green(), color.blue()}); + scheduleAnimation(); + } } void clearBackgroundColor() { mColorLayerCounter--; // Only clear the color layer if we have received the same amounts of clear as set - // requests. - if (mColorLayerCounter == 0) { - getPendingTransaction().hide(mColorBackgroundLayer); + // requests and TDA has a non null surface control (i.e. is attached) + if (mColorLayerCounter == 0 && mSurfaceControl != null) { + getPendingTransaction().unsetColor(mSurfaceControl); scheduleAnimation(); } } @@ -1061,12 +1055,16 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { @Override void migrateToNewSurfaceControl(SurfaceControl.Transaction t) { super.migrateToNewSurfaceControl(t); + + if (mColorLayerCounter > 0) { + setBackgroundColor(mBackgroundColor); + } + if (mAppAnimationLayer == null) { return; } // As TaskDisplayArea is getting a new surface, reparent and reorder the child surfaces. - t.reparent(mColorBackgroundLayer, mSurfaceControl); t.reparent(mAppAnimationLayer, mSurfaceControl); t.reparent(mBoostedAppAnimationLayer, mSurfaceControl); t.reparent(mHomeAppAnimationLayer, mSurfaceControl); diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index a518222c3bde..71893f49481f 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -288,7 +288,7 @@ class TaskSnapshotController { } final ActivityRecord activity = result.first; final WindowState mainWindow = result.second; - final Rect contentInsets = getSystemBarInsets(task.getBounds(), + final Rect contentInsets = getSystemBarInsets(mainWindow.getFrame(), mainWindow.getInsetsStateWithVisibilityOverride()); InsetUtils.addInsets(contentInsets, activity.getLetterboxInsets()); @@ -554,7 +554,7 @@ class TaskSnapshotController { final LayoutParams attrs = mainWindow.getAttrs(); final Rect taskBounds = task.getBounds(); final InsetsState insetsState = mainWindow.getInsetsStateWithVisibilityOverride(); - final Rect systemBarInsets = getSystemBarInsets(taskBounds, insetsState); + final Rect systemBarInsets = getSystemBarInsets(mainWindow.getFrame(), insetsState); final SystemBarBackgroundPainter decorPainter = new SystemBarBackgroundPainter(attrs.flags, attrs.privateFlags, attrs.insetsFlags.appearance, task.getTaskDescription(), mHighResTaskSnapshotScale, insetsState); diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index e48b5e17739b..e755b9e5c51d 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -47,7 +47,6 @@ cc_library_static { "com_android_server_lights_LightsService.cpp", "com_android_server_location_GnssLocationProvider.cpp", "com_android_server_locksettings_SyntheticPasswordManager.cpp", - "com_android_server_net_NetworkStatsService.cpp", "com_android_server_power_PowerManagerService.cpp", "com_android_server_powerstats_PowerStatsService.cpp", "com_android_server_hint_HintManagerService.cpp", @@ -73,7 +72,6 @@ cc_library_static { "com_android_server_sensor_SensorService.cpp", "onload.cpp", ":lib_cachedAppOptimizer_native", - ":lib_networkStatsFactory_native", ], include_dirs: [ @@ -85,7 +83,6 @@ cc_library_static { header_libs: [ "bionic_libc_platform_headers", - "bpf_connectivity_headers", ], } @@ -140,9 +137,6 @@ cc_defaults { "libhidlbase", "libutils", "libhwui", - "libbpf_android", - "libnetdutils", - "libnetworkstats", "libpsi", "libdataloader", "libincfs", @@ -205,13 +199,6 @@ cc_defaults { } filegroup { - name: "lib_networkStatsFactory_native", - srcs: [ - "com_android_server_net_NetworkStatsFactory.cpp", - ], -} - -filegroup { name: "lib_cachedAppOptimizer_native", srcs: [ "com_android_server_am_CachedAppOptimizer.cpp", diff --git a/services/core/jni/BroadcastRadio/types.h b/services/core/jni/BroadcastRadio/types.h index 910bb7c0a4d1..4d286bf05650 100644 --- a/services/core/jni/BroadcastRadio/types.h +++ b/services/core/jni/BroadcastRadio/types.h @@ -30,13 +30,13 @@ namespace BroadcastRadio { // Keep in sync with STATUS_* constants from RadioManager.java. enum class Status : jint { OK = 0, - ERROR = -0x80000000ll, // Integer.MIN_VALUE + ERROR = -0x80000000LL, // Integer.MIN_VALUE PERMISSION_DENIED = -1, // -EPERM - NO_INIT = -19, // -ENODEV - BAD_VALUE = -22, // -EINVAL - DEAD_OBJECT = -32, // -EPIPE - INVALID_OPERATION = -38, // -ENOSYS - TIMED_OUT = -110, // -ETIMEDOUT + NO_INIT = -19, // -ENODEV + BAD_VALUE = -22, // -EINVAL + DEAD_OBJECT = -32, // -EPIPE + INVALID_OPERATION = -38, // -ENOSYS + TIMED_OUT = -110, // -ETIMEDOUT }; // Keep in sync with REGION_* constants from RadioManager.java. diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index ff61abc4ff7f..9d3edd6e8b2e 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -51,8 +51,6 @@ int register_android_server_Watchdog(JNIEnv* env); int register_android_server_HardwarePropertiesManagerService(JNIEnv* env); int register_android_server_SyntheticPasswordManager(JNIEnv* env); int register_android_hardware_display_DisplayViewport(JNIEnv* env); -int register_android_server_net_NetworkStatsFactory(JNIEnv* env); -int register_android_server_net_NetworkStatsService(JNIEnv* env); int register_android_server_am_CachedAppOptimizer(JNIEnv* env); int register_android_server_am_LowMemDetector(JNIEnv* env); int register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(JNIEnv* env); @@ -107,8 +105,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_server_SyntheticPasswordManager(env); register_android_graphics_GraphicsStatsService(env); register_android_hardware_display_DisplayViewport(env); - register_android_server_net_NetworkStatsFactory(env); - register_android_server_net_NetworkStatsService(env); register_android_server_am_CachedAppOptimizer(env); register_android_server_am_LowMemDetector(env); register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(env); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 710a9cf74112..4825f09be4d7 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -54,7 +54,6 @@ import android.hardware.display.DisplayManagerInternal; import android.net.ConnectivityManager; import android.net.ConnectivityModuleConnector; import android.net.NetworkStackClient; -import android.net.TrafficStats; import android.os.BaseBundle; import android.os.Binder; import android.os.Build; @@ -141,7 +140,6 @@ import com.android.server.media.MediaRouterService; import com.android.server.media.metrics.MediaMetricsManagerService; import com.android.server.media.projection.MediaProjectionManagerService; import com.android.server.net.NetworkPolicyManagerService; -import com.android.server.net.NetworkStatsService; import com.android.server.net.watchlist.NetworkWatchlistService; import com.android.server.notification.NotificationManagerService; import com.android.server.oemlock.OemLockService; @@ -379,6 +377,8 @@ public final class SystemServer implements Dumpable { "com.android.server.media.MediaResourceMonitorService"; private static final String CONNECTIVITY_SERVICE_INITIALIZER_CLASS = "com.android.server.ConnectivityServiceInitializer"; + private static final String NETWORK_STATS_SERVICE_INITIALIZER_CLASS = + "com.android.server.NetworkStatsServiceInitializer"; private static final String IP_CONNECTIVITY_METRICS_CLASS = "com.android.server.connectivity.IpConnectivityMetrics"; private static final String MEDIA_COMMUNICATION_SERVICE_CLASS = @@ -1334,10 +1334,8 @@ public final class SystemServer implements Dumpable { DynamicSystemService dynamicSystem = null; IStorageManager storageManager = null; NetworkManagementService networkManagement = null; - IpSecService ipSecService = null; VpnManagerService vpnManager = null; VcnManagementService vcnManagement = null; - NetworkStatsService networkStats = null; NetworkPolicyManagerService networkPolicy = null; WindowManagerService wm = null; SerialService serial = null; @@ -1806,16 +1804,6 @@ public final class SystemServer implements Dumpable { } t.traceEnd(); - - t.traceBegin("StartIpSecService"); - try { - ipSecService = IpSecService.create(context); - ServiceManager.addService(Context.IPSEC_SERVICE, ipSecService); - } catch (Throwable e) { - reportWtf("starting IpSec Service", e); - } - t.traceEnd(); - t.traceBegin("StartFontManagerService"); mSystemServiceManager.startService(new FontManagerService.Lifecycle(context, safeMode)); t.traceEnd(); @@ -1836,13 +1824,10 @@ public final class SystemServer implements Dumpable { t.traceEnd(); t.traceBegin("StartNetworkStatsService"); - try { - networkStats = NetworkStatsService.create(context); - ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats); - TrafficStats.init(context); - } catch (Throwable e) { - reportWtf("starting NetworkStats Service", e); - } + // This has to be called before NetworkPolicyManager because NetworkPolicyManager + // needs to take NetworkStatsService to initialize. + mSystemServiceManager.startServiceFromJar(NETWORK_STATS_SERVICE_INITIALIZER_CLASS, + CONNECTIVITY_SERVICE_APEX_PATH); t.traceEnd(); t.traceBegin("StartNetworkPolicyManagerService"); @@ -2659,7 +2644,6 @@ public final class SystemServer implements Dumpable { // These are needed to propagate to the runnable below. final NetworkManagementService networkManagementF = networkManagement; - final NetworkStatsService networkStatsF = networkStats; final NetworkPolicyManagerService networkPolicyF = networkPolicy; final CountryDetectorService countryDetectorF = countryDetector; final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater; @@ -2667,7 +2651,6 @@ public final class SystemServer implements Dumpable { final TelephonyRegistry telephonyRegistryF = telephonyRegistry; final MediaRouterService mediaRouterF = mediaRouter; final MmsServiceBroker mmsServiceF = mmsService; - final IpSecService ipSecServiceF = ipSecService; final VpnManagerService vpnManagerF = vpnManager; final VcnManagementService vcnManagementF = vcnManagement; final WindowManagerService windowManagerF = wm; @@ -2757,24 +2740,6 @@ public final class SystemServer implements Dumpable { .networkScoreAndNetworkManagementServiceReady(); } t.traceEnd(); - t.traceBegin("MakeIpSecServiceReady"); - try { - if (ipSecServiceF != null) { - ipSecServiceF.systemReady(); - } - } catch (Throwable e) { - reportWtf("making IpSec Service ready", e); - } - t.traceEnd(); - t.traceBegin("MakeNetworkStatsServiceReady"); - try { - if (networkStatsF != null) { - networkStatsF.systemReady(); - } - } catch (Throwable e) { - reportWtf("making Network Stats Service ready", e); - } - t.traceEnd(); t.traceBegin("MakeConnectivityServiceReady"); try { if (connectivityF != null) { diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java index 62a16f7f24fd..c5f990d52b82 100644 --- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java +++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java @@ -60,6 +60,12 @@ public final class ProfcollectForwardingService extends SystemService { private static ProfcollectForwardingService sSelfService; private final Handler mHandler = new ProfcollectdHandler(IoThread.getHandler().getLooper()); + private IProviderStatusCallback mProviderStatusCallback = new IProviderStatusCallback.Stub() { + public void onProviderReady() { + mHandler.sendEmptyMessage(ProfcollectdHandler.MESSAGE_REGISTER_SCHEDULERS); + } + }; + public ProfcollectForwardingService(Context context) { super(context); @@ -93,13 +99,23 @@ public final class ProfcollectForwardingService extends SystemService { } BackgroundThread.get().getThreadHandler().post(() -> { if (serviceHasSupportedTraceProvider()) { - registerObservers(); - ProfcollectBGJobService.schedule(getContext()); + registerProviderStatusCallback(); } }); } } + private void registerProviderStatusCallback() { + if (mIProfcollect == null) { + return; + } + try { + mIProfcollect.registerProviderStatusCallback(mProviderStatusCallback); + } catch (RemoteException e) { + Log.e(LOG_TAG, e.getMessage()); + } + } + private boolean serviceHasSupportedTraceProvider() { if (mIProfcollect == null) { return false; @@ -141,6 +157,7 @@ public final class ProfcollectForwardingService extends SystemService { } public static final int MESSAGE_BINDER_CONNECT = 0; + public static final int MESSAGE_REGISTER_SCHEDULERS = 1; @Override public void handleMessage(android.os.Message message) { @@ -148,6 +165,10 @@ public final class ProfcollectForwardingService extends SystemService { case MESSAGE_BINDER_CONNECT: connectNativeService(); break; + case MESSAGE_REGISTER_SCHEDULERS: + registerObservers(); + ProfcollectBGJobService.schedule(getContext()); + break; default: throw new AssertionError("Unknown message: " + message); } diff --git a/services/proguard.flags b/services/proguard.flags index 5d01d3e7f85c..425da6c11177 100644 --- a/services/proguard.flags +++ b/services/proguard.flags @@ -1,21 +1,112 @@ -# TODO(b/196084106): Refine and optimize this configuration. Note that this +# TODO(b/210510433): Refine and optimize this configuration. Note that this # configuration is only used when `SOONG_CONFIG_ANDROID_SYSTEM_OPTIMIZE_JAVA=true`. --keep,allowoptimization,allowaccessmodification class ** { - !synthetic *; + +# Preserve line number information for debugging stack traces. +-keepattributes SourceFile,LineNumberTable + +# Allows making private and protected methods/fields public as part of +# optimization. This enables inlining of trivial getter/setter methods. +-allowaccessmodification + +# Process entrypoint +-keep class com.android.server.SystemServer { + public static void main(java.lang.String[]); +} + +# APIs referenced by dependent JAR files and modules +-keep @interface android.annotation.SystemApi +-keep @android.annotation.SystemApi class * { + public protected *; +} +-keepclasseswithmembers class * { + @android.annotation.SystemApi *; +} + +# Derivatives of SystemService and other services created via reflection +-keep,allowoptimization,allowaccessmodification class * extends com.android.server.SystemService { + public <methods>; +} +-keep,allowoptimization,allowaccessmodification class * extends com.android.server.devicepolicy.BaseIDevicePolicyManager { + public <init>(...); +} +-keep,allowoptimization,allowaccessmodification class com.android.server.wallpaper.WallpaperManagerService { + public <init>(...); +} + +# Binder interfaces +-keep,allowoptimization,allowaccessmodification class * extends android.os.IInterface +-keep,allowoptimization,allowaccessmodification class * extends android.os.IHwInterface + +# Global entities normally kept through explicit Manifest entries +# TODO(b/210510433): Revisit and consider generating from frameworks/base/core/res/AndroidManifest.xml, +# by including that manifest with the library rule that triggers optimization. +-keep,allowoptimization,allowaccessmodification class com.android.server.** extends android.app.Activity +-keep,allowoptimization,allowaccessmodification class com.android.server.** extends android.app.Service +-keep,allowoptimization,allowaccessmodification class com.android.server.** extends android.app.backup.BackupAgent +-keep,allowoptimization,allowaccessmodification class com.android.server.** extends android.content.BroadcastReceiver +-keep,allowoptimization,allowaccessmodification class com.android.server.** extends android.content.ContentProvider +-keep,allowoptimization,allowaccessmodification class com.android.server.** extends android.preference.Preference +-keep,allowoptimization,allowaccessmodification class com.android.server.** extends android.view.View { + public <init>(...); } -# Various classes subclassed in ethernet-service (avoid marking final). +# Various classes subclassed in or referenced via JNI in ethernet-service -keep public class android.net.** { *; } +-keep,allowoptimization,allowaccessmodification class com.android.net.module.util.* { *; } +-keep,allowoptimization,allowaccessmodification public class com.android.server.net.IpConfigStore { *; } +-keep,allowoptimization,allowaccessmodification public class com.android.server.net.BaseNetworkObserver { *; } -# Referenced via CarServiceHelperService in car-frameworks-service (avoid removing). +# Referenced via CarServiceHelperService in car-frameworks-service (avoid removing) -keep public class com.android.server.utils.Slogf { *; } -# Allows making private and protected methods/fields public as part of -# optimization. This enables inlining of trivial getter/setter methods. --allowaccessmodification +# Notification extractors +# TODO(b/210510433): Revisit and consider generating from frameworks/base/core/res/res/values/config.xml. +-keep,allowoptimization,allowaccessmodification public class com.android.server.notification.** implements com.android.server.notification.NotificationSignalExtractor + +# JNI keep rules +# TODO(b/210510433): Revisit and fix with @Keep, or consider auto-generating from +# frameworks/base/services/core/jni/onload.cpp. +-keep,allowoptimization,allowaccessmodification class com.android.server.broadcastradio.hal1.BroadcastRadioService { *; } +-keep,allowoptimization,allowaccessmodification class com.android.server.broadcastradio.hal1.Convert { *; } +-keep,allowoptimization,allowaccessmodification class com.android.server.broadcastradio.hal1.Tuner { *; } +-keep,allowoptimization,allowaccessmodification class com.android.server.broadcastradio.hal1.TunerCallback { *; } +-keep,allowoptimization,allowaccessmodification class com.android.server.location.gnss.GnssConfiguration$HalInterfaceVersion { *; } +-keep,allowoptimization,allowaccessmodification class com.android.server.location.gnss.GnssPowerStats { *; } +-keep,allowoptimization,allowaccessmodification class com.android.server.location.gnss.hal.GnssNative { *; } +-keep,allowoptimization,allowaccessmodification class com.android.server.pm.PackageManagerShellCommandDataLoader { *; } +-keep,allowoptimization,allowaccessmodification class com.android.server.sensors.SensorManagerInternal$ProximityActiveListener { *; } +-keep,allowoptimization,allowaccessmodification class com.android.server.sensors.SensorService { *; } +-keep,allowoptimization,allowaccessmodification class com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareImpl$AudioSessionProvider$AudioSession { *; } +-keep,allowoptimization,allowaccessmodification class com.android.server.soundtrigger_middleware.ExternalCaptureStateTracker { *; } +-keep,allowoptimization,allowaccessmodification class com.android.server.storage.AppFuseBridge { *; } +-keep,allowoptimization,allowaccessmodification class com.android.server.tv.TvInputHal { *; } +-keep,allowoptimization,allowaccessmodification class com.android.server.usb.UsbAlsaJackDetector { *; } +-keep,allowoptimization,allowaccessmodification class com.android.server.usb.UsbMidiDevice { *; } +-keep,allowoptimization,allowaccessmodification class com.android.server.vibrator.VibratorController$OnVibrationCompleteListener { *; } +-keep,allowoptimization,allowaccessmodification class com.android.server.vibrator.VibratorManagerService$OnSyncedVibrationCompleteListener { *; } +-keepclasseswithmembers,allowoptimization,allowaccessmodification class com.android.server.** { + *** *FromNative(...); +} +-keep,allowoptimization,allowaccessmodification class com.android.server.input.InputManagerService { + <methods>; +} +-keep,allowoptimization,allowaccessmodification class com.android.server.usb.UsbHostManager { + *** usbDeviceRemoved(...); + *** usbDeviceAdded(...); +} +-keep,allowoptimization,allowaccessmodification class **.*NativeWrapper* { *; } -# Disallow accessmodification for soundtrigger classes. Logging via reflective -# public member traversal can cause infinite loops. See b/210901706. --keep,allowoptimization class com.android.server.soundtrigger_middleware.** { - !synthetic *; +# Miscellaneous reflection keep rules +# TODO(b/210510433): Revisit and fix with @Keep. +-keep,allowoptimization,allowaccessmodification class com.android.server.usage.AppStandbyController { + public <init>(...); } +-keep,allowoptimization,allowaccessmodification class android.hardware.usb.gadget.** { *; } + +# Needed when optimizations enabled +# TODO(b/210510433): Revisit and fix with @Keep. +-keep,allowoptimization,allowaccessmodification class com.android.server.SystemService { *; } +-keep,allowoptimization,allowaccessmodification class com.android.server.SystemService$TargetUser { *; } +-keep,allowoptimization,allowaccessmodification class com.android.server.usage.StorageStatsManagerLocal { *; } +-keep,allowoptimization,allowaccessmodification class com.android.internal.util.** { *; } +-keep,allowoptimization,allowaccessmodification class android.os.** { *; } diff --git a/services/tests/servicestests/src/com/android/server/BootReceiverTest.java b/services/tests/servicestests/src/com/android/server/BootReceiverTest.java deleted file mode 100644 index 489e2f769a3d..000000000000 --- a/services/tests/servicestests/src/com/android/server/BootReceiverTest.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.server; - -import android.test.AndroidTestCase; - -/** - * Tests for {@link com.android.server.BootReceiver} - */ -public class BootReceiverTest extends AndroidTestCase { - public void testLogLinePotentiallySensitive() throws Exception { - /* - * Strings to be dropped from the log as potentially sensitive: register dumps, process - * names, hardware info. - */ - final String[] becomeNull = { - "CPU: 4 PID: 120 Comm: kunit_try_catch Tainted: G W 5.8.0-rc6+ #7", - "Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1 04/01/2014", - "[ 0.083207] RSP: 0000:ffffffff8fe07ca8 EFLAGS: 00010046 ORIG_RAX: 0000000000000000", - "[ 0.084709] RAX: 0000000000000000 RBX: ffffffffff240000 RCX: ffffffff815fcf01", - "[ 0.086109] RDX: dffffc0000000000 RSI: 0000000000000001 RDI: ffffffffff240004", - "[ 0.087509] RBP: ffffffff8fe07d60 R08: fffffbfff1fc0f21 R09: fffffbfff1fc0f21", - "[ 0.088911] R10: ffffffff8fe07907 R11: fffffbfff1fc0f20 R12: ffffffff8fe07d38", - "R13: 0000000000000001 R14: 0000000000000001 R15: ffffffff8fe07e80", - "x29: ffff00003ce07150 x28: ffff80001aa29cc0", - "x1 : 0000000000000000 x0 : ffff00000f628000", - }; - - /* Strings to be left unchanged, including non-sensitive registers and parts of reports. */ - final String[] leftAsIs = { - "FS: 0000000000000000(0000) GS:ffffffff92409000(0000) knlGS:0000000000000000", - "[ 69.2366] [ T6006]c7 6006 =======================================================", - "[ 69.245688] [ T6006] BUG: KFENCE: out-of-bounds in kfence_handle_page_fault", - "[ 69.257816] [ T6006]c7 6006 Out-of-bounds access at 0xffffffca75c45000 ", - "[ 69.273536] [ T6006]c7 6006 __do_kernel_fault+0xa8/0x11c", - "pc : __mutex_lock+0x428/0x99c ", - "sp : ffff00003ce07150", - "Call trace:", - "", - }; - - final String[][] stripped = { - { "Detected corrupted memory at 0xffffffffb6797ff9 [ 0xac . . . . . . ]:", - "Detected corrupted memory at 0xffffffffb6797ff9" }, - }; - for (int i = 0; i < becomeNull.length; i++) { - assertEquals(BootReceiver.stripSensitiveData(becomeNull[i]), null); - } - - for (int i = 0; i < leftAsIs.length; i++) { - assertEquals(BootReceiver.stripSensitiveData(leftAsIs[i]), leftAsIs[i]); - } - - for (int i = 0; i < stripped.length; i++) { - assertEquals(BootReceiver.stripSensitiveData(stripped[i][0]), stripped[i][1]); - } - } -} diff --git a/services/tests/servicestests/src/com/android/server/OWNERS b/services/tests/servicestests/src/com/android/server/OWNERS index 6a7d298514c5..68994e6b5a6f 100644 --- a/services/tests/servicestests/src/com/android/server/OWNERS +++ b/services/tests/servicestests/src/com/android/server/OWNERS @@ -1,6 +1,6 @@ per-file *Alarm* = file:/apex/jobscheduler/OWNERS per-file *AppOp* = file:/core/java/android/permission/OWNERS -per-file *Bluetooth* = file:/core/java/android/bluetooth/OWNERS +per-file *Bluetooth* = file:platform/packages/modules/Bluetooth:master:/framework/java/android/bluetooth/OWNERS per-file *Gnss* = file:/services/core/java/com/android/server/location/OWNERS per-file *Network* = file:/services/core/java/com/android/server/net/OWNERS per-file BatteryServiceTest.java = file:platform/hardware/interfaces:/health/aidl/OWNERS diff --git a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java index 9e1445cf589d..bdea679a3311 100644 --- a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java +++ b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java @@ -30,7 +30,7 @@ import android.content.Context; import android.content.Intent; import android.media.AudioManager; import android.media.AudioSystem; -import android.media.BtProfileConnectionInfo; +import android.media.BluetoothProfileConnectionInfo; import android.util.Log; import androidx.test.InstrumentationRegistry; @@ -100,7 +100,7 @@ public class AudioDeviceBrokerTest { mAudioDeviceBroker.queueOnBluetoothActiveDeviceChanged( new AudioDeviceBroker.BtDeviceChangedData(mFakeBtDevice, null, - BtProfileConnectionInfo.a2dpInfo(true, 1), "testSource")); + BluetoothProfileConnectionInfo.createA2dpInfo(true, 1), "testSource")); Thread.sleep(2 * MAX_MESSAGE_HANDLING_DELAY_MS); verify(mSpyDevInventory, times(1)).setBluetoothActiveDevice( any(AudioDeviceBroker.BtDeviceInfo.class) @@ -208,13 +208,13 @@ public class AudioDeviceBrokerTest { // first connection: ensure the device is connected as a starting condition for the test mAudioDeviceBroker.queueOnBluetoothActiveDeviceChanged( new AudioDeviceBroker.BtDeviceChangedData(mFakeBtDevice, null, - BtProfileConnectionInfo.a2dpInfo(true, 1), "testSource")); + BluetoothProfileConnectionInfo.createA2dpInfo(true, 1), "testSource")); Thread.sleep(MAX_MESSAGE_HANDLING_DELAY_MS); // disconnection mAudioDeviceBroker.queueOnBluetoothActiveDeviceChanged( new AudioDeviceBroker.BtDeviceChangedData(null, mFakeBtDevice, - BtProfileConnectionInfo.a2dpInfo(false, -1), "testSource")); + BluetoothProfileConnectionInfo.createA2dpInfo(false, -1), "testSource")); if (delayAfterDisconnection > 0) { Thread.sleep(delayAfterDisconnection); } @@ -222,7 +222,7 @@ public class AudioDeviceBrokerTest { // reconnection mAudioDeviceBroker.queueOnBluetoothActiveDeviceChanged( new AudioDeviceBroker.BtDeviceChangedData(mFakeBtDevice, null, - BtProfileConnectionInfo.a2dpInfo(true, 2), "testSource")); + BluetoothProfileConnectionInfo.createA2dpInfo(true, 2), "testSource")); Thread.sleep(AudioService.BECOMING_NOISY_DELAY_MS + MAX_MESSAGE_HANDLING_DELAY_MS); // Verify disconnection has been cancelled and we're seeing two connections attempts, diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java index 01bd04c6f06b..77e49addf79f 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java @@ -43,6 +43,7 @@ import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiPortInfo; import android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener; import android.hardware.hdmi.IHdmiControlStatusChangeListener; +import android.hardware.hdmi.IHdmiVendorCommandListener; import android.os.Binder; import android.os.IPowerManager; import android.os.IThermalService; @@ -886,6 +887,117 @@ public class HdmiControlServiceTest { } @Test + public void addVendorCommandListener_receiveCallback_VendorCmdNoIdTest() { + int destAddress = mHdmiControlServiceSpy.playback().getDeviceInfo().getLogicalAddress(); + int sourceAddress = Constants.ADDR_TV; + byte[] params = {0x00, 0x01, 0x02, 0x03}; + int vendorId = 0x123456; + mHdmiControlServiceSpy.setPowerStatus(HdmiControlManager.POWER_STATUS_ON); + + VendorCommandListener vendorCmdListener = + new VendorCommandListener(sourceAddress, destAddress, params, vendorId); + mHdmiControlServiceSpy.addVendorCommandListener(vendorCmdListener, vendorId); + mTestLooper.dispatchAll(); + + HdmiCecMessage vendorCommandNoId = + HdmiCecMessageBuilder.buildVendorCommand(sourceAddress, destAddress, params); + mNativeWrapper.onCecMessage(vendorCommandNoId); + mTestLooper.dispatchAll(); + assertThat(vendorCmdListener.mVendorCommandCallbackReceived).isTrue(); + assertThat(vendorCmdListener.mParamsCorrect).isTrue(); + assertThat(vendorCmdListener.mHasVendorId).isFalse(); + } + + @Test + public void addVendorCommandListener_receiveCallback_VendorCmdWithIdTest() { + int destAddress = mHdmiControlServiceSpy.playback().getDeviceInfo().getLogicalAddress(); + int sourceAddress = Constants.ADDR_TV; + byte[] params = {0x00, 0x01, 0x02, 0x03}; + int vendorId = 0x123456; + mHdmiControlServiceSpy.setPowerStatus(HdmiControlManager.POWER_STATUS_ON); + + VendorCommandListener vendorCmdListener = + new VendorCommandListener(sourceAddress, destAddress, params, vendorId); + mHdmiControlServiceSpy.addVendorCommandListener(vendorCmdListener, vendorId); + mTestLooper.dispatchAll(); + + HdmiCecMessage vendorCommandWithId = + HdmiCecMessageBuilder.buildVendorCommandWithId( + sourceAddress, destAddress, vendorId, params); + mNativeWrapper.onCecMessage(vendorCommandWithId); + mTestLooper.dispatchAll(); + assertThat(vendorCmdListener.mVendorCommandCallbackReceived).isTrue(); + assertThat(vendorCmdListener.mParamsCorrect).isTrue(); + assertThat(vendorCmdListener.mHasVendorId).isTrue(); + } + + @Test + public void addVendorCommandListener_noCallback_VendorCmdDiffIdTest() { + int destAddress = mHdmiControlServiceSpy.playback().getDeviceInfo().getLogicalAddress(); + int sourceAddress = Constants.ADDR_TV; + byte[] params = {0x00, 0x01, 0x02, 0x03}; + int vendorId = 0x123456; + int diffVendorId = 0x345678; + mHdmiControlServiceSpy.setPowerStatus(HdmiControlManager.POWER_STATUS_ON); + + VendorCommandListener vendorCmdListener = + new VendorCommandListener(sourceAddress, destAddress, params, vendorId); + mHdmiControlServiceSpy.addVendorCommandListener(vendorCmdListener, vendorId); + mTestLooper.dispatchAll(); + + HdmiCecMessage vendorCommandWithDiffId = + HdmiCecMessageBuilder.buildVendorCommandWithId( + sourceAddress, destAddress, diffVendorId, params); + mNativeWrapper.onCecMessage(vendorCommandWithDiffId); + mTestLooper.dispatchAll(); + assertThat(vendorCmdListener.mVendorCommandCallbackReceived).isFalse(); + } + + private static class VendorCommandListener extends IHdmiVendorCommandListener.Stub { + boolean mVendorCommandCallbackReceived = false; + boolean mParamsCorrect = false; + boolean mHasVendorId = false; + + int mSourceAddress; + int mDestAddress; + byte[] mParams; + int mVendorId; + + VendorCommandListener(int sourceAddress, int destAddress, byte[] params, int vendorId) { + this.mSourceAddress = sourceAddress; + this.mDestAddress = destAddress; + this.mParams = params.clone(); + this.mVendorId = vendorId; + } + + @Override + public void onReceived( + int sourceAddress, int destAddress, byte[] params, boolean hasVendorId) { + mVendorCommandCallbackReceived = true; + if (mSourceAddress == sourceAddress && mDestAddress == destAddress) { + byte[] expectedParams; + if (hasVendorId) { + // If the command has vendor ID, we have to add it to mParams. + expectedParams = new byte[params.length]; + expectedParams[0] = (byte) ((mVendorId >> 16) & 0xFF); + expectedParams[1] = (byte) ((mVendorId >> 8) & 0xFF); + expectedParams[2] = (byte) (mVendorId & 0xFF); + System.arraycopy(mParams, 0, expectedParams, 3, mParams.length); + } else { + expectedParams = params.clone(); + } + if (Arrays.equals(expectedParams, params)) { + mParamsCorrect = true; + } + } + mHasVendorId = hasVendorId; + } + + @Override + public void onControlStateChanged(boolean enabled, int reason) {} + } + + @Test public void dispatchMessageToLocalDevice_broadcastMessage_returnsHandled() { HdmiCecMessage message = HdmiCecMessageBuilder.buildStandby( Constants.ADDR_TV, diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStrongAuthTest.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStrongAuthTest.java index acb20edfe8d8..6de7fddf6ccd 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStrongAuthTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStrongAuthTest.java @@ -229,8 +229,8 @@ public class LockSettingsStrongAuthTest { } private void verifyAlarm(long when, String tag, AlarmManager.OnAlarmListener alarm) { - verify(mAlarmManager).set( - eq(AlarmManager.ELAPSED_REALTIME), + verify(mAlarmManager).setExact( + eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), eq(when), eq(tag), eq(alarm), diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java index 94cf20f9c15b..1393d39e574f 100644 --- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java @@ -504,6 +504,7 @@ public class NetworkPolicyManagerServiceTest { ArgumentCaptor.forClass(NetworkStatsManager.UsageCallback.class); verify(mStatsManager, times(2)) .registerUsageCallback(any(), anyLong(), any(), usageObserver.capture()); + // It doesn't matter which of the observers is returned here. usageObserver.getValue().onThresholdReached( new NetworkTemplate.Builder(MATCH_MOBILE).build()); diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java index 2bda120afb9d..f99f65eaad08 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java @@ -489,6 +489,20 @@ public class ApexManagerTest { assertThat(e).hasMessageThat().contains("Failed to collect certificates from "); } + @Test + public void testGetActivePackageNameForApexModuleName() throws Exception { + final String moduleName = "com.android.module_name"; + + ApexInfo[] apexInfo = createApexInfoForTestPkg(true, false); + apexInfo[0].moduleName = moduleName; + when(mApexService.getAllPackages()).thenReturn(apexInfo); + mApexManager.scanApexPackagesTraced(mPackageParser2, + ParallelPackageParser.makeExecutorService()); + + assertThat(mApexManager.getActivePackageNameForApexModuleName(moduleName)) + .isEqualTo(TEST_APEX_PKG); + } + private ApexInfo[] createApexInfoForTestPkg(boolean isActive, boolean isFactory) { File apexFile = extractResource(TEST_APEX_PKG, TEST_APEX_FILE_NAME); ApexInfo apexInfo = new ApexInfo(); diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java new file mode 100644 index 000000000000..1d9ea4b6028c --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2021 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 com.android.server.pm.parsing.library; + +import android.os.Build; +import android.platform.test.annotations.Presubmit; +import android.util.ArrayMap; + +import androidx.test.filters.SmallTest; + +import com.android.server.SystemConfig; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.PackageImpl; +import com.android.server.pm.parsing.pkg.ParsedPackage; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + + +/** + * Test for {@link ApexSharedLibraryUpdater} + */ +@Presubmit +@SmallTest +@RunWith(JUnit4.class) +public class ApexSharedLibraryUpdaterTest extends PackageSharedLibraryUpdaterTest { + + private final ArrayMap<String, SystemConfig.SharedLibraryEntry> mSharedLibraries = + new ArrayMap<>(8); + + @Before + public void setUp() throws Exception { + installSharedLibraries(); + } + + private void installSharedLibraries() throws Exception { + mSharedLibraries.clear(); + insertLibrary("foo", 0, 0); + insertLibrary("fooBcpSince30", 30, 0); + insertLibrary("fooBcpBefore30", 0, 30); + insertLibrary("fooFromFuture", Build.VERSION.SDK_INT + 2, 0); + } + + private void insertLibrary(String libraryName, int onBootclasspathSince, + int onBootclasspathBefore) { + mSharedLibraries.put(libraryName, new SystemConfig.SharedLibraryEntry( + libraryName, + "foo.jar", + new String[0] /* dependencies */, + onBootclasspathSince, + onBootclasspathBefore + ) + ); + } + + @Test + public void testRegularAppOnRPlus() { + // platform Q should have changes (tested below) + + // these should have no changes + checkNoChanges(Build.VERSION_CODES.R); + checkNoChanges(Build.VERSION_CODES.S); + checkNoChanges(Build.VERSION_CODES.TIRAMISU); + checkNoChanges(Build.VERSION_CODES.CUR_DEVELOPMENT); + } + + private void checkNoChanges(int targetSdkVersion) { + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(targetSdkVersion) + .hideAsParsed()); + + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(targetSdkVersion) + .hideAsParsed()) + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void testBcpSince30Applied() { + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.R) + .addUsesLibrary("fooBcpSince30") + .hideAsParsed()); + + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.R) + .hideAsParsed()) + .hideAsFinal(); + + // note: target sdk is not what matters in this logic. It's the system SDK + // should be removed because on 30+ (R+) it is implicit + + checkBackwardsCompatibility(before, after); + } + + @Test + public void testBcpSince11kNotAppliedWithoutLibrary() { + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.R) + .hideAsParsed()); + + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.R) + .hideAsParsed()) + .hideAsFinal(); + + // note: target sdk is not what matters in this logic. It's the system SDK + // nothing should change because the implicit from is only from a future platform release + checkBackwardsCompatibility(before, after); + } + + @Test + public void testBcpSince11kNotAppliedWithLibrary() { + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.R) + .addUsesLibrary("fooFromFuture") + .hideAsParsed()); + + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.R) + .addUsesLibrary("fooFromFuture") + .hideAsParsed()) + .hideAsFinal(); + + // note: target sdk is not what matters in this logic. It's the system SDK + // nothing should change because the implicit from is only from a future platform release + checkBackwardsCompatibility(before, after); + } + + @Test + public void testBcpBefore30NotApplied() { + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.R) + .hideAsParsed()); + + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.R) + .hideAsParsed()) + .hideAsFinal(); + + // should not be affected because it is still in the BCP in 30 / R + checkBackwardsCompatibility(before, after); + } + + @Test + public void testBcpBefore30Applied() { + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.Q) + .hideAsParsed()); + + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.Q) + .addUsesLibrary("fooBcpBefore30") + .hideAsParsed()) + .hideAsFinal(); + + // should be present because this was in BCP in 29 / Q + checkBackwardsCompatibility(before, after); + } + + /** + * Test a library that was first removed from the BCP [to a mainline module] and later was + * moved back to the BCP via a mainline module update. All of this happening before the current + * SDK. + */ + @Test + public void testBcpRemovedThenAddedPast() { + insertLibrary("fooBcpRemovedThenAdded", 30, 28); + + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.N) + .hideAsParsed()); + + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.N) + .addUsesLibrary("fooBcpBefore30") + .hideAsParsed()) + .hideAsFinal(); + + // the library is now in the BOOTCLASSPATH (for the second time) so it doesn't need to be + // listed + checkBackwardsCompatibility(before, after); + } + + /** + * Test a library that was first removed from the BCP [to a mainline module] and later was + * moved back to the BCP via a mainline module update. The first part happening before the + * current SDK and the second part after. + */ + @Test + public void testBcpRemovedThenAddedMiddle_targetQ() { + insertLibrary("fooBcpRemovedThenAdded", Build.VERSION.SDK_INT + 1, 30); + + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.Q) + .hideAsParsed()); + + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.Q) + .addUsesLibrary("fooBcpRemovedThenAdded") + .addUsesLibrary("fooBcpBefore30") + .hideAsParsed()) + .hideAsFinal(); + + // in this example, we are at the point where the library is not in the BOOTCLASSPATH. + // Because the app targets Q / 29 (when this library was in the BCP) then we need to add it + checkBackwardsCompatibility(before, after); + } + + /** + * Test a library that was first removed from the BCP [to a mainline module] and later was + * moved back to the BCP via a mainline module update. The first part happening before the + * current SDK and the second part after. + */ + @Test + public void testBcpRemovedThenAddedMiddle_targetR() { + insertLibrary("fooBcpRemovedThenAdded", Build.VERSION.SDK_INT + 1, 30); + + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.R) + .hideAsParsed()); + + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.R) + .hideAsParsed()) + .hideAsFinal(); + + // in this example, we are at the point where the library is not in the BOOTCLASSPATH. + // Because the app targets R/30 (when this library was removed from the BCP) then we don't + //need to add it + checkBackwardsCompatibility(before, after); + } + + /** + * Test a library that was first removed from the BCP [to a mainline module] and later was + * moved back to the BCP via a mainline module update. The first part happening before the + * current SDK and the second part after. + */ + @Test + public void testBcpRemovedThenAddedMiddle_targetR_usingLib() { + insertLibrary("fooBcpRemovedThenAdded", Build.VERSION.SDK_INT + 1, 30); + + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.R) + .addUsesLibrary("fooBcpRemovedThenAdded") + .hideAsParsed()); + + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.R) + .addUsesLibrary("fooBcpRemovedThenAdded") + .hideAsParsed()) + .hideAsFinal(); + + // in this example, we are at the point where the library is not in the BOOTCLASSPATH. + // Because the app wants to use the library, it needs to be present + checkBackwardsCompatibility(before, after); + } + + private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) { + checkBackwardsCompatibility(before, after, + () -> new ApexSharedLibraryUpdater(mSharedLibraries)); + } +} diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java index 9768f176ea85..5bcd0f6bb029 100644 --- a/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java @@ -21,6 +21,8 @@ import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_T import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER; import static com.android.server.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; +import static com.google.common.truth.Truth.assertThat; + import android.content.pm.parsing.ParsingPackage; import android.os.Build; import android.platform.test.annotations.Presubmit; @@ -182,6 +184,22 @@ public class PackageBackwardCompatibilityTest extends PackageSharedLibraryUpdate checkBackwardsCompatibility(before, ((ParsedPackage) after.hideAsParsed()).hideAsFinal()); } + /** + * Ensures that ApexSharedLibraryUpdater is the last updater in the list of package updaters + * used by PackageBackwardCompatibility. + * + * This is required so mainline can add and remove libraries installed by the platform updaters. + */ + @Test + public void testApexPackageUpdaterOrdering() { + PackageBackwardCompatibility instance = + (PackageBackwardCompatibility) PackageBackwardCompatibility.getInstance(); + PackageSharedLibraryUpdater[] updaterArray = instance.getPackageUpdaters(); + + PackageSharedLibraryUpdater lastUpdater = updaterArray[updaterArray.length - 1]; + assertThat(lastUpdater).isInstanceOf(ApexSharedLibraryUpdater.class); + } + private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) { checkBackwardsCompatibility(before, after, PackageBackwardCompatibility::getInstance); } diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigNamedActorTest.kt b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigNamedActorTest.kt index b7199d4a2443..150822bdff6b 100644 --- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigNamedActorTest.kt +++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigNamedActorTest.kt @@ -17,6 +17,7 @@ package com.android.server.systemconfig import android.content.Context +import android.util.Xml import androidx.test.InstrumentationRegistry import com.android.server.SystemConfig import com.google.common.truth.Truth.assertThat @@ -227,6 +228,7 @@ class SystemConfigNamedActorTest { .writeText(this.trimIndent()) private fun assertPermissions() = SystemConfig(false).apply { - readPermissions(tempFolder.root, 0) + val parser = Xml.newPullParser() + readPermissions(parser, tempFolder.root, 0) }. let { assertThat(it.namedActors) } } diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java index 5eb21a58c38e..bfdffc0e6567 100644 --- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java +++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java @@ -21,10 +21,12 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.testng.Assert.expectThrows; +import android.os.Build; import android.platform.test.annotations.Presubmit; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; +import android.util.Xml; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -36,9 +38,12 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; import java.io.BufferedWriter; import java.io.File; +import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.Arrays; @@ -59,12 +64,15 @@ public class SystemConfigTest { private static final String LOG_TAG = "SystemConfigTest"; private SystemConfig mSysConfig; + private File mFooJar; @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder(); @Before public void setUp() throws Exception { mSysConfig = new SystemConfigTestClass(); + mFooJar = createTempFile( + mTemporaryFolder.getRoot().getCanonicalFile(), "foo.jar", "JAR"); } /** @@ -76,6 +84,11 @@ public class SystemConfigTest { } } + private void readPermissions(File libraryDir, int permissionFlag) { + final XmlPullParser parser = Xml.newPullParser(); + mSysConfig.readPermissions(parser, libraryDir, permissionFlag); + } + /** * Tests that readPermissions works correctly for the tag: install-in-user-type */ @@ -126,16 +139,17 @@ public class SystemConfigTest { new ArraySet<>(Arrays.asList("GUEST", "PROFILE"))); final File folder1 = createTempSubfolder("folder1"); - createTempFile(folder1, "permFile1.xml", contents1); + createTempFile(folder1, "permissionFile1.xml", contents1); final File folder2 = createTempSubfolder("folder2"); - createTempFile(folder2, "permFile2.xml", contents2); + createTempFile(folder2, "permissionFile2.xml", contents2); - // Also, make a third file, but with the name folder1/permFile2.xml, to prove no conflicts. - createTempFile(folder1, "permFile2.xml", contents3); + // Also, make a third file, but with the name folder1/permissionFile2.xml, to prove no + // conflicts. + createTempFile(folder1, "permissionFile2.xml", contents3); - mSysConfig.readPermissions(folder1, /* No permission needed anyway */ 0); - mSysConfig.readPermissions(folder2, /* No permission needed anyway */ 0); + readPermissions(folder1, /* No permission needed anyway */ 0); + readPermissions(folder2, /* No permission needed anyway */ 0); Map<String, Set<String>> actualWhite = mSysConfig.getAndClearPackageToUserTypeWhitelist(); Map<String, Set<String>> actualBlack = mSysConfig.getAndClearPackageToUserTypeBlacklist(); @@ -165,7 +179,7 @@ public class SystemConfigTest { final File folder = createTempSubfolder("folder"); createTempFile(folder, "component-override.xml", contents); - mSysConfig.readPermissions(folder, /* No permission needed anyway */ 0); + readPermissions(folder, /* No permission needed anyway */ 0); final ArrayMap<String, Boolean> packageOneExpected = new ArrayMap<>(); packageOneExpected.put("com.android.package1.Full", true); @@ -197,7 +211,7 @@ public class SystemConfigTest { final File folder = createTempSubfolder("folder"); createTempFile(folder, "staged-installer-whitelist.xml", contents); - mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0); + readPermissions(folder, /* Grant all permission flags */ ~0); assertThat(mSysConfig.getWhitelistedStagedInstallers()) .containsExactly("com.android.package1"); @@ -215,7 +229,7 @@ public class SystemConfigTest { final File folder = createTempSubfolder("folder"); createTempFile(folder, "staged-installer-whitelist.xml", contents); - mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0); + readPermissions(folder, /* Grant all permission flags */ ~0); assertThat(mSysConfig.getWhitelistedStagedInstallers()) .containsExactly("com.android.package1"); @@ -238,7 +252,7 @@ public class SystemConfigTest { IllegalStateException e = expectThrows( IllegalStateException.class, - () -> mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0)); + () -> readPermissions(folder, /* Grant all permission flags */ ~0)); assertThat(e).hasMessageThat().contains("Multiple modules installers"); } @@ -257,7 +271,7 @@ public class SystemConfigTest { final File folder = createTempSubfolder("folder"); createTempFile(folder, "staged-installer-whitelist.xml", contents); - mSysConfig.readPermissions(folder, /* Grant all but ALLOW_APP_CONFIGS flag */ ~0x08); + readPermissions(folder, /* Grant all but ALLOW_APP_CONFIGS flag */ ~0x08); assertThat(mSysConfig.getWhitelistedStagedInstallers()).isEmpty(); } @@ -277,7 +291,7 @@ public class SystemConfigTest { final File folder = createTempSubfolder("folder"); createTempFile(folder, "vendor-apex-allowlist.xml", contents); - mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0); + readPermissions(folder, /* Grant all permission flags */ ~0); assertThat(mSysConfig.getAllowedVendorApexes()) .containsExactly("com.android.apex1", "com.installer"); @@ -297,7 +311,7 @@ public class SystemConfigTest { final File folder = createTempSubfolder("folder"); createTempFile(folder, "vendor-apex-allowlist.xml", contents); - mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0); + readPermissions(folder, /* Grant all permission flags */ ~0); assertThat(mSysConfig.getAllowedVendorApexes()).isEmpty(); } @@ -317,11 +331,273 @@ public class SystemConfigTest { final File folder = createTempSubfolder("folder"); createTempFile(folder, "vendor-apex-allowlist.xml", contents); - mSysConfig.readPermissions(folder, /* Grant all but ALLOW_VENDOR_APEX flag */ ~0x400); + readPermissions(folder, /* Grant all but ALLOW_VENDOR_APEX flag */ ~0x400); assertThat(mSysConfig.getAllowedVendorApexes()).isEmpty(); } + @Test + public void readApexPrivAppPermissions_addAllPermissions() + throws Exception { + final String contents = + "<privapp-permissions package=\"com.android.apk_in_apex\">" + + "<permission name=\"android.permission.FOO\"/>" + + "<deny-permission name=\"android.permission.BAR\"/>" + + "</privapp-permissions>"; + File apexDir = createTempSubfolder("apex"); + File permissionFile = createTempFile( + createTempSubfolder("apex/com.android.my_module/etc/permissions"), + "permissions.xml", contents); + XmlPullParser parser = readXmlUntilStartTag(permissionFile); + + mSysConfig.readApexPrivAppPermissions(parser, permissionFile, apexDir.toPath()); + + assertThat(mSysConfig.getApexPrivAppPermissions("com.android.my_module", + "com.android.apk_in_apex")) + .containsExactly("android.permission.FOO"); + assertThat(mSysConfig.getApexPrivAppDenyPermissions("com.android.my_module", + "com.android.apk_in_apex")) + .containsExactly("android.permission.BAR"); + } + + @Test + public void pruneVendorApexPrivappAllowlists_removeVendor() + throws Exception { + File apexDir = createTempSubfolder("apex"); + + // Read non-vendor apex permission allowlists + final String allowlistNonVendorContents = + "<privapp-permissions package=\"com.android.apk_in_non_vendor_apex\">" + + "<permission name=\"android.permission.FOO\"/>" + + "<deny-permission name=\"android.permission.BAR\"/>" + + "</privapp-permissions>"; + File nonVendorPermDir = + createTempSubfolder("apex/com.android.non_vendor/etc/permissions"); + File nonVendorPermissionFile = + createTempFile(nonVendorPermDir, "permissions.xml", allowlistNonVendorContents); + XmlPullParser nonVendorParser = readXmlUntilStartTag(nonVendorPermissionFile); + mSysConfig.readApexPrivAppPermissions(nonVendorParser, nonVendorPermissionFile, + apexDir.toPath()); + + // Read vendor apex permission allowlists + final String allowlistVendorContents = + "<privapp-permissions package=\"com.android.apk_in_vendor_apex\">" + + "<permission name=\"android.permission.BAZ\"/>" + + "<deny-permission name=\"android.permission.BAT\"/>" + + "</privapp-permissions>"; + File vendorPermissionFile = + createTempFile(createTempSubfolder("apex/com.android.vendor/etc/permissions"), + "permissions.xml", allowlistNonVendorContents); + XmlPullParser vendorParser = readXmlUntilStartTag(vendorPermissionFile); + mSysConfig.readApexPrivAppPermissions(vendorParser, vendorPermissionFile, + apexDir.toPath()); + + // Read allowed vendor apex list + final String allowedVendorContents = + "<config>\n" + + " <allowed-vendor-apex package=\"com.android.vendor\" " + + "installerPackage=\"com.installer\" />\n" + + "</config>"; + final File allowedVendorFolder = createTempSubfolder("folder"); + createTempFile(allowedVendorFolder, "vendor-apex-allowlist.xml", allowedVendorContents); + readPermissions(allowedVendorFolder, /* Grant all permission flags */ ~0); + + // Finally, prune non-vendor allowlists. + // There is no guarantee in which order the above reads will be done, however pruning + // will always happen last. + mSysConfig.pruneVendorApexPrivappAllowlists(); + + assertThat(mSysConfig.getApexPrivAppPermissions("com.android.non_vendor", + "com.android.apk_in_non_vendor_apex")) + .containsExactly("android.permission.FOO"); + assertThat(mSysConfig.getApexPrivAppDenyPermissions("com.android.non_vendor", + "com.android.apk_in_non_vendor_apex")) + .containsExactly("android.permission.BAR"); + assertThat(mSysConfig.getApexPrivAppPermissions("com.android.vendor", + "com.android.apk_in_vendor_apex")) + .isNull(); + assertThat(mSysConfig.getApexPrivAppDenyPermissions("com.android.vendor", + "com.android.apk_in_vendor_apex")) + .isNull(); + } + + /** + * Tests that readPermissions works correctly for a library with on-bootclasspath-before + * and on-bootclasspath-since. + */ + @Test + public void readPermissions_allowLibs_parsesSimpleLibrary() throws IOException { + String contents = + "<permissions>\n" + + " <library \n" + + " name=\"foo\"\n" + + " file=\"" + mFooJar + "\"\n" + + " on-bootclasspath-before=\"10\"\n" + + " on-bootclasspath-since=\"20\"\n" + + " />\n\n" + + " </permissions>"; + parseSharedLibraries(contents); + assertFooIsOnlySharedLibrary(); + SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo"); + assertThat(entry.onBootclasspathBefore).isEqualTo(10); + assertThat(entry.onBootclasspathSince).isEqualTo(20); + } + + /** + * Tests that readPermissions works correctly for a library using the new + * {@code apex-library} tag. + */ + @Test + public void readPermissions_allowLibs_parsesUpdatableLibrary() throws IOException { + String contents = + "<permissions>\n" + + " <apex-library \n" + + " name=\"foo\"\n" + + " file=\"" + mFooJar + "\"\n" + + " on-bootclasspath-before=\"10\"\n" + + " on-bootclasspath-since=\"20\"\n" + + " />\n\n" + + " </permissions>"; + parseSharedLibraries(contents); + assertFooIsOnlySharedLibrary(); + SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo"); + assertThat(entry.onBootclasspathBefore).isEqualTo(10); + assertThat(entry.onBootclasspathSince).isEqualTo(20); + } + + /** + * Tests that readPermissions for a library with {@code min-device-sdk} lower than the current + * SDK results in the library being added to the shared libraries. + */ + @Test + public void readPermissions_allowLibs_allowsOldMinSdk() throws IOException { + String contents = + "<permissions>\n" + + " <library \n" + + " name=\"foo\"\n" + + " file=\"" + mFooJar + "\"\n" + + " min-device-sdk=\"30\"\n" + + " />\n\n" + + " </permissions>"; + parseSharedLibraries(contents); + assertFooIsOnlySharedLibrary(); + } + + /** + * Tests that readPermissions for a library with {@code min-device-sdk} equal to the current + * SDK results in the library being added to the shared libraries. + */ + @Test + public void readPermissions_allowLibs_allowsCurrentMinSdk() throws IOException { + String contents = + "<permissions>\n" + + " <library \n" + + " name=\"foo\"\n" + + " file=\"" + mFooJar + "\"\n" + + " min-device-sdk=\"" + Build.VERSION.SDK_INT + "\"\n" + + " />\n\n" + + " </permissions>"; + parseSharedLibraries(contents); + assertFooIsOnlySharedLibrary(); + } + + /** + * Tests that readPermissions for a library with {@code min-device-sdk} greater than the current + * SDK results in the library being ignored. + */ + @Test + public void readPermissions_allowLibs_ignoresMinSdkInFuture() throws IOException { + String contents = + "<permissions>\n" + + " <library \n" + + " name=\"foo\"\n" + + " file=\"" + mFooJar + "\"\n" + + " min-device-sdk=\"" + (Build.VERSION.SDK_INT + 1) + "\"\n" + + " />\n\n" + + " </permissions>"; + parseSharedLibraries(contents); + assertThat(mSysConfig.getSharedLibraries()).isEmpty(); + } + + /** + * Tests that readPermissions for a library with {@code max-device-sdk} less than the current + * SDK results in the library being ignored. + */ + @Test + public void readPermissions_allowLibs_ignoredOldMaxSdk() throws IOException { + String contents = + "<permissions>\n" + + " <library \n" + + " name=\"foo\"\n" + + " file=\"" + mFooJar + "\"\n" + + " max-device-sdk=\"30\"\n" + + " />\n\n" + + " </permissions>"; + parseSharedLibraries(contents); + assertThat(mSysConfig.getSharedLibraries()).isEmpty(); + } + + /** + * Tests that readPermissions for a library with {@code max-device-sdk} equal to the current + * SDK results in the library being added to the shared libraries. + */ + @Test + public void readPermissions_allowLibs_allowsCurrentMaxSdk() throws IOException { + String contents = + "<permissions>\n" + + " <library \n" + + " name=\"foo\"\n" + + " file=\"" + mFooJar + "\"\n" + + " max-device-sdk=\"" + Build.VERSION.SDK_INT + "\"\n" + + " />\n\n" + + " </permissions>"; + parseSharedLibraries(contents); + assertFooIsOnlySharedLibrary(); + } + + /** + * Tests that readPermissions for a library with {@code max-device-sdk} greater than the current + * SDK results in the library being added to the shared libraries. + */ + @Test + public void readPermissions_allowLibs_allowsMaxSdkInFuture() throws IOException { + String contents = + "<permissions>\n" + + " <library \n" + + " name=\"foo\"\n" + + " file=\"" + mFooJar + "\"\n" + + " max-device-sdk=\"" + (Build.VERSION.SDK_INT + 1) + "\"\n" + + " />\n\n" + + " </permissions>"; + parseSharedLibraries(contents); + assertFooIsOnlySharedLibrary(); + } + + private void parseSharedLibraries(String contents) throws IOException { + File folder = createTempSubfolder("permissions_folder"); + createTempFile(folder, "permissions.xml", contents); + readPermissions(folder, /* permissionFlag = ALLOW_LIBS */ 0x02); + } + + /** + * Create an {@link XmlPullParser} for {@param permissionFile} and begin parsing it until + * reaching the root tag. + */ + private XmlPullParser readXmlUntilStartTag(File permissionFile) + throws IOException, XmlPullParserException { + FileReader permReader = new FileReader(permissionFile); + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(permReader); + int type; + do { + type = parser.next(); + } while (type != parser.START_TAG && type != parser.END_DOCUMENT); + if (type != parser.START_TAG) { + throw new XmlPullParserException("No start tag found"); + } + return parser; + } + /** * Creates folderName/fileName in the mTemporaryFolder and fills it with the contents. * @@ -331,7 +607,7 @@ public class SystemConfigTest { private File createTempSubfolder(String folderName) throws IOException { File folder = new File(mTemporaryFolder.getRoot(), folderName); - folder.mkdir(); + folder.mkdirs(); return folder; } @@ -341,7 +617,7 @@ public class SystemConfigTest { * @param folder pre-existing subdirectory of mTemporaryFolder to put the file * @param fileName name of the file (e.g. filename.xml) to create * @param contents contents to write to the file - * @return the folder containing the newly created file (not the file itself!) + * @return the newly created file */ private File createTempFile(File folder, String fileName, String contents) throws IOException { @@ -357,6 +633,13 @@ public class SystemConfigTest { Log.d(LOG_TAG, input.nextLine()); } - return folder; + return file; + } + + private void assertFooIsOnlySharedLibrary() { + assertThat(mSysConfig.getSharedLibraries().size()).isEqualTo(1); + SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo"); + assertThat(entry.name).isEqualTo("foo"); + assertThat(entry.filename).isEqualTo(mFooJar.toString()); } } diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java index 32fed3bc3dc1..4519890e72a1 100644 --- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java @@ -252,7 +252,7 @@ public class TimeDetectorServiceTest { int slotIndex = 1234; TimestampedValue<Long> timeValue = new TimestampedValue<>(100L, 1_000_000L); return new TelephonyTimeSuggestion.Builder(slotIndex) - .setUtcTime(timeValue) + .setUnixEpochTime(timeValue) .build(); } diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java index 0d5b5a565d5a..2d9903f9cf60 100644 --- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java +++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java @@ -52,12 +52,12 @@ import java.util.Objects; @RunWith(AndroidJUnit4.class) public class TimeDetectorStrategyImplTest { - private static final Instant TIME_LOWER_BOUND = createUtcTime(2009, 1, 1, 12, 0, 0); + private static final Instant TIME_LOWER_BOUND = createUnixEpochTime(2009, 1, 1, 12, 0, 0); private static final TimestampedValue<Instant> ARBITRARY_CLOCK_INITIALIZATION_INFO = new TimestampedValue<>( 123456789L /* realtimeClockMillis */, - createUtcTime(2010, 5, 23, 12, 0, 0)); + createUnixEpochTime(2010, 5, 23, 12, 0, 0)); // This is the traditional ordering for time detection on Android. private static final @Origin int [] PROVIDERS_PRIORITY = { ORIGIN_TELEPHONY, ORIGIN_NETWORK }; @@ -66,7 +66,7 @@ public class TimeDetectorStrategyImplTest { * An arbitrary time, very different from the {@link #ARBITRARY_CLOCK_INITIALIZATION_INFO} * time. Can be used as the basis for time suggestions. */ - private static final Instant ARBITRARY_TEST_TIME = createUtcTime(2018, 1, 1, 12, 0, 0); + private static final Instant ARBITRARY_TEST_TIME = createUnixEpochTime(2018, 1, 1, 12, 0, 0); private static final int ARBITRARY_SLOT_INDEX = 123456; @@ -91,7 +91,7 @@ public class TimeDetectorStrategyImplTest { .simulateTelephonyTimeSuggestion(timeSuggestion); long expectedSystemClockMillis = - mScript.calculateTimeInMillisForNow(timeSuggestion.getUtcTime()); + mScript.calculateTimeInMillisForNow(timeSuggestion.getUnixEpochTime()); mScript.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis) .assertLatestTelephonySuggestion(slotIndex, timeSuggestion); } @@ -128,7 +128,7 @@ public class TimeDetectorStrategyImplTest { mScript.simulateTimePassing(clockIncrementMillis); long expectedSystemClockMillis1 = - mScript.calculateTimeInMillisForNow(timeSuggestion1.getUtcTime()); + mScript.calculateTimeInMillisForNow(timeSuggestion1.getUnixEpochTime()); mScript.simulateTelephonyTimeSuggestion(timeSuggestion1) .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1) @@ -155,7 +155,7 @@ public class TimeDetectorStrategyImplTest { mScript.simulateTimePassing(clockIncrementMillis); long expectedSystemClockMillis3 = - mScript.calculateTimeInMillisForNow(timeSuggestion3.getUtcTime()); + mScript.calculateTimeInMillisForNow(timeSuggestion3.getUnixEpochTime()); mScript.simulateTelephonyTimeSuggestion(timeSuggestion3) .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis3) @@ -182,8 +182,8 @@ public class TimeDetectorStrategyImplTest { mScript.generateTelephonyTimeSuggestion(slotIndex2, slotIndex2Time); mScript.simulateTimePassing(); - long expectedSystemClockMillis = - mScript.calculateTimeInMillisForNow(slotIndex2TimeSuggestion.getUtcTime()); + long expectedSystemClockMillis = mScript.calculateTimeInMillisForNow( + slotIndex2TimeSuggestion.getUnixEpochTime()); mScript.simulateTelephonyTimeSuggestion(slotIndex2TimeSuggestion) .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis) @@ -199,8 +199,8 @@ public class TimeDetectorStrategyImplTest { mScript.generateTelephonyTimeSuggestion(slotIndex1, slotIndex1Time); mScript.simulateTimePassing(); - long expectedSystemClockMillis = - mScript.calculateTimeInMillisForNow(slotIndex1TimeSuggestion.getUtcTime()); + long expectedSystemClockMillis = mScript.calculateTimeInMillisForNow( + slotIndex1TimeSuggestion.getUnixEpochTime()); mScript.simulateTelephonyTimeSuggestion(slotIndex1TimeSuggestion) .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis) @@ -232,8 +232,8 @@ public class TimeDetectorStrategyImplTest { mScript.generateTelephonyTimeSuggestion(slotIndex2, slotIndex2Time); mScript.simulateTimePassing(); - long expectedSystemClockMillis = - mScript.calculateTimeInMillisForNow(slotIndex2TimeSuggestion.getUtcTime()); + long expectedSystemClockMillis = mScript.calculateTimeInMillisForNow( + slotIndex2TimeSuggestion.getUnixEpochTime()); mScript.simulateTelephonyTimeSuggestion(slotIndex2TimeSuggestion) .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis) @@ -267,26 +267,27 @@ public class TimeDetectorStrategyImplTest { TelephonyTimeSuggestion timeSuggestion1 = mScript.generateTelephonyTimeSuggestion(slotIndex, testTime); - TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime(); + TimestampedValue<Long> unixEpochTime1 = timeSuggestion1.getUnixEpochTime(); // Initialize the strategy / device with a time set from a telephony suggestion. mScript.simulateTimePassing(); - long expectedSystemClockMillis1 = mScript.calculateTimeInMillisForNow(utcTime1); + long expectedSystemClockMillis1 = mScript.calculateTimeInMillisForNow(unixEpochTime1); mScript.simulateTelephonyTimeSuggestion(timeSuggestion1) .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1) .assertLatestTelephonySuggestion(slotIndex, timeSuggestion1); - // The UTC time increment should be larger than the system clock update threshold so we - // know it shouldn't be ignored for other reasons. - long validUtcTimeMillis = utcTime1.getValue() + (2 * systemClockUpdateThreshold); + // The Unix epoch time increment should be larger than the system clock update threshold so + // we know it shouldn't be ignored for other reasons. + long validUnixEpochTimeMillis = unixEpochTime1.getValue() + + (2 * systemClockUpdateThreshold); // Now supply a new signal that has an obviously bogus reference time : older than the last // one. - long referenceTimeBeforeLastSignalMillis = utcTime1.getReferenceTimeMillis() - 1; - TimestampedValue<Long> utcTime2 = new TimestampedValue<>( - referenceTimeBeforeLastSignalMillis, validUtcTimeMillis); + long referenceTimeBeforeLastSignalMillis = unixEpochTime1.getReferenceTimeMillis() - 1; + TimestampedValue<Long> unixEpochTime2 = new TimestampedValue<>( + referenceTimeBeforeLastSignalMillis, validUnixEpochTimeMillis); TelephonyTimeSuggestion timeSuggestion2 = - createTelephonyTimeSuggestion(slotIndex, utcTime2); + createTelephonyTimeSuggestion(slotIndex, unixEpochTime2); mScript.simulateTelephonyTimeSuggestion(timeSuggestion2) .verifySystemClockWasNotSetAndResetCallTracking() .assertLatestTelephonySuggestion(slotIndex, timeSuggestion1); @@ -294,22 +295,22 @@ public class TimeDetectorStrategyImplTest { // Now supply a new signal that has an obviously bogus reference time : substantially in the // future. long referenceTimeInFutureMillis = - utcTime1.getReferenceTimeMillis() + Integer.MAX_VALUE + 1; - TimestampedValue<Long> utcTime3 = new TimestampedValue<>( - referenceTimeInFutureMillis, validUtcTimeMillis); + unixEpochTime1.getReferenceTimeMillis() + Integer.MAX_VALUE + 1; + TimestampedValue<Long> unixEpochTime3 = new TimestampedValue<>( + referenceTimeInFutureMillis, validUnixEpochTimeMillis); TelephonyTimeSuggestion timeSuggestion3 = - createTelephonyTimeSuggestion(slotIndex, utcTime3); + createTelephonyTimeSuggestion(slotIndex, unixEpochTime3); mScript.simulateTelephonyTimeSuggestion(timeSuggestion3) .verifySystemClockWasNotSetAndResetCallTracking() .assertLatestTelephonySuggestion(slotIndex, timeSuggestion1); - // Just to prove validUtcTimeMillis is valid. - long validReferenceTimeMillis = utcTime1.getReferenceTimeMillis() + 100; - TimestampedValue<Long> utcTime4 = new TimestampedValue<>( - validReferenceTimeMillis, validUtcTimeMillis); - long expectedSystemClockMillis4 = mScript.calculateTimeInMillisForNow(utcTime4); + // Just to prove validUnixEpochTimeMillis is valid. + long validReferenceTimeMillis = unixEpochTime1.getReferenceTimeMillis() + 100; + TimestampedValue<Long> unixEpochTime4 = new TimestampedValue<>( + validReferenceTimeMillis, validUnixEpochTimeMillis); + long expectedSystemClockMillis4 = mScript.calculateTimeInMillisForNow(unixEpochTime4); TelephonyTimeSuggestion timeSuggestion4 = - createTelephonyTimeSuggestion(slotIndex, utcTime4); + createTelephonyTimeSuggestion(slotIndex, unixEpochTime4); mScript.simulateTelephonyTimeSuggestion(timeSuggestion4) .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis4) .assertLatestTelephonySuggestion(slotIndex, timeSuggestion4); @@ -344,7 +345,7 @@ public class TimeDetectorStrategyImplTest { Instant testTime = ARBITRARY_TEST_TIME; TelephonyTimeSuggestion timeSuggestion1 = mScript.generateTelephonyTimeSuggestion(slotIndex, testTime); - TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime(); + TimestampedValue<Long> unixEpochTime1 = timeSuggestion1.getUnixEpochTime(); // Simulate time passing. mScript.simulateTimePassing(clockIncrementMillis); @@ -358,7 +359,7 @@ public class TimeDetectorStrategyImplTest { // Simulate more time passing. mScript.simulateTimePassing(clockIncrementMillis); - long expectedSystemClockMillis1 = mScript.calculateTimeInMillisForNow(utcTime1); + long expectedSystemClockMillis1 = mScript.calculateTimeInMillisForNow(unixEpochTime1); // Turn on auto time detection. mScript.simulateAutoTimeDetectionToggle() @@ -379,7 +380,7 @@ public class TimeDetectorStrategyImplTest { mScript.simulateTimePassing(clockIncrementMillis); long expectedSystemClockMillis2 = - mScript.calculateTimeInMillisForNow(timeSuggestion2.getUtcTime()); + mScript.calculateTimeInMillisForNow(timeSuggestion2.getUnixEpochTime()); // The new time, though valid, should not be set in the system clock because auto time is // disabled. @@ -406,7 +407,7 @@ public class TimeDetectorStrategyImplTest { mScript.simulateTimePassing(); long expectedSystemClockMillis = - mScript.calculateTimeInMillisForNow(telephonySuggestion.getUtcTime()); + mScript.calculateTimeInMillisForNow(telephonySuggestion.getUnixEpochTime()); mScript.simulateTelephonyTimeSuggestion(telephonySuggestion) .verifySystemClockWasSetAndResetCallTracking( expectedSystemClockMillis /* expectedNetworkBroadcast */) @@ -416,7 +417,7 @@ public class TimeDetectorStrategyImplTest { assertEquals(telephonySuggestion, mScript.peekBestTelephonySuggestion()); // Simulate time passing, long enough that telephonySuggestion is now too old. - mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_UTC_TIME_AGE_MILLIS); + mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_SUGGESTION_TIME_AGE_MILLIS); // Look inside and check what the strategy considers the current best telephony suggestion. // It should still be the, it's just no longer used. @@ -435,7 +436,7 @@ public class TimeDetectorStrategyImplTest { mScript.simulateTimePassing(); long expectedSystemClockMillis = - mScript.calculateTimeInMillisForNow(timeSuggestion.getUtcTime()); + mScript.calculateTimeInMillisForNow(timeSuggestion.getUnixEpochTime()); mScript.simulateManualTimeSuggestion(timeSuggestion, true /* expectedResult */) .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis); } @@ -457,7 +458,7 @@ public class TimeDetectorStrategyImplTest { mScript.simulateTimePassing(); long expectedAutoClockMillis = - mScript.calculateTimeInMillisForNow(telephonyTimeSuggestion.getUtcTime()); + mScript.calculateTimeInMillisForNow(telephonyTimeSuggestion.getUnixEpochTime()); mScript.simulateTelephonyTimeSuggestion(telephonyTimeSuggestion) .verifySystemClockWasSetAndResetCallTracking(expectedAutoClockMillis) .assertLatestTelephonySuggestion(slotIndex, telephonyTimeSuggestion); @@ -480,7 +481,7 @@ public class TimeDetectorStrategyImplTest { mScript.simulateTimePassing(); long expectedManualClockMillis = - mScript.calculateTimeInMillisForNow(manualTimeSuggestion.getUtcTime()); + mScript.calculateTimeInMillisForNow(manualTimeSuggestion.getUnixEpochTime()); mScript.simulateManualTimeSuggestion(manualTimeSuggestion, true /* expectedResult */) .verifySystemClockWasSetAndResetCallTracking(expectedManualClockMillis) .assertLatestTelephonySuggestion(slotIndex, telephonyTimeSuggestion); @@ -492,7 +493,7 @@ public class TimeDetectorStrategyImplTest { mScript.simulateAutoTimeDetectionToggle(); expectedAutoClockMillis = - mScript.calculateTimeInMillisForNow(telephonyTimeSuggestion.getUtcTime()); + mScript.calculateTimeInMillisForNow(telephonyTimeSuggestion.getUnixEpochTime()); mScript.verifySystemClockWasSetAndResetCallTracking(expectedAutoClockMillis) .assertLatestTelephonySuggestion(slotIndex, telephonyTimeSuggestion); @@ -540,7 +541,7 @@ public class TimeDetectorStrategyImplTest { mScript.simulateTimePassing(); long expectedSystemClockMillis = - mScript.calculateTimeInMillisForNow(timeSuggestion.getUtcTime()); + mScript.calculateTimeInMillisForNow(timeSuggestion.getUnixEpochTime()); mScript.simulateNetworkTimeSuggestion(timeSuggestion) .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis); } @@ -586,7 +587,7 @@ public class TimeDetectorStrategyImplTest { mScript.simulateTimePassing(); long expectedSystemClockMillis = - mScript.calculateTimeInMillisForNow(timeSuggestion.getUtcTime()); + mScript.calculateTimeInMillisForNow(timeSuggestion.getUnixEpochTime()); mScript.simulateGnssTimeSuggestion(timeSuggestion) .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis); } @@ -617,7 +618,7 @@ public class TimeDetectorStrategyImplTest { mScript.simulateTimePassing(); long expectedSystemClockMillis = - mScript.calculateTimeInMillisForNow(timeSuggestion.getUtcTime()); + mScript.calculateTimeInMillisForNow(timeSuggestion.getUnixEpochTime()); mScript.simulateExternalTimeSuggestion(timeSuggestion) .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis); } @@ -671,7 +672,8 @@ public class TimeDetectorStrategyImplTest { mScript.simulateTimePassing(smallTimeIncrementMillis) .simulateNetworkTimeSuggestion(networkTimeSuggestion1) .verifySystemClockWasSetAndResetCallTracking( - mScript.calculateTimeInMillisForNow(networkTimeSuggestion1.getUtcTime())); + mScript.calculateTimeInMillisForNow( + networkTimeSuggestion1.getUnixEpochTime())); // Check internal state. mScript.assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, null) @@ -690,7 +692,8 @@ public class TimeDetectorStrategyImplTest { mScript.simulateTimePassing(smallTimeIncrementMillis) .simulateTelephonyTimeSuggestion(telephonyTimeSuggestion) .verifySystemClockWasSetAndResetCallTracking( - mScript.calculateTimeInMillisForNow(telephonyTimeSuggestion.getUtcTime())); + mScript.calculateTimeInMillisForNow( + telephonyTimeSuggestion.getUnixEpochTime())); // Check internal state. mScript.assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, telephonyTimeSuggestion) @@ -700,7 +703,7 @@ public class TimeDetectorStrategyImplTest { // Simulate some significant time passing: half the time allowed before a time signal // becomes "too old to use". - mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_UTC_TIME_AGE_MILLIS / 2) + mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_SUGGESTION_TIME_AGE_MILLIS / 2) .verifySystemClockWasNotSetAndResetCallTracking(); // Now another network suggestion is made. Telephony suggestions are prioritized over @@ -720,7 +723,7 @@ public class TimeDetectorStrategyImplTest { // Simulate some significant time passing: half the time allowed before a time signal // becomes "too old to use". This should mean that telephonyTimeSuggestion is now too old to // be used but networkTimeSuggestion2 is not. - mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_UTC_TIME_AGE_MILLIS / 2); + mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_SUGGESTION_TIME_AGE_MILLIS / 2); // NOTE: The TimeDetectorStrategyImpl doesn't set an alarm for the point when the last // suggestion it used becomes too old: it requires a new suggestion or an auto-time toggle @@ -743,7 +746,7 @@ public class TimeDetectorStrategyImplTest { // Verify the latest network time now wins. mScript.verifySystemClockWasSetAndResetCallTracking( - mScript.calculateTimeInMillisForNow(networkTimeSuggestion2.getUtcTime())); + mScript.calculateTimeInMillisForNow(networkTimeSuggestion2.getUnixEpochTime())); // Check internal state. mScript.assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, telephonyTimeSuggestion) @@ -774,7 +777,8 @@ public class TimeDetectorStrategyImplTest { mScript.simulateTimePassing(smallTimeIncrementMillis) .simulateGnssTimeSuggestion(gnssTimeSuggestion1) .verifySystemClockWasSetAndResetCallTracking( - mScript.calculateTimeInMillisForNow(gnssTimeSuggestion1.getUtcTime())); + mScript.calculateTimeInMillisForNow( + gnssTimeSuggestion1.getUnixEpochTime())); // Check internal state. mScript.assertLatestNetworkSuggestion(null) @@ -793,7 +797,8 @@ public class TimeDetectorStrategyImplTest { mScript.simulateTimePassing(smallTimeIncrementMillis) .simulateNetworkTimeSuggestion(networkTimeSuggestion) .verifySystemClockWasSetAndResetCallTracking( - mScript.calculateTimeInMillisForNow(networkTimeSuggestion.getUtcTime())); + mScript.calculateTimeInMillisForNow( + networkTimeSuggestion.getUnixEpochTime())); // Check internal state. mScript.assertLatestNetworkSuggestion(networkTimeSuggestion) @@ -803,7 +808,7 @@ public class TimeDetectorStrategyImplTest { // Simulate some significant time passing: half the time allowed before a time signal // becomes "too old to use". - mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_UTC_TIME_AGE_MILLIS / 2) + mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_SUGGESTION_TIME_AGE_MILLIS / 2) .verifySystemClockWasNotSetAndResetCallTracking(); // Now another gnss suggestion is made. Network suggestions are prioritized over @@ -823,7 +828,7 @@ public class TimeDetectorStrategyImplTest { // Simulate some significant time passing: half the time allowed before a time signal // becomes "too old to use". This should mean that telephonyTimeSuggestion is now too old to // be used but networkTimeSuggestion2 is not. - mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_UTC_TIME_AGE_MILLIS / 2); + mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_SUGGESTION_TIME_AGE_MILLIS / 2); // NOTE: The TimeDetectorStrategyImpl doesn't set an alarm for the point when the last // suggestion it used becomes too old: it requires a new suggestion or an auto-time toggle @@ -846,7 +851,7 @@ public class TimeDetectorStrategyImplTest { // Verify the latest gnss time now wins. mScript.verifySystemClockWasSetAndResetCallTracking( - mScript.calculateTimeInMillisForNow(gnssTimeSuggestion2.getUtcTime())); + mScript.calculateTimeInMillisForNow(gnssTimeSuggestion2.getUnixEpochTime())); // Check internal state. mScript.assertLatestNetworkSuggestion(networkTimeSuggestion) @@ -877,7 +882,8 @@ public class TimeDetectorStrategyImplTest { mScript.simulateTimePassing(smallTimeIncrementMillis) .simulateExternalTimeSuggestion(externalTimeSuggestion1) .verifySystemClockWasSetAndResetCallTracking( - mScript.calculateTimeInMillisForNow(externalTimeSuggestion1.getUtcTime())); + mScript.calculateTimeInMillisForNow( + externalTimeSuggestion1.getUnixEpochTime())); // Check internal state. mScript.assertLatestNetworkSuggestion(null) @@ -896,7 +902,8 @@ public class TimeDetectorStrategyImplTest { mScript.simulateTimePassing(smallTimeIncrementMillis) .simulateNetworkTimeSuggestion(networkTimeSuggestion) .verifySystemClockWasSetAndResetCallTracking( - mScript.calculateTimeInMillisForNow(networkTimeSuggestion.getUtcTime())); + mScript.calculateTimeInMillisForNow( + networkTimeSuggestion.getUnixEpochTime())); // Check internal state. mScript.assertLatestNetworkSuggestion(networkTimeSuggestion) @@ -906,7 +913,7 @@ public class TimeDetectorStrategyImplTest { // Simulate some significant time passing: half the time allowed before a time signal // becomes "too old to use". - mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_UTC_TIME_AGE_MILLIS / 2) + mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_SUGGESTION_TIME_AGE_MILLIS / 2) .verifySystemClockWasNotSetAndResetCallTracking(); // Now another external suggestion is made. Network suggestions are prioritized over @@ -926,7 +933,7 @@ public class TimeDetectorStrategyImplTest { // Simulate some significant time passing: half the time allowed before a time signal // becomes "too old to use". This should mean that networkTimeSuggestion is now too old to // be used but externalTimeSuggestion2 is not. - mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_UTC_TIME_AGE_MILLIS / 2); + mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_SUGGESTION_TIME_AGE_MILLIS / 2); // NOTE: The TimeDetectorStrategyImpl doesn't set an alarm for the point when the last // suggestion it used becomes too old: it requires a new suggestion or an auto-time toggle @@ -949,7 +956,7 @@ public class TimeDetectorStrategyImplTest { // Verify the latest external time now wins. mScript.verifySystemClockWasSetAndResetCallTracking( - mScript.calculateTimeInMillisForNow(externalTimeSuggestion2.getUtcTime())); + mScript.calculateTimeInMillisForNow(externalTimeSuggestion2.getUnixEpochTime())); // Check internal state. mScript.assertLatestNetworkSuggestion(networkTimeSuggestion) @@ -1438,11 +1445,11 @@ public class TimeDetectorStrategyImplTest { * reference time. */ ManualTimeSuggestion generateManualTimeSuggestion(Instant suggestedTime) { - TimestampedValue<Long> utcTime = + TimestampedValue<Long> unixEpochTime = new TimestampedValue<>( mFakeEnvironment.peekElapsedRealtimeMillis(), suggestedTime.toEpochMilli()); - return new ManualTimeSuggestion(utcTime); + return new ManualTimeSuggestion(unixEpochTime); } /** @@ -1472,11 +1479,11 @@ public class TimeDetectorStrategyImplTest { * reference time. */ NetworkTimeSuggestion generateNetworkTimeSuggestion(Instant suggestedTime) { - TimestampedValue<Long> utcTime = + TimestampedValue<Long> unixEpochTime = new TimestampedValue<>( mFakeEnvironment.peekElapsedRealtimeMillis(), suggestedTime.toEpochMilli()); - return new NetworkTimeSuggestion(utcTime); + return new NetworkTimeSuggestion(unixEpochTime); } /** @@ -1484,11 +1491,11 @@ public class TimeDetectorStrategyImplTest { * reference time. */ GnssTimeSuggestion generateGnssTimeSuggestion(Instant suggestedTime) { - TimestampedValue<Long> utcTime = + TimestampedValue<Long> unixEpochTime = new TimestampedValue<>( mFakeEnvironment.peekElapsedRealtimeMillis(), suggestedTime.toEpochMilli()); - return new GnssTimeSuggestion(utcTime); + return new GnssTimeSuggestion(unixEpochTime); } /** @@ -1504,19 +1511,19 @@ public class TimeDetectorStrategyImplTest { * Calculates what the supplied time would be when adjusted for the movement of the fake * elapsed realtime clock. */ - long calculateTimeInMillisForNow(TimestampedValue<Long> utcTime) { - return TimeDetectorStrategy.getTimeAt(utcTime, peekElapsedRealtimeMillis()); + long calculateTimeInMillisForNow(TimestampedValue<Long> unixEpochTime) { + return TimeDetectorStrategy.getTimeAt(unixEpochTime, peekElapsedRealtimeMillis()); } } private static TelephonyTimeSuggestion createTelephonyTimeSuggestion(int slotIndex, - TimestampedValue<Long> utcTime) { + TimestampedValue<Long> unixEpochTime) { return new TelephonyTimeSuggestion.Builder(slotIndex) - .setUtcTime(utcTime) + .setUnixEpochTime(unixEpochTime) .build(); } - private static Instant createUtcTime(int year, int monthInYear, int day, int hourOfDay, + private static Instant createUnixEpochTime(int year, int monthInYear, int day, int hourOfDay, int minute, int second) { return LocalDateTime.of(year, monthInYear, day, hourOfDay, minute, second) .toInstant(ZoneOffset.UTC); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 6f04f176afd8..29fa2d379379 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -37,6 +37,7 @@ import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.os.Process.NOBODY_UID; import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.InsetsState.ITYPE_IME; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; @@ -127,6 +128,8 @@ import android.view.IRemoteAnimationFinishedCallback; import android.view.IRemoteAnimationRunner.Stub; import android.view.IWindowManager; import android.view.IWindowSession; +import android.view.InsetsSource; +import android.view.InsetsState; import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationTarget; import android.view.Surface; @@ -2884,6 +2887,41 @@ public class ActivityRecordTests extends WindowTestsBase { assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); } + @UseTestDisplay(addWindows = W_INPUT_METHOD) + @Test + public void testImeInsetsFrozenFlag_resetWhenReportedToBeImeInputTarget() { + final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); + + InsetsSource imeSource = new InsetsSource(ITYPE_IME); + app.getInsetsState().addSource(imeSource); + mDisplayContent.setImeLayeringTarget(app); + mDisplayContent.updateImeInputAndControlTarget(app); + + InsetsState state = mDisplayContent.getInsetsPolicy().getInsetsForWindow(app); + assertFalse(state.getSource(ITYPE_IME).isVisible()); + assertTrue(state.getSource(ITYPE_IME).getFrame().isEmpty()); + + // Simulate app is closing and expect IME insets is frozen. + mDisplayContent.mOpeningApps.clear(); + app.mActivityRecord.commitVisibility(false, false); + app.mActivityRecord.onWindowsGone(); + assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); + + // Simulate app re-start input or turning screen off/on then unlocked by un-secure + // keyguard to back to the app, expect IME insets is not frozen + imeSource.setFrame(new Rect(100, 400, 500, 500)); + app.getInsetsState().addSource(imeSource); + app.getInsetsState().setSourceVisible(ITYPE_IME, true); + mDisplayContent.updateImeInputAndControlTarget(app); + assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); + + // Verify when IME is visible and the app can receive the right IME insets from policy. + makeWindowVisibleAndDrawn(app, mImeWindow); + state = mDisplayContent.getInsetsPolicy().getInsetsForWindow(app); + assertTrue(state.getSource(ITYPE_IME).isVisible()); + assertEquals(state.getSource(ITYPE_IME).getFrame(), imeSource.getFrame()); + } + private void assertHasStartingWindow(ActivityRecord atoken) { assertNotNull(atoken.mStartingSurface); assertNotNull(atoken.mStartingData); diff --git a/services/translation/OWNERS b/services/translation/OWNERS index a1e663aa8ff7..440f9a840057 100644 --- a/services/translation/OWNERS +++ b/services/translation/OWNERS @@ -1,8 +1,3 @@ # Bug component: 994311 -adamhe@google.com -augale@google.com -joannechung@google.com -lpeter@google.com -svetoslavganov@google.com -tymtsai@google.com +include /core/java/android/view/translation/OWNERS diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index 8cb0909def5d..21f789f4e735 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -492,6 +492,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser // current USB state private boolean mHostConnected; + private boolean mUsbAccessoryConnected; private boolean mSourcePower; private boolean mSinkPower; private boolean mConfigured; @@ -961,10 +962,10 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser break; case MSG_UPDATE_HOST_STATE: Iterator devices = (Iterator) msg.obj; - boolean connected = (msg.arg1 == 1); + mUsbAccessoryConnected = (msg.arg1 == 1); if (DEBUG) { - Slog.i(TAG, "HOST_STATE connected:" + connected); + Slog.i(TAG, "HOST_STATE connected:" + mUsbAccessoryConnected); } mHideUsbNotification = false; @@ -1218,7 +1219,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser } else if (mSourcePower) { titleRes = com.android.internal.R.string.usb_supplying_notification_title; id = SystemMessage.NOTE_USB_SUPPLYING; - } else if (mHostConnected && mSinkPower && mUsbCharging) { + } else if (mHostConnected && mSinkPower && (mUsbCharging || mUsbAccessoryConnected)) { titleRes = com.android.internal.R.string.usb_charging_notification_title; id = SystemMessage.NOTE_USB_CHARGING; } diff --git a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java index 125296540688..9a991a1b4a9a 100644 --- a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java +++ b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java @@ -107,6 +107,25 @@ public final class TelephonyUtils { } } + /** + * Convenience method for running the provided action in the provided + * executor enclosed in + * {@link Binder#clearCallingIdentity}/{@link Binder#restoreCallingIdentity} + * + * Any exception thrown by the given action will need to be handled by caller. + * + */ + public static void runWithCleanCallingIdentity( + @NonNull Runnable action, @NonNull Executor executor) { + if (action != null) { + if (executor != null) { + executor.execute(() -> runWithCleanCallingIdentity(action)); + } else { + runWithCleanCallingIdentity(action); + } + } + } + /** * Convenience method for running the provided action enclosed in diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java index 23cf5116b2da..e88106cb95fe 100644 --- a/telephony/java/android/telephony/Annotation.java +++ b/telephony/java/android/telephony/Annotation.java @@ -1,6 +1,8 @@ package android.telephony; import android.annotation.IntDef; +import android.net.NetworkAgent; +import android.net.NetworkCapabilities; import android.telecom.Connection; import android.telephony.data.ApnSetting; @@ -664,4 +666,59 @@ public class Annotation { TelephonyManager.THERMAL_MITIGATION_RESULT_INVALID_STATE, TelephonyManager.THERMAL_MITIGATION_RESULT_UNKNOWN_ERROR}) public @interface ThermalMitigationResult {} + + /** + * Per Android API guideline 8.15, annotation can't be public APIs. So duplicate + * android.net.NetworkCapabilities.NetCapability here. Must update here when new capabilities + * are added in {@link NetworkCapabilities}. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "NET_CAPABILITY_" }, value = { + NetworkCapabilities.NET_CAPABILITY_MMS, + NetworkCapabilities.NET_CAPABILITY_SUPL, + NetworkCapabilities.NET_CAPABILITY_DUN, + NetworkCapabilities.NET_CAPABILITY_FOTA, + NetworkCapabilities.NET_CAPABILITY_IMS, + NetworkCapabilities.NET_CAPABILITY_CBS, + NetworkCapabilities.NET_CAPABILITY_WIFI_P2P, + NetworkCapabilities.NET_CAPABILITY_IA, + NetworkCapabilities.NET_CAPABILITY_RCS, + NetworkCapabilities.NET_CAPABILITY_XCAP, + NetworkCapabilities.NET_CAPABILITY_EIMS, + NetworkCapabilities.NET_CAPABILITY_NOT_METERED, + NetworkCapabilities.NET_CAPABILITY_INTERNET, + NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED, + NetworkCapabilities.NET_CAPABILITY_TRUSTED, + NetworkCapabilities.NET_CAPABILITY_NOT_VPN, + NetworkCapabilities.NET_CAPABILITY_VALIDATED, + NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL, + NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, + NetworkCapabilities.NET_CAPABILITY_FOREGROUND, + NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED, + NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED, + NetworkCapabilities.NET_CAPABILITY_OEM_PAID, + NetworkCapabilities.NET_CAPABILITY_MCX, + NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY, + NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED, + NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, + NetworkCapabilities.NET_CAPABILITY_VEHICLE_INTERNAL, + NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED, + NetworkCapabilities.NET_CAPABILITY_ENTERPRISE, + NetworkCapabilities.NET_CAPABILITY_VSIM, + NetworkCapabilities.NET_CAPABILITY_BIP, + NetworkCapabilities.NET_CAPABILITY_HEAD_UNIT, + }) + public @interface NetCapability { } + + /** + * Per Android API guideline 8.15, annotation can't be public APIs. So duplicate + * android.net.NetworkAgent.ValidationStatus here. Must update here when new validation status + * are added in {@link NetworkAgent}. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "VALIDATION_STATUS_" }, value = { + NetworkAgent.VALIDATION_STATUS_VALID, + NetworkAgent.VALIDATION_STATUS_NOT_VALID + }) + public @interface ValidationStatus {} } diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 9a764a0a0a3a..8f957fd6c855 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -28,6 +28,7 @@ import android.annotation.SystemService; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; +import android.net.NetworkCapabilities; import android.net.ipsec.ike.SaProposal; import android.os.Build; import android.os.PersistableBundle; @@ -168,7 +169,10 @@ public class CarrierConfigManager { /** * This flag specifies whether VoLTE availability is based on provisioning. By default this is * false. + * Used for UCE to determine if EAB provisioning checks should be based on provisioning. + * @deprecated Use {@link Ims#KEY_MMTEL_REQUIRES_PROVISIONING_BUNDLE} instead. */ + @Deprecated public static final String KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool"; @@ -349,6 +353,12 @@ public class CarrierConfigManager { KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool"; /** + * Flag indicating if the carrier supports tethering of mobile data. + */ + public static final String KEY_CARRIER_SUPPORTS_TETHERING_BOOL = + "carrier_supports_tethering_bool"; + + /** * Flag indicating whether radio is to be restarted on error PDP_FAIL_REGULAR_DEACTIVATION * This is false by default. * @@ -858,7 +868,12 @@ public class CarrierConfigManager { /** * Flag specifying whether provisioning is required for VoLTE, Video Telephony, and WiFi * Calling. + + * Combines VoLTE, VT, VoWiFI calling provisioning into one parameter. + * @deprecated Use {@link Ims#KEY_MMTEL_REQUIRES_PROVISIONING_BUNDLE} instead for + * finer-grained control. */ + @Deprecated public static final String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool"; @@ -872,7 +887,11 @@ public class CarrierConfigManager { * and enable the UT over IMS capability for the subscription when the subscription is loaded. * * The default value for this key is {@code false}. + * + * @deprecated Use {@link Ims#KEY_MMTEL_REQUIRES_PROVISIONING_BUNDLE} instead for + * determining if UT requires provisioning. */ + @Deprecated public static final String KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL = "carrier_ut_provisioning_required_bool"; @@ -3705,7 +3724,7 @@ public class CarrierConfigManager { /** * SMDP+ server address for downloading opportunistic eSIM profile. * FQDN (Fully Qualified Domain Name) of the SM-DP+ (e.g., smdp.gsma.com) restricted to the - * Alphanumeric mode character set defined in table 5 of ISO/IEC 18004 [15] excluding '$'. + * Alphanumeric mode character set defined in table 5 of ISO/IEC 18004 excluding '$'. */ public static final String KEY_SMDP_SERVER_ADDRESS_STRING = "smdp_server_address_string"; @@ -3749,29 +3768,52 @@ public class CarrierConfigManager { "opportunistic_carrier_ids_int_array"; /** - * Controls RSRP threshold at which OpportunisticNetworkService will decide whether + * Boolean configuration to control auto provisioning eSIM download in + * OpportunisticNetworkService using only WiFi or both WiFi/Data. + * True will download esim only via WiFi. + * False will use both WiFi and Data connection. + * + * @hide + */ + public static final String KEY_OPPORTUNISTIC_ESIM_DOWNLOAD_VIA_WIFI_ONLY_BOOL = + "opportunistic_esim_download_via_wifi_only_bool"; + +/** + * Controls RSRP threshold, in dBm, at which OpportunisticNetworkService will decide whether * the opportunistic network is good enough for internet data. + * + * <p>The value of {@link CellSignalStrengthLte#getRsrp()} will be compared with this + * threshold. */ public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSRP_INT = "opportunistic_network_entry_threshold_rsrp_int"; /** - * Controls RSSNR threshold at which OpportunisticNetworkService will decide whether - * the opportunistic network is good enough for internet data. + * Controls RSSNR threshold, in dB, at which OpportunisticNetworkService will + * decide whether the opportunistic network is good enough for internet data. + * + * <p>The value of {@link CellSignalStrengthLte#getRssnr()} will be compared with this + * threshold. */ public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSSNR_INT = "opportunistic_network_entry_threshold_rssnr_int"; /** - * Controls RSRP threshold below which OpportunisticNetworkService will decide whether + * Controls RSRP threshold, in dBm, below which OpportunisticNetworkService will decide whether * the opportunistic network available is not good enough for internet data. + * + * <p>The value of {@link CellSignalStrengthLte#getRsrp()} will be compared with this + * threshold. */ public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSRP_INT = "opportunistic_network_exit_threshold_rsrp_int"; /** - * Controls RSSNR threshold below which OpportunisticNetworkService will decide whether - * the opportunistic network available is not good enough for internet data. + * Controls RSSNR threshold, in dB, below which OpportunisticNetworkService will + * decide whether the opportunistic network available is not good enough for internet data. + * + * <p>The value of {@link CellSignalStrengthLte#getRssnr()} will be compared with this + * threshold. */ public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT = "opportunistic_network_exit_threshold_rssnr_int"; @@ -3855,101 +3897,248 @@ public class CarrierConfigManager { public static final String KEY_OPPORTUNISTIC_NETWORK_MAX_BACKOFF_TIME_LONG = "opportunistic_network_max_backoff_time_long"; - /** - * Controls SS-RSRP threshold in dBm at which 5G opportunistic network will be considered good - * enough for internet data. - * - * @hide - */ - public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_SS_RSRP_INT = - "opportunistic_network_entry_threshold_ss_rsrp_int"; + /** @hide */ + public static class OpportunisticNetwork { + /** + * Prefix of all {@code OpportunisticNetwork.KEY_*} constants. + * + * @hide + */ + public static final String PREFIX = "opportunistic."; - /** - * Controls SS-RSRQ threshold in dB at which 5G opportunistic network will be considered good - * enough for internet data. - * - * @hide - */ - public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_SS_RSRQ_DOUBLE = - "opportunistic_network_entry_threshold_ss_rsrq_double"; + /** + * Controls SS-RSRP threshold in dBm at which 5G opportunistic network will be considered + * good enough for internet data. Note other factors may be considered for the final + * decision. + * + * <p>The value of {@link CellSignalStrengthNr#getSsRsrp()} will be compared with this + * threshold. + * + * @hide + */ + public static final String KEY_ENTRY_THRESHOLD_SS_RSRP_INT = + PREFIX + "entry_threshold_ss_rsrp_int"; - /** - * Controls SS-RSRP threshold in dBm below which 5G opportunistic network available will not - * be considered good enough for internet data. - * - * @hide - */ - public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_SS_RSRP_INT = - "opportunistic_network_exit_threshold_ss_rsrp_int"; + /** + * Similar to {@link #KEY_ENTRY_THRESHOLD_SS_RSRP_INT} but supports different + * thresholds for different 5G bands. For bands not specified here, the threshold + * will be {@link #KEY_ENTRY_THRESHOLD_SS_RSRP_INT}. + * + * <p>For each key-value in the bundle: the key is the band number in string, which + * shall be a decimal integer as defined in {@code NgranBands.BAND_*} constants; + * the value is the threshold in int. + * + * @hide + */ + public static final String KEY_ENTRY_THRESHOLD_SS_RSRP_INT_BUNDLE = + PREFIX + "entry_threshold_ss_rsrp_int_bundle"; - /** - * Controls SS-RSRQ threshold in dB below which 5G opportunistic network available will not - * be considered good enough for internet data. - * - * @hide - */ - public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_SS_RSRQ_DOUBLE = - "opportunistic_network_exit_threshold_ss_rsrq_double"; + /** + * Controls SS-RSRQ threshold in dB at which 5G opportunistic network will be considered + * good enough for internet data. Note other factors may be considered for the final + * decision. + * + * <p>The value of {@link CellSignalStrengthNr#getSsRsrq()} will be compared with this + * threshold. + * + * @hide + */ + public static final String KEY_ENTRY_THRESHOLD_SS_RSRQ_DOUBLE = + PREFIX + "entry_threshold_ss_rsrq_double"; - /** - * Controls back off time in milliseconds for switching back to - * 5G opportunistic subscription. This time will be added to - * {@link CarrierConfigManager#KEY_OPPORTUNISTIC_NETWORK_5G_DATA_SWITCH_HYSTERESIS_TIME_LONG} to - * determine hysteresis time if there is ping pong situation - * (determined by system app or 1st party app) between primary and 5G opportunistic - * subscription. Ping ping situation is defined in - * #KEY_OPPORTUNISTIC_NETWORK_5G_PING_PONG_TIME_LONG. - * If ping pong situation continuous #KEY_OPPORTUNISTIC_5G_NETWORK_BACKOFF_TIME_LONG - * will be added to previously determined hysteresis time. - * - * @hide - */ - public static final String KEY_OPPORTUNISTIC_NETWORK_5G_BACKOFF_TIME_LONG = - "opportunistic_network_5g_backoff_time_long"; + /** + * Similar to {@link #KEY_ENTRY_THRESHOLD_SS_RSRQ_DOUBLE} but supports different + * thresholds for different 5G bands. For bands not specified here, the threshold + * will be {@link #KEY_ENTRY_THRESHOLD_SS_RSRQ_DOUBLE}. + * + * <p>For each key-value in the bundle: the key is the band number in string, which + * shall be a decimal integer as defined in {@code NgranBands.BAND_*} constants; + * the value is the threshold in double. + * + * @hide + */ + public static final String KEY_ENTRY_THRESHOLD_SS_RSRQ_DOUBLE_BUNDLE = + PREFIX + "entry_threshold_ss_rsrq_double_bundle"; - /** - * Controls the max back off time in milliseconds for switching back to - * 5G opportunistic subscription. - * This time will be the max hysteresis that can be determined irrespective of there is - * continuous ping pong situation or not as described in - * #KEY_OPPORTUNISTIC_NETWORK_5G_PING_PONG_TIME_LONG and - * #KEY_OPPORTUNISTIC_NETWORK_5G_BACKOFF_TIME_LONG. - * - * @hide - */ - public static final String KEY_OPPORTUNISTIC_NETWORK_5G_MAX_BACKOFF_TIME_LONG = - "opportunistic_network_5g_max_backoff_time_long"; + /** + * Controls SS-RSRP threshold in dBm below which 5G opportunistic network available will not + * be considered good enough for internet data. Note other factors may be considered + * for the final decision. + * + * <p>The value of {@link CellSignalStrengthNr#getSsRsrp()} will be compared with this + * threshold. + * + * @hide + */ + public static final String KEY_EXIT_THRESHOLD_SS_RSRP_INT = + PREFIX + "exit_threshold_ss_rsrp_int"; - /** - * Controls the ping pong determination of 5G opportunistic network. - * If opportunistic network is determined as out of service or below - * #KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_SS_RSRP_INT or - * #KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_SS_RSRQ_INT within - * #KEY_OPPORTUNISTIC_NETWORK_5G_PING_PONG_TIME_LONG of switching to opportunistic network, - * it will be determined as ping pong situation by system app or 1st party app. - * - * @hide - */ - public static final String KEY_OPPORTUNISTIC_NETWORK_5G_PING_PONG_TIME_LONG = - "opportunistic_network_5g_ping_pong_time_long"; + /** + * Similar to {@link #KEY_EXIT_THRESHOLD_SS_RSRP_INT} but supports different + * thresholds for different 5G bands. For bands not specified here, the threshold + * will be {@link #KEY_EXIT_THRESHOLD_SS_RSRP_INT}. + * + * <p>The syntax of its value is similar to + * {@link #KEY_ENTRY_THRESHOLD_SS_RSRP_INT_BUNDLE}. + * + * @hide + */ + public static final String KEY_EXIT_THRESHOLD_SS_RSRP_INT_BUNDLE = + PREFIX + "exit_threshold_ss_rsrp_int_bundle"; - /** - * Controls hysteresis time in milliseconds for which will be waited before switching - * data to a 5G opportunistic network. - * - * @hide - */ - public static final String KEY_OPPORTUNISTIC_NETWORK_5G_DATA_SWITCH_HYSTERESIS_TIME_LONG = - "opportunistic_network_5g_data_switch_hysteresis_time_long"; + /** + * Controls SS-RSRQ threshold in dB below which 5G opportunistic network available will not + * be considered good enough for internet data. Note other factors may be considered + * for the final decision. + * + * <p>The value of {@link CellSignalStrengthNr#getSsRsrq()} will be compared with this + * threshold. + * + * @hide + */ + public static final String KEY_EXIT_THRESHOLD_SS_RSRQ_DOUBLE = + PREFIX + "exit_threshold_ss_rsrq_double"; + + /** + * Similar to {@link #KEY_EXIT_THRESHOLD_SS_RSRQ_DOUBLE} but supports different + * thresholds for different 5G bands. For bands not specified here, the threshold + * will be {@link #KEY_EXIT_THRESHOLD_SS_RSRQ_DOUBLE}. + * + * <p>The syntax of its value is similar to + * {@link #KEY_ENTRY_THRESHOLD_SS_RSRQ_DOUBLE_BUNDLE}. + * + * @hide + */ + public static final String KEY_EXIT_THRESHOLD_SS_RSRQ_DOUBLE_BUNDLE = + PREFIX + "exit_threshold_ss_rsrq_double_bundle"; + + /** + * Controls hysteresis time in milliseconds for which will be waited before switching + * data to a 5G opportunistic network. + * + * @hide + */ + public static final String KEY_5G_DATA_SWITCH_HYSTERESIS_TIME_LONG = + PREFIX + "5g_data_switch_hysteresis_time_long"; + + /** + * Similar to {@link #KEY_5G_DATA_SWITCH_HYSTERESIS_TIME_LONG} but supports + * different values for different 5G bands. For bands not specified here, the threshold + * will be {@link #KEY_5G_DATA_SWITCH_HYSTERESIS_TIME_LONG}. + * + * <p>For each key-value in the bundle: the key is the band number in string, which + * shall be a decimal integer as defined in {@code NgranBands.BAND_*} constants; + * the value is the time in long. + * + * @hide + */ + public static final String KEY_5G_DATA_SWITCH_HYSTERESIS_TIME_LONG_BUNDLE = + PREFIX + "5g_data_switch_hysteresis_time_long_bundle"; + + /** + * Controls hysteresis time in milliseconds for which will be waited before switching from + * 5G opportunistic network to primary network. + * + * @hide + */ + public static final String KEY_5G_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG = + PREFIX + "5g_data_switch_exit_hysteresis_time_long"; + + /** + * Similar to {@link #KEY_5G_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG} but supports + * different values for different 5G bands. For bands not specified here, the threshold + * will be {@link #KEY_5G_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG}. + * + * <p>The syntax is similar to + * {@link KEY_5G_DATA_SWITCH_HYSTERESIS_TIME_LONG_BUNDLE}. + * + * @hide + */ + public static final String KEY_5G_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG_BUNDLE = + PREFIX + "5g_data_switch_exit_hysteresis_time_long_bundle"; + + /** + * Controls back off time in milliseconds for switching back to + * 5G opportunistic subscription. This time will be added to + * {@link #KEY_5G_DATA_SWITCH_HYSTERESIS_TIME_LONG} to + * determine hysteresis time if there is ping pong situation + * (determined by system app or 1st party app) between primary and 5G opportunistic + * subscription. Ping ping situation is defined in + * {@link #KEY_5G_PING_PONG_TIME_LONG}. + * If ping pong situation continuous {@link #KEY_5G_NETWORK_BACKOFF_TIME_LONG} + * will be added to previously determined hysteresis time. + * + * @hide + */ + public static final String KEY_5G_BACKOFF_TIME_LONG = + PREFIX + "5g_backoff_time_long"; + + /** + * Controls the max back off time in milliseconds for switching back to + * 5G opportunistic subscription. + * This time will be the max hysteresis that can be determined irrespective of there is + * continuous ping pong situation or not as described in + * {@link #KEY_5G_PING_PONG_TIME_LONG} and + * {@link #KEY_5G_BACKOFF_TIME_LONG}. + * + * @hide + */ + public static final String KEY_5G_MAX_BACKOFF_TIME_LONG = + PREFIX + "5g_max_backoff_time_long"; + + /** + * Controls the ping pong determination of 5G opportunistic network. + * If opportunistic network is determined as out of service or below + * {@link #KEY_EXIT_THRESHOLD_SS_RSRP_INT} or + * {@link #KEY_EXIT_THRESHOLD_SS_RSRQ_DOUBLE} within + * {@link #KEY_5G_PING_PONG_TIME_LONG} of switching to opportunistic network, + * it will be determined as ping pong situation by system app or 1st party app. + * + * @hide + */ + public static final String KEY_5G_PING_PONG_TIME_LONG = + PREFIX + "5g_ping_pong_time_long"; + + private static PersistableBundle getDefaults() { + PersistableBundle defaults = new PersistableBundle(); + // Default value is -111 dBm for all bands. + sDefaults.putInt(KEY_ENTRY_THRESHOLD_SS_RSRP_INT, -111); + sDefaults.putPersistableBundle(KEY_ENTRY_THRESHOLD_SS_RSRP_INT_BUNDLE, + PersistableBundle.EMPTY); + // Default value is -18.5 dB for all bands. + sDefaults.putDouble(KEY_ENTRY_THRESHOLD_SS_RSRQ_DOUBLE, -18.5); + sDefaults.putPersistableBundle( + KEY_ENTRY_THRESHOLD_SS_RSRQ_DOUBLE_BUNDLE, + PersistableBundle.EMPTY); + // Default value is -120 dBm for all bands. + sDefaults.putInt(KEY_EXIT_THRESHOLD_SS_RSRP_INT, -120); + sDefaults.putPersistableBundle(KEY_EXIT_THRESHOLD_SS_RSRP_INT_BUNDLE, + PersistableBundle.EMPTY); + // Default value is -18.5 dB for all bands. + sDefaults.putDouble(KEY_EXIT_THRESHOLD_SS_RSRQ_DOUBLE, -18.5); + sDefaults.putPersistableBundle( + KEY_EXIT_THRESHOLD_SS_RSRQ_DOUBLE_BUNDLE, + PersistableBundle.EMPTY); + // Default value is 2 seconds for all bands. + defaults.putLong(KEY_5G_DATA_SWITCH_HYSTERESIS_TIME_LONG, 2000); + defaults.putPersistableBundle( + KEY_5G_DATA_SWITCH_HYSTERESIS_TIME_LONG_BUNDLE, + PersistableBundle.EMPTY); + // Default value is 2 seconds for all bands. + defaults.putLong(KEY_5G_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG, 2000); + defaults.putPersistableBundle( + KEY_5G_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG_BUNDLE, + PersistableBundle.EMPTY); + // Default value is 10 seconds. + sDefaults.putLong(KEY_5G_BACKOFF_TIME_LONG, 10000); + // Default value is 60 seconds. + sDefaults.putLong(KEY_5G_MAX_BACKOFF_TIME_LONG, 60000); + // Default value is 60 seconds. + sDefaults.putLong(KEY_5G_PING_PONG_TIME_LONG, 60000); + return defaults; + } + } - /** - * Controls hysteresis time in milliseconds for which will be waited before switching from - * 5G opportunistic network to primary network. - * - * @hide - */ - public static final String KEY_OPPORTUNISTIC_NETWORK_5G_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG = - "opportunistic_network_5g_data_switch_exit_hysteresis_time_long"; /** * Controls whether 4G opportunistic networks should be scanned for possible data switch. * @@ -4402,12 +4591,10 @@ public class CarrierConfigManager { "carrier_auto_cancel_cs_notification"; /** - * Passing this value as {@link KEY_SUBSCRIPTION_GROUP_UUID_STRING} will remove the + * Passing this value as {@link #KEY_SUBSCRIPTION_GROUP_UUID_STRING} will remove the * subscription from a group instead of adding it to a group. * - * TODO: Expose in a future release. - * - * @hide + * <p>This value will work all the way back to {@link android.os.Build.VERSION_CODES#Q}. */ public static final String REMOVE_GROUP_UUID_STRING = "00000000-0000-0000-0000-000000000000"; @@ -4420,9 +4607,7 @@ public class CarrierConfigManager { * <p>If set to {@link #REMOVE_GROUP_UUID_STRING}, then the subscription will be removed from * its current group. * - * TODO: unhide this key. - * - * @hide + * <p>This key will work all the way back to {@link android.os.Build.VERSION_CODES#Q}. */ public static final String KEY_SUBSCRIPTION_GROUP_UUID_STRING = "subscription_group_uuid_string"; @@ -4447,17 +4632,15 @@ public class CarrierConfigManager { "data_switch_validation_min_gap_long"; /** - * A boolean property indicating whether this subscription should be managed as an opportunistic - * subscription. - * - * If true, then this subscription will be selected based on available coverage and will not be - * available for a user in settings menus for selecting macro network providers. If unset, - * defaults to “false”. - * - * TODO: unhide this key. - * - * @hide - */ + * A boolean property indicating whether this subscription should be managed as an opportunistic + * subscription. + * + * If true, then this subscription will be selected based on available coverage and will not be + * available for a user in settings menus for selecting macro network providers. If unset, + * defaults to “false”. + * + * <p>This key will work all the way back to {@link android.os.Build.VERSION_CODES#Q}. + */ public static final String KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL = "is_opportunistic_subscription_bool"; @@ -4596,6 +4779,15 @@ public class CarrierConfigManager { KEY_PREFIX + "enable_presence_group_subscribe_bool"; /** + * Flag indicating whether or not to use SIP URI when send a presence subscribe. + * When {@code true}, the device sets the To and Contact header to be SIP URI using + * the TelephonyManager#getIsimDomain" API. + * If {@code false}, the device uses a TEL URI. + */ + public static final String KEY_USE_SIP_URI_FOR_PRESENCE_SUBSCRIBE_BOOL = + KEY_PREFIX + "use_sip_uri_for_presence_subscribe_bool"; + + /** * An integer key associated with the period of time in seconds the non-rcs capability * information of each contact is cached on the device. * <p> @@ -4637,6 +4829,134 @@ public class CarrierConfigManager { public static final String KEY_RCS_REQUEST_RETRY_INTERVAL_MILLIS_LONG = KEY_PREFIX + "rcs_request_retry_interval_millis_long"; + /** + * A bundle which specifies the MMTEL capability and registration technology + * that requires provisioning. If a tuple is not present, the + * framework will not require that the tuple requires provisioning before + * enabling the capability. + * <p> Possible keys in this bundle are + * <ul> + * <li>{@link #KEY_CAPABILITY_TYPE_VOICE_INT_ARRAY}</li> + * <li>{@link #KEY_CAPABILITY_TYPE_VIDEO_INT_ARRAY}</li> + * <li>{@link #KEY_CAPABILITY_TYPE_UT_INT_ARRAY}</li> + * <li>{@link #KEY_CAPABILITY_TYPE_SMS_INT_ARRAY}</li> + * <li>{@link #KEY_CAPABILITY_TYPE_CALL_COMPOSER_INT_ARRAY}</li> + * </ul> + * <p> The values are defined in + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationTech} + */ + public static final String KEY_MMTEL_REQUIRES_PROVISIONING_BUNDLE = + KEY_PREFIX + "mmtel_requires_provisioning_bundle"; + + /** + * List of different RAT technologies on which Provisioning for Voice calling (IR.92) + * is supported. + * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE + * <p>Possible values are, + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR} + */ + public static final String KEY_CAPABILITY_TYPE_VOICE_INT_ARRAY = + KEY_PREFIX + "capability_type_voice_int_array"; + + /** + * List of different RAT technologies on which Provisioning for Video Telephony (IR.94) + * is supported. + * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO + * <p>Possible values are, + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR} + */ + public static final String KEY_CAPABILITY_TYPE_VIDEO_INT_ARRAY = + KEY_PREFIX + "capability_type_video_int_array"; + + /** + * List of different RAT technologies on which Provisioning for XCAP over Ut for + * supplementary services. (IR.92) is supported. + * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT + * <p>Possible values are, + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR} + */ + public static final String KEY_CAPABILITY_TYPE_UT_INT_ARRAY = + KEY_PREFIX + "capability_type_ut_int_array"; + + /** + * List of different RAT technologies on which Provisioning for SMS (IR.92) is supported. + * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS + * <p>Possible values are, + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR} + */ + public static final String KEY_CAPABILITY_TYPE_SMS_INT_ARRAY = + KEY_PREFIX + "capability_type_sms_int_array"; + + /** + * List of different RAT technologies on which Provisioning for Call Composer + * (section 2.4 of RCC.20) is supported. + * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_CALL_COMPOSER + * <p>Possible values are, + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR} + */ + public static final String KEY_CAPABILITY_TYPE_CALL_COMPOSER_INT_ARRAY = + KEY_PREFIX + "capability_type_call_composer_int_array"; + + /** + * A bundle which specifies the RCS capability and registration technology + * that requires provisioning. If a tuple is not present, the + * framework will not require that the tuple requires provisioning before + * enabling the capability. + * <p> Possible keys in this bundle are + * <ul> + * <li>{@link #KEY_CAPABILITY_TYPE_OPTIONS_UCE_INT_ARRAY}</li> + * <li>{@link #KEY_CAPABILITY_TYPE_PRESENCE_UCE_INT_ARRAY}</li> + * </ul> + * <p> The values are defined in + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationTech} + */ + public static final String KEY_RCS_REQUIRES_PROVISIONING_BUNDLE = + KEY_PREFIX + "rcs_requires_provisioning_bundle"; + + /** + * This carrier supports User Capability Exchange using SIP OPTIONS as defined by the + * framework. If set, the RcsFeature should support capability exchange using SIP OPTIONS. + * If not set, this RcsFeature should not service capability requests. + * @see RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_OPTIONS_UCE + * <p>Possible values are, + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR} + */ + public static final String KEY_CAPABILITY_TYPE_OPTIONS_UCE_INT_ARRAY = + KEY_PREFIX + "capability_type_options_uce_int_array"; + + /** + * This carrier supports User Capability Exchange using a presence server as defined by the + * framework. If set, the RcsFeature should support capability exchange using a presence + * server. If not set, this RcsFeature should not publish capabilities or service capability + * requests using presence. + * @see RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_PRESENCE_UCE + * <p>Possible values are, + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM} + * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR} + */ + public static final String KEY_CAPABILITY_TYPE_PRESENCE_UCE_INT_ARRAY = + KEY_PREFIX + "capability_type_presence_uce_int_array"; + private Ims() {} private static PersistableBundle getDefaults() { @@ -4649,6 +4969,7 @@ public class CarrierConfigManager { defaults.putBoolean(KEY_ENABLE_PRESENCE_CAPABILITY_EXCHANGE_BOOL, false); defaults.putBoolean(KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL, false); defaults.putBoolean(KEY_ENABLE_PRESENCE_GROUP_SUBSCRIBE_BOOL, false); + defaults.putBoolean(KEY_USE_SIP_URI_FOR_PRESENCE_SUBSCRIBE_BOOL, false); defaults.putInt(KEY_NON_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC_INT, 30 * 24 * 60 * 60); defaults.putBoolean(KEY_RCS_REQUEST_FORBIDDEN_BY_SIP_489_BOOL, false); defaults.putLong(KEY_RCS_REQUEST_RETRY_INTERVAL_MILLIS_LONG, 20 * 60 * 1000); @@ -4673,6 +4994,17 @@ public class CarrierConfigManager { "+g.gsma.rcs.botversion=\"#=1,#=2\"", "+g.gsma.rcs.cpimext"}); + /** + * @see #KEY_MMTEL_REQUIRES_PROVISIONING_BUNDLE + */ + defaults.putPersistableBundle( + KEY_MMTEL_REQUIRES_PROVISIONING_BUNDLE, new PersistableBundle()); + /** + * @see #KEY_RCS_REQUIRES_PROVISIONING_BUNDLE + */ + defaults.putPersistableBundle( + KEY_RCS_REQUIRES_PROVISIONING_BUNDLE, new PersistableBundle()); + return defaults; } } @@ -5133,6 +5465,53 @@ public class CarrierConfigManager { public static final String KEY_APN_PRIORITY_STRING_ARRAY = "apn_priority_string_array"; /** + * Network capability priority for determine the satisfy order in telephony. The priority is + * from the lowest 0 to the highest 100. The long-lived network shall have the lowest priority. + * This allows other short-lived requests like MMS requests to be established. Emergency request + * always has the highest priority. + * + * @hide + */ + public static final String KEY_TELEPHONY_NETWORK_CAPABILITY_PRIORITIES_STRING_ARRAY = + "telephony_network_capability_priorities_string_array"; + + /** + * Defines the rules for data retry. + * + * The syntax of the retry rule: + * 1. Retry based on {@link NetworkCapabilities}. Note that only APN-type network capabilities + * are supported. + * "capabilities=[netCaps1|netCaps2|...], [retry_interval=n1|n2|n3|n4...], [maximum_retries=n]" + * + * 2. Retry based on {@link DataFailCause} + * "fail_causes=[cause1|cause2|cause3|..], [retry_interval=n1|n2|n3|n4...], [maximum_retries=n]" + * + * 3. Retry based on {@link NetworkCapabilities} and {@link DataFailCause}. Note that only + * APN-type network capabilities are supported. + * "capabilities=[netCaps1|netCaps2|...], fail_causes=[cause1|cause2|cause3|...], + * [retry_interval=n1|n2|n3|n4...], [maximum_retries=n]" + * + * For example, + * "capabilities=eims, retry_interval=1000, maximum_retries=20" means if the attached + * network request is emergency, then retry data network setup every 1 second for up to 20 + * times. + * + * "fail_causes=8|27|28|29|30|32|33|35|50|51|111|-5|-6|65537|65538|-3|2253|2254 + * , maximum_retries=0" means for those fail causes, never retry with timers. Note that + * when environment changes, retry can still happen. + * + * "capabilities=internet|enterprise|dun|ims|fota, retry_interval=2500|3000|" + * "5000|10000|15000|20000|40000|60000|120000|240000|600000|1200000|1800000" + * "1800000, maximum_retries=20" means for those capabilities, retry happens in 2.5s, 3s, 5s, + * 10s, 15s, 20s, 40s, 1m, 2m, 4m, 10m, 20m, 30m, 30m, 30m, until reaching 20 retries. + * + * // TODO: remove KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS + * @hide + */ + public static final String KEY_TELEPHONY_DATA_RETRY_RULES_STRING_ARRAY = + "telephony_data_retry_rules_string_array"; + + /** * The patterns of missed incoming call sms. This is the regular expression used for * matching the missed incoming call's date, time, and caller id. The pattern should match * fields for at least month, day, hour, and minute. Year is optional although it is encouraged. @@ -5421,6 +5800,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_VOICE_PRIVACY_DISABLE_UI_BOOL, false); sDefaults.putBoolean(KEY_WORLD_PHONE_BOOL, false); sDefaults.putBoolean(KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, true); + sDefaults.putBoolean(KEY_CARRIER_SUPPORTS_TETHERING_BOOL, true); sDefaults.putBoolean(KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL, false); sDefaults.putIntArray(KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY, new int[]{}); sDefaults.putInt(KEY_VOLTE_REPLACEMENT_RAT_INT, 0); @@ -5815,14 +6195,15 @@ public class CarrierConfigManager { sDefaults.putInt(KEY_ESIM_MAX_DOWNLOAD_RETRY_ATTEMPTS_INT, 5); sDefaults.putInt(KEY_ESIM_DOWNLOAD_RETRY_BACKOFF_TIMER_SEC_INT, 60); sDefaults.putIntArray(KEY_OPPORTUNISTIC_CARRIER_IDS_INT_ARRAY, new int[] {0}); + sDefaults.putBoolean(KEY_OPPORTUNISTIC_ESIM_DOWNLOAD_VIA_WIFI_ONLY_BOOL, false); /* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_GOOD */ sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSRP_INT, -108); /* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_MODERATE */ sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSRP_INT, -118); /* Default value is minimum RSSNR level needed for SIGNAL_STRENGTH_GOOD */ - sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSSNR_INT, 45); + sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSSNR_INT, 5); /* Default value is minimum RSSNR level needed for SIGNAL_STRENGTH_MODERATE */ - sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT, 10); + sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT, 1); /* Default value is 1024 kbps */ sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_BANDWIDTH_INT, 1024); /* Default value is 10 seconds */ @@ -5831,6 +6212,7 @@ public class CarrierConfigManager { sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_HYSTERESIS_TIME_LONG, 10000); /* Default value is 3 seconds. */ sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG, 3000); + sDefaults.putAll(OpportunisticNetwork.getDefaults()); sDefaults.putBoolean(KEY_PING_TEST_BEFORE_DATA_SWITCH_BOOL, true); sDefaults.putBoolean(KEY_SWITCH_DATA_TO_PRIMARY_IF_PRIMARY_IS_OOS_BOOL, true); /* Default value is 60 seconds. */ @@ -5839,24 +6221,6 @@ public class CarrierConfigManager { sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_BACKOFF_TIME_LONG, 10000); /* Default value is 60 seconds. */ sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_MAX_BACKOFF_TIME_LONG, 60000); - /* Default value is -111 dBm. */ - sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_SS_RSRP_INT, -111); - /* Default value is -18.5 dB. */ - sDefaults.putDouble(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_SS_RSRQ_DOUBLE, -18.5); - /* Default value is -120 dBm. */ - sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_SS_RSRP_INT, -120); - /* Default value is -18.5 dB. */ - sDefaults.putDouble(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_SS_RSRQ_DOUBLE, -18.5); - /* Default value is 10 seconds. */ - sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_5G_BACKOFF_TIME_LONG, 10000); - /* Default value is 60 seconds. */ - sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_5G_MAX_BACKOFF_TIME_LONG, 60000); - /* Default value is 60 seconds. */ - sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_5G_PING_PONG_TIME_LONG, 60000); - /* Default value is 2 seconds. */ - sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_5G_DATA_SWITCH_HYSTERESIS_TIME_LONG, 2000); - /* Default value is 2 seconds. */ - sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_5G_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG, 2000); sDefaults.putBoolean(KEY_ENABLE_4G_OPPORTUNISTIC_NETWORK_SCAN_BOOL, true); sDefaults.putLong(KEY_TIME_TO_SWITCH_BACK_TO_PRIMARY_IF_OPPORTUNISTIC_OOS_LONG, 60000L); sDefaults.putLong( @@ -5915,6 +6279,24 @@ public class CarrierConfigManager { "enterprise:0", "default:1", "mms:2", "supl:2", "dun:2", "hipri:3", "fota:2", "ims:2", "cbs:2", "ia:2", "emergency:2", "mcx:3", "xcap:3" }); + + // Do not modify the priority unless you know what you are doing. This will have significant + // impacts on the order of data network setup. + sDefaults.putStringArray( + KEY_TELEPHONY_NETWORK_CAPABILITY_PRIORITIES_STRING_ARRAY, new String[] { + "eims:90", "supl:80", "mms:70", "xcap:70", "cbs:50", "mcx:50", "fota:50", + "ims:40", "dun:30", "enterprise:20", "internet:20" + }); + sDefaults.putStringArray( + KEY_TELEPHONY_DATA_RETRY_RULES_STRING_ARRAY, new String[] { + "capabilities=eims, retry_interval=1000, maximum_retries=20", + "fail_causes=8|27|28|29|30|32|33|35|50|51|111|-5|-6|65537|65538|-3|2253|" + + "2254, maximum_retries=0", // No retry for those causes + "capabilities=mms|supl|cbs, retry_interval=2000", + "capabilities=internet|enterprise|dun|ims|fota, retry_interval=2500|3000|" + + "5000|10000|15000|20000|40000|60000|120000|240000|" + + "600000|1200000|1800000, maximum_retries=20" + }); sDefaults.putStringArray(KEY_MISSED_INCOMING_CALL_SMS_PATTERN_STRING_ARRAY, new String[0]); sDefaults.putBoolean(KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL, false); sDefaults.putString(KEY_DEFAULT_PREFERRED_APN_NAME_STRING, ""); diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java index 947dc0107dba..5e902613a654 100644 --- a/telephony/java/android/telephony/CellSignalStrengthLte.java +++ b/telephony/java/android/telephony/CellSignalStrengthLte.java @@ -125,13 +125,13 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P /** * Construct a cell signal strength * - * @param rssi in dBm [-113,-51], UNKNOWN - * @param rsrp in dBm [-140,-43], UNKNOWN - * @param rsrq in dB [-34, 3], UNKNOWN - * @param rssnr in dB [-20, +30], UNKNOWN - * @param cqiTableIndex [1, 6], UNKNOWN - * @param cqi [0, 15], UNKNOWN - * @param timingAdvance [0, 1282], UNKNOWN + * @param rssi in dBm [-113,-51], {@link CellInfo#UNAVAILABLE} + * @param rsrp in dBm [-140,-43], {@link CellInfo#UNAVAILABLE} + * @param rsrq in dB [-34, 3], {@link CellInfo#UNAVAILABLE} + * @param rssnr in dB [-20, +30], {@link CellInfo#UNAVAILABLE} + * @param cqiTableIndex [1, 6], {@link CellInfo#UNAVAILABLE} + * @param cqi [0, 15], {@link CellInfo#UNAVAILABLE} + * @param timingAdvance [0, 1282], {@link CellInfo#UNAVAILABLE} * */ /** @hide */ @@ -151,12 +151,12 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P /** * Construct a cell signal strength * - * @param rssi in dBm [-113,-51], UNKNOWN - * @param rsrp in dBm [-140,-43], UNKNOWN - * @param rsrq in dB [-34, 3], UNKNOWN - * @param rssnr in dB [-20, +30], UNKNOWN - * @param cqi [0, 15], UNKNOWN - * @param timingAdvance [0, 1282], UNKNOWN + * @param rssi in dBm [-113,-51], {@link CellInfo#UNAVAILABLE} + * @param rsrp in dBm [-140,-43], {@link CellInfo#UNAVAILABLE} + * @param rsrq in dB [-34, 3], {@link CellInfo#UNAVAILABLE} + * @param rssnr in dB [-20, +30], {@link CellInfo#UNAVAILABLE} + * @param cqi [0, 15], {@link CellInfo#UNAVAILABLE} + * @param timingAdvance [0, 1282], {@link CellInfo#UNAVAILABLE} * */ /** @hide */ @@ -403,10 +403,11 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P } /** - * Get reference signal signal-to-noise ratio + * Get reference signal signal-to-noise ratio in dB + * Range: -20 dB to +30 dB. * * @return the RSSNR if available or - * {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable. + * {@link android.telephony.CellInfo#UNAVAILABLE} if unavailable. */ public int getRssnr() { return mRssnr; @@ -414,8 +415,10 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P /** * Get reference signal received power in dBm + * Range: -140 dBm to -43 dBm. * - * @return the RSRP of the measured cell. + * @return the RSRP of the measured cell or {@link CellInfo#UNAVAILABLE} if + * unavailable. */ public int getRsrp() { return mRsrp; diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java index 88efe1f6a4a7..56bf3039d209 100644 --- a/telephony/java/android/telephony/DataFailCause.java +++ b/telephony/java/android/telephony/DataFailCause.java @@ -1076,6 +1076,13 @@ public final class DataFailCause { */ public static final int SERVICE_TEMPORARILY_UNAVAILABLE = 0x10009; + /** + * The request is not supported by the vendor. + * + * @hide + */ + public static final int REQUEST_NOT_SUPPORTED = 0x1000A; + private static final Map<Integer, String> sFailCauseMap; static { sFailCauseMap = new HashMap<>(); diff --git a/telephony/java/android/telephony/ImsManager.java b/telephony/java/android/telephony/ImsManager.java index fc76f99cf074..6b9871c3f5d7 100644 --- a/telephony/java/android/telephony/ImsManager.java +++ b/telephony/java/android/telephony/ImsManager.java @@ -160,6 +160,26 @@ public class ImsManager { return new SipDelegateManager(mContext, subscriptionId, sRcsCache, sTelephonyCache); } + + /** + * Create an instance of {@link ProvisioningManager} for the subscription id specified. + * <p> + * Provides a ProvisioningManager instance to carrier apps to update carrier provisioning + * information, as well as provides a callback so that apps can listen for changes + * in MMTEL/RCS provisioning + * @param subscriptionId The ID of the subscription that this ProvisioningManager will use. + * @throws IllegalArgumentException if the subscription is invalid. + * @return a ProvisioningManager instance with the specific subscription ID. + */ + @NonNull + public ProvisioningManager getProvisioningManager(int subscriptionId) { + if (!SubscriptionManager.isValidSubscriptionId(subscriptionId)) { + throw new IllegalArgumentException("Invalid subscription ID: " + subscriptionId); + } + + return new ProvisioningManager(subscriptionId); + } + private static IImsRcsController getIImsRcsControllerInterface() { return IImsRcsController.Stub.asInterface( TelephonyFrameworkInitializer diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index 846e6f3c5800..9fd2ae46b0bc 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -19,6 +19,7 @@ package android.telephony; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; @@ -767,6 +768,10 @@ public class ServiceState implements Parcelable { * * @return long name of operator, null if unregistered or unknown */ + @RequiresPermission(anyOf = { + android.Manifest.permission.ACCESS_FINE_LOCATION, + android.Manifest.permission.ACCESS_COARSE_LOCATION + }) public String getOperatorAlphaLong() { return mOperatorAlphaLong; } @@ -782,6 +787,10 @@ public class ServiceState implements Parcelable { * @return long name of operator * @hide */ + @RequiresPermission(anyOf = { + android.Manifest.permission.ACCESS_FINE_LOCATION, + android.Manifest.permission.ACCESS_COARSE_LOCATION + }) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link #getOperatorAlphaLong} instead.") public String getVoiceOperatorAlphaLong() { @@ -800,6 +809,10 @@ public class ServiceState implements Parcelable { * * @return short name of operator, null if unregistered or unknown */ + @RequiresPermission(anyOf = { + android.Manifest.permission.ACCESS_FINE_LOCATION, + android.Manifest.permission.ACCESS_COARSE_LOCATION + }) public String getOperatorAlphaShort() { return mOperatorAlphaShort; } @@ -815,6 +828,10 @@ public class ServiceState implements Parcelable { * @return short name of operator, null if unregistered or unknown * @hide */ + @RequiresPermission(anyOf = { + android.Manifest.permission.ACCESS_FINE_LOCATION, + android.Manifest.permission.ACCESS_COARSE_LOCATION + }) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link #getOperatorAlphaShort} instead.") public String getVoiceOperatorAlphaShort() { @@ -832,6 +849,10 @@ public class ServiceState implements Parcelable { * @return short name of operator, null if unregistered or unknown * @hide */ + @RequiresPermission(anyOf = { + android.Manifest.permission.ACCESS_FINE_LOCATION, + android.Manifest.permission.ACCESS_COARSE_LOCATION + }) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link #getOperatorAlphaShort} instead.") public String getDataOperatorAlphaShort() { @@ -853,6 +874,10 @@ public class ServiceState implements Parcelable { * @return name of operator, null if unregistered or unknown * @hide */ + @RequiresPermission(anyOf = { + android.Manifest.permission.ACCESS_FINE_LOCATION, + android.Manifest.permission.ACCESS_COARSE_LOCATION + }) public String getOperatorAlpha() { if (TextUtils.isEmpty(mOperatorAlphaLong)) { return mOperatorAlphaShort; @@ -878,6 +903,10 @@ public class ServiceState implements Parcelable { * The country code can be decoded using * {@link com.android.internal.telephony.MccTable#countryCodeForMcc(int)}. */ + @RequiresPermission(anyOf = { + android.Manifest.permission.ACCESS_FINE_LOCATION, + android.Manifest.permission.ACCESS_COARSE_LOCATION + }) public String getOperatorNumeric() { return mOperatorNumeric; } @@ -893,6 +922,10 @@ public class ServiceState implements Parcelable { * @return numeric format of operator, null if unregistered or unknown * @hide */ + @RequiresPermission(anyOf = { + android.Manifest.permission.ACCESS_FINE_LOCATION, + android.Manifest.permission.ACCESS_COARSE_LOCATION + }) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public String getVoiceOperatorNumeric() { return mOperatorNumeric; @@ -909,6 +942,10 @@ public class ServiceState implements Parcelable { * @return numeric format of operator, null if unregistered or unknown * @hide */ + @RequiresPermission(anyOf = { + android.Manifest.permission.ACCESS_FINE_LOCATION, + android.Manifest.permission.ACCESS_COARSE_LOCATION + }) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link #getOperatorNumeric} instead.") public String getDataOperatorNumeric() { @@ -1758,8 +1795,17 @@ public class ServiceState implements Parcelable { /** * Get the CDMA NID (Network Identification Number), a number uniquely identifying a network * within a wireless system. (Defined in 3GPP2 C.S0023 3.4.8) + * + * <p>Require at least {@link android.Manifest.permission#ACCESS_FINE_LOCATION} or + * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}. Otherwise return + * {@link #UNKNOWN_ID}. + * * @return The CDMA NID or {@link #UNKNOWN_ID} if not available. */ + @RequiresPermission(anyOf = { + android.Manifest.permission.ACCESS_FINE_LOCATION, + android.Manifest.permission.ACCESS_COARSE_LOCATION + }) public int getCdmaNetworkId() { return this.mNetworkId; } @@ -1767,8 +1813,17 @@ public class ServiceState implements Parcelable { /** * Get the CDMA SID (System Identification Number), a number uniquely identifying a wireless * system. (Defined in 3GPP2 C.S0023 3.4.8) + * + * <p>Require at least {@link android.Manifest.permission#ACCESS_FINE_LOCATION} or + * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}. Otherwise return + * {@link #UNKNOWN_ID}. + * * @return The CDMA SID or {@link #UNKNOWN_ID} if not available. */ + @RequiresPermission(anyOf = { + android.Manifest.permission.ACCESS_FINE_LOCATION, + android.Manifest.permission.ACCESS_COARSE_LOCATION + }) public int getCdmaSystemId() { return this.mSystemId; } @@ -2069,6 +2124,8 @@ public class ServiceState implements Parcelable { state.mOperatorAlphaLong = null; state.mOperatorAlphaShort = null; state.mOperatorNumeric = null; + state.mSystemId = UNKNOWN_ID; + state.mNetworkId = UNKNOWN_ID; return state; } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index aab6daa20279..390ffc751498 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -8765,7 +8765,8 @@ public class TelephonyManager { * @param allowedNetworkTypes The bitmask of allowed network types. * @return true on success; false on any failure. * @hide - * @deprecated Use {@link #setAllowedNetworkTypesForReason} instead. + * @deprecated Use {@link #setAllowedNetworkTypesForReason} instead with reason + * {@link #ALLOWED_NETWORK_TYPES_REASON_CARRIER}. */ @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @@ -8799,10 +8800,7 @@ public class TelephonyManager { /** * To indicate allowed network type change is requested by user. - * - * @hide */ - @SystemApi public static final int ALLOWED_NETWORK_TYPES_REASON_USER = 0; /** @@ -8821,10 +8819,7 @@ public class TelephonyManager { * Carrier configuration won't affect the settings configured through * other reasons and will result in allowing network types that are in both * configurations (i.e intersection of both sets). - * - * @hide */ - @SystemApi public static final int ALLOWED_NETWORK_TYPES_REASON_CARRIER = 2; /** @@ -8838,35 +8833,23 @@ public class TelephonyManager { /** * Set the allowed network types of the device and provide the reason triggering the allowed * network change. + * <p>Requires permission: android.Manifest.MODIFY_PHONE_STATE or + * that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). + * * This can be called for following reasons * <ol> * <li>Allowed network types control by USER {@link #ALLOWED_NETWORK_TYPES_REASON_USER} - * <li>Allowed network types control by power manager - * {@link #ALLOWED_NETWORK_TYPES_REASON_POWER} * <li>Allowed network types control by carrier {@link #ALLOWED_NETWORK_TYPES_REASON_CARRIER} - * <li>Allowed network types control by the user-controlled "Allow 2G" toggle - * {@link #ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G} * </ol> * This API will result in allowing an intersection of allowed network types for all reasons, * including the configuration done through other reasons. * - * The functionality of this API with the parameter - * {@link #ALLOWED_NETWORK_TYPES_REASON_CARRIER} is the same as the API - * {@link TelephonyManager#setAllowedNetworkTypes}. Use this API instead of - * {@link TelephonyManager#setAllowedNetworkTypes}. - * <p> - * If {@link android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported} - * ({@link TelephonyManager#CAPABILITY_USES_ALLOWED_NETWORK_TYPES_BITMASK}) returns true, then - * setAllowedNetworkTypesBitmap is used on the radio interface. Otherwise, - * setPreferredNetworkTypesBitmap is used instead. - * * @param reason the reason the allowed network type change is taking place - * @param allowedNetworkTypes The bitmask of allowed network types. + * @param allowedNetworkTypes The bitmask of allowed network type * @throws IllegalStateException if the Telephony process is not currently available. * @throws IllegalArgumentException if invalid AllowedNetworkTypesReason is passed. - * @hide + * @throws SecurityException if the caller does not have the required privileges */ - @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @RequiresFeature( enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported", @@ -8896,18 +8879,19 @@ public class TelephonyManager { * * {@link #getAllowedNetworkTypesForReason} returns allowed network type for a * specific reason. + * <p>Requires permission: android.Manifest.READ_PRIVILEGED_PHONE_STATE or + * that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param reason the reason the allowed network type change is taking place * @return the allowed network type bitmask * @throws IllegalStateException if the Telephony process is not currently available. * @throws IllegalArgumentException if invalid AllowedNetworkTypesReason is passed. - * @hide + * @throws SecurityException if the caller does not have the required permission/privileges */ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @RequiresFeature( enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported", value = TelephonyManager.CAPABILITY_USES_ALLOWED_NETWORK_TYPES_BITMASK) - @SystemApi public @NetworkTypeBitMask long getAllowedNetworkTypesForReason( @AllowedNetworkTypesReason int reason) { if (!isValidAllowedNetworkTypesReason(reason)) { @@ -12127,12 +12111,15 @@ public class TelephonyManager { if (carriers == null || !SubscriptionManager.isValidPhoneId(slotIndex)) { return -1; } - // Execute the method setCarrierRestrictionRules with an empty excluded list and - // indicating priority for the allowed list. + // Execute the method setCarrierRestrictionRules with an empty excluded list. + // If the allowed list is empty, it means that all carriers are allowed (default allowed), + // otherwise it means that only specified carriers are allowed (default not allowed). CarrierRestrictionRules carrierRestrictionRules = CarrierRestrictionRules.newBuilder() .setAllowedCarriers(carriers) .setDefaultCarrierRestriction( - CarrierRestrictionRules.CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED) + carriers.isEmpty() + ? CarrierRestrictionRules.CARRIER_RESTRICTION_DEFAULT_ALLOWED + : CarrierRestrictionRules.CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED) .build(); int result = setCarrierRestrictionRules(carrierRestrictionRules); @@ -13026,127 +13013,88 @@ public class TelephonyManager { // 2G /** * network type bitmask unknown. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_UNKNOWN = 0L; /** * network type bitmask indicating the support of radio tech GSM. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_GSM = (1 << (NETWORK_TYPE_GSM -1)); /** * network type bitmask indicating the support of radio tech GPRS. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_GPRS = (1 << (NETWORK_TYPE_GPRS -1)); /** * network type bitmask indicating the support of radio tech EDGE. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_EDGE = (1 << (NETWORK_TYPE_EDGE -1)); /** * network type bitmask indicating the support of radio tech CDMA(IS95A/IS95B). - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_CDMA = (1 << (NETWORK_TYPE_CDMA -1)); /** * network type bitmask indicating the support of radio tech 1xRTT. - * @hide */ - @SystemApi + @SuppressLint("AllUpper") public static final long NETWORK_TYPE_BITMASK_1xRTT = (1 << (NETWORK_TYPE_1xRTT - 1)); // 3G /** * network type bitmask indicating the support of radio tech EVDO 0. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_EVDO_0 = (1 << (NETWORK_TYPE_EVDO_0 -1)); /** * network type bitmask indicating the support of radio tech EVDO A. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_EVDO_A = (1 << (NETWORK_TYPE_EVDO_A - 1)); /** * network type bitmask indicating the support of radio tech EVDO B. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_EVDO_B = (1 << (NETWORK_TYPE_EVDO_B -1)); /** * network type bitmask indicating the support of radio tech EHRPD. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_EHRPD = (1 << (NETWORK_TYPE_EHRPD -1)); /** * network type bitmask indicating the support of radio tech HSUPA. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_HSUPA = (1 << (NETWORK_TYPE_HSUPA -1)); /** * network type bitmask indicating the support of radio tech HSDPA. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_HSDPA = (1 << (NETWORK_TYPE_HSDPA -1)); /** * network type bitmask indicating the support of radio tech HSPA. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_HSPA = (1 << (NETWORK_TYPE_HSPA -1)); /** * network type bitmask indicating the support of radio tech HSPAP. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_HSPAP = (1 << (NETWORK_TYPE_HSPAP -1)); /** * network type bitmask indicating the support of radio tech UMTS. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_UMTS = (1 << (NETWORK_TYPE_UMTS -1)); /** * network type bitmask indicating the support of radio tech TD_SCDMA. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_TD_SCDMA = (1 << (NETWORK_TYPE_TD_SCDMA -1)); // 4G /** * network type bitmask indicating the support of radio tech LTE. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_LTE = (1 << (NETWORK_TYPE_LTE -1)); /** * network type bitmask indicating the support of radio tech LTE CA (carrier aggregation). - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_LTE_CA = (1 << (NETWORK_TYPE_LTE_CA -1)); /** * network type bitmask indicating the support of radio tech NR(New Radio) 5G. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_NR = (1 << (NETWORK_TYPE_NR -1)); /** * network type bitmask indicating the support of radio tech IWLAN. - * @hide */ - @SystemApi public static final long NETWORK_TYPE_BITMASK_IWLAN = (1 << (NETWORK_TYPE_IWLAN -1)); /** @hide */ @@ -13201,12 +13149,11 @@ public class TelephonyManager { /** * @return Modem supported radio access family bitmask * - * <p>Requires permission: {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} or + * <p>Requires permission: android.Manifest.READ_PRIVILEGED_PHONE_STATE or * that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). - * @hide + * + * @throws SecurityException if the caller does not have the required permission */ - @SystemApi - @TestApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public @NetworkTypeBitMask long getSupportedRadioAccessFamily() { try { diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index d6dce25d931f..8c02ffe12363 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -2158,8 +2158,7 @@ public class ApnSetting implements Parcelable { | TYPE_FOTA | TYPE_IMS | TYPE_CBS | TYPE_IA | TYPE_EMERGENCY | TYPE_MCX | TYPE_XCAP | TYPE_VSIM | TYPE_BIP | TYPE_ENTERPRISE)) == 0 || TextUtils.isEmpty(mApnName) || TextUtils.isEmpty(mEntryName)) { - throw new IllegalArgumentException("mApName=" + mApnName + ", mEntryName=" - + mEntryName + ", mApnTypeBitmask=" + mApnTypeBitmask); + return null; } return new ApnSetting(this); } diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java index 93903d2658cd..c1d16a9aaea7 100644 --- a/telephony/java/android/telephony/data/DataProfile.java +++ b/telephony/java/android/telephony/data/DataProfile.java @@ -18,13 +18,16 @@ package android.telephony.data; import static android.telephony.data.ApnSetting.ProtocolType; +import android.annotation.ElapsedRealtimeLong; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.net.NetworkCapabilities; import android.os.Parcel; import android.os.Parcelable; import android.telephony.Annotation.ApnType; +import android.telephony.Annotation.NetCapability; import android.telephony.TelephonyManager; import android.telephony.TelephonyManager.NetworkTypeBitMask; import android.telephony.data.ApnSetting.AuthType; @@ -66,7 +69,13 @@ public final class DataProfile implements Parcelable { private final @Nullable TrafficDescriptor mTrafficDescriptor; - private final boolean mPreferred; + private boolean mPreferred; + + /** + * The last timestamp of this data profile being used for data network setup. Never add this + * to {@link #equals(Object)} and {@link #hashCode()}. + */ + private @ElapsedRealtimeLong long mSetupTimestamp; private DataProfile(@NonNull Builder builder) { mApnSetting = builder.mApnSetting; @@ -99,6 +108,7 @@ public final class DataProfile implements Parcelable { mApnSetting = source.readParcelable(ApnSetting.class.getClassLoader()); mTrafficDescriptor = source.readParcelable(TrafficDescriptor.class.getClassLoader()); mPreferred = source.readBoolean(); + mSetupTimestamp = source.readLong(); } /** @@ -291,6 +301,16 @@ public final class DataProfile implements Parcelable { } /** + * Set the preferred flag for the data profile. + * + * @param preferred {@code true} if this data profile is preferred for internet. + * @hide + */ + public void setPreferred(boolean preferred) { + mPreferred = preferred; + } + + /** * @return {@code true} if this data profile was used to bring up the last default * (i.e internet) data connection successfully, or the one chosen by the user in Settings' * APN editor. For one carrier there can be only one profiled preferred. @@ -315,6 +335,94 @@ public final class DataProfile implements Parcelable { return mTrafficDescriptor; } + /** + * Check if this data profile can satisfy certain network capabilities + * + * @param networkCapabilities The network capabilities. Note that the non-APN-type capabilities + * will be ignored. + * + * @return {@code true} if this data profile can satisfy the given network capabilities. + * @hide + */ + public boolean canSatisfy(@NonNull @NetCapability int[] networkCapabilities) { + if (mApnSetting != null) { + for (int netCap : networkCapabilities) { + if (!canSatisfy(netCap)) { + return false; + } + } + return true; + } + return false; + } + + /** + * Check if this data profile can satisfy a certain network capability. + * + * @param networkCapability The network capability. Note that the non-APN-type capability + * will always be satisfied. + * @return {@code true} if this data profile can satisfy the given network capability. + * @hide + */ + public boolean canSatisfy(@NetCapability int networkCapability) { + return mApnSetting != null && mApnSetting.canHandleType( + networkCapabilityToApnType(networkCapability)); + } + + /** + * Convert network capability into APN type. + * + * @param networkCapability Network capability. + * @return APN type. + * @hide + */ + private static @ApnType int networkCapabilityToApnType(@NetCapability int networkCapability) { + switch (networkCapability) { + case NetworkCapabilities.NET_CAPABILITY_MMS: + return ApnSetting.TYPE_MMS; + case NetworkCapabilities.NET_CAPABILITY_SUPL: + return ApnSetting.TYPE_SUPL; + case NetworkCapabilities.NET_CAPABILITY_DUN: + return ApnSetting.TYPE_DUN; + case NetworkCapabilities.NET_CAPABILITY_FOTA: + return ApnSetting.TYPE_FOTA; + case NetworkCapabilities.NET_CAPABILITY_IMS: + return ApnSetting.TYPE_IMS; + case NetworkCapabilities.NET_CAPABILITY_CBS: + return ApnSetting.TYPE_CBS; + case NetworkCapabilities.NET_CAPABILITY_XCAP: + return ApnSetting.TYPE_XCAP; + case NetworkCapabilities.NET_CAPABILITY_EIMS: + return ApnSetting.TYPE_EMERGENCY; + case NetworkCapabilities.NET_CAPABILITY_INTERNET: + return ApnSetting.TYPE_DEFAULT; + case NetworkCapabilities.NET_CAPABILITY_MCX: + return ApnSetting.TYPE_MCX; + case NetworkCapabilities.NET_CAPABILITY_IA: + return ApnSetting.TYPE_IA; + default: + return ApnSetting.TYPE_NONE; + } + } + + /** + * Set the timestamp of this data profile being used for data network setup. + * + * @hide + */ + public void setLastSetupTimestamp(@ElapsedRealtimeLong long timestamp) { + mSetupTimestamp = timestamp; + } + + /** + * @return the timestamp of this data profile being used for data network setup. + * + * @hide + */ + public @ElapsedRealtimeLong long getLastSetupTimestamp() { + return mSetupTimestamp; + } + @Override public int describeContents() { return 0; @@ -323,8 +431,8 @@ public final class DataProfile implements Parcelable { @NonNull @Override public String toString() { - return "DataProfile=" + mApnSetting + ", " + mTrafficDescriptor + ", preferred=" - + mPreferred; + return "[DataProfile=" + mApnSetting + ", " + mTrafficDescriptor + ", preferred=" + + mPreferred + "]"; } @Override @@ -333,6 +441,7 @@ public final class DataProfile implements Parcelable { dest.writeParcelable(mApnSetting, flags); dest.writeParcelable(mTrafficDescriptor, flags); dest.writeBoolean(mPreferred); + dest.writeLong(mSetupTimestamp); } public static final @android.annotation.NonNull Parcelable.Creator<DataProfile> CREATOR = diff --git a/telephony/java/android/telephony/data/DataServiceCallback.java b/telephony/java/android/telephony/data/DataServiceCallback.java index 051d6c5d5ec0..13d8c7b9c915 100644 --- a/telephony/java/android/telephony/data/DataServiceCallback.java +++ b/telephony/java/android/telephony/data/DataServiceCallback.java @@ -259,9 +259,10 @@ public class DataServiceCallback { } /** - * Unthrottles the APN on the current transport. There is no matching "APN throttle" method. - * Instead, the APN is throttled when {@link IDataService#setupDataCall} fails within - * the time specified by {@link DataCallResponse#getRetryDurationMillis}. + * Unthrottles the APN on the current transport. + * The APN is throttled when {@link IDataService#setupDataCall} fails within + * the time specified by {@link DataCallResponse#getRetryDurationMillis} and will remain + * throttled until this method is called. * <p/> * see: {@link DataCallResponse#getRetryDurationMillis} * @@ -282,9 +283,9 @@ public class DataServiceCallback { /** * Unthrottles the DataProfile on the current transport. - * There is no matching "DataProfile throttle" method. - * Instead, the DataProfile is throttled when {@link IDataService#setupDataCall} fails within - * the time specified by {@link DataCallResponse#getRetryDurationMillis}. + * The DataProfile is throttled when {@link IDataService#setupDataCall} fails within + * the time specified by {@link DataCallResponse#getRetryDurationMillis} and will remain + * throttled until this method is called. * <p/> * see: {@link DataCallResponse#getRetryDurationMillis} * diff --git a/telephony/java/android/telephony/ims/ImsCallSession.java b/telephony/java/android/telephony/ims/ImsCallSession.java index dfe5e6c93f53..d65286f26447 100755 --- a/telephony/java/android/telephony/ims/ImsCallSession.java +++ b/telephony/java/android/telephony/ims/ImsCallSession.java @@ -27,10 +27,12 @@ import android.util.Log; import com.android.ims.internal.IImsCallSession; import com.android.ims.internal.IImsVideoCallProvider; +import com.android.internal.telephony.util.TelephonyUtils; import java.util.ArrayList; import java.util.List; import java.util.Set; +import java.util.concurrent.Executor; /** * Provides the call initiation/termination, and media exchange between two IMS endpoints. @@ -522,6 +524,7 @@ public class ImsCallSession { private final IImsCallSession miSession; private boolean mClosed = false; private Listener mListener; + private Executor mListenerExecutor = Runnable::run; /** @hide */ public ImsCallSession(IImsCallSession iSession) { @@ -538,9 +541,9 @@ public class ImsCallSession { } /** @hide */ - public ImsCallSession(IImsCallSession iSession, Listener listener) { + public ImsCallSession(IImsCallSession iSession, Listener listener, Executor executor) { this(iSession); - setListener(listener); + setListener(listener, executor); } /** @@ -738,10 +741,14 @@ public class ImsCallSession { * override the previous listener. * * @param listener to listen to the session events of this object + * @param executor an Executor that will execute callbacks * @hide */ - public void setListener(Listener listener) { + public void setListener(Listener listener, Executor executor) { mListener = listener; + if (executor != null) { + mListenerExecutor = executor; + } } /** @@ -1205,44 +1212,56 @@ public class ImsCallSession { */ @Override public void callSessionInitiating(ImsCallProfile profile) { - if (mListener != null) { - mListener.callSessionInitiating(ImsCallSession.this, profile); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionInitiating(ImsCallSession.this, profile); + } + }, mListenerExecutor); } @Override public void callSessionProgressing(ImsStreamMediaProfile profile) { - if (mListener != null) { - mListener.callSessionProgressing(ImsCallSession.this, profile); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionProgressing(ImsCallSession.this, profile); + } + }, mListenerExecutor); } @Override public void callSessionInitiated(ImsCallProfile profile) { - if (mListener != null) { - mListener.callSessionStarted(ImsCallSession.this, profile); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionStarted(ImsCallSession.this, profile); + } + }, mListenerExecutor); } @Override public void callSessionInitiatingFailed(ImsReasonInfo reasonInfo) { - if (mListener != null) { - mListener.callSessionStartFailed(ImsCallSession.this, reasonInfo); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionStartFailed(ImsCallSession.this, reasonInfo); + } + }, mListenerExecutor); } @Override public void callSessionInitiatedFailed(ImsReasonInfo reasonInfo) { - if (mListener != null) { - mListener.callSessionStartFailed(ImsCallSession.this, reasonInfo); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionStartFailed(ImsCallSession.this, reasonInfo); + } + }, mListenerExecutor); } @Override public void callSessionTerminated(ImsReasonInfo reasonInfo) { - if (mListener != null) { - mListener.callSessionTerminated(ImsCallSession.this, reasonInfo); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionTerminated(ImsCallSession.this, reasonInfo); + } + }, mListenerExecutor); } /** @@ -1250,44 +1269,56 @@ public class ImsCallSession { */ @Override public void callSessionHeld(ImsCallProfile profile) { - if (mListener != null) { - mListener.callSessionHeld(ImsCallSession.this, profile); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionHeld(ImsCallSession.this, profile); + } + }, mListenerExecutor); } @Override public void callSessionHoldFailed(ImsReasonInfo reasonInfo) { - if (mListener != null) { - mListener.callSessionHoldFailed(ImsCallSession.this, reasonInfo); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionHoldFailed(ImsCallSession.this, reasonInfo); + } + }, mListenerExecutor); } @Override public void callSessionHoldReceived(ImsCallProfile profile) { - if (mListener != null) { - mListener.callSessionHoldReceived(ImsCallSession.this, profile); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionHoldReceived(ImsCallSession.this, profile); + } + }, mListenerExecutor); } @Override public void callSessionResumed(ImsCallProfile profile) { - if (mListener != null) { - mListener.callSessionResumed(ImsCallSession.this, profile); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionResumed(ImsCallSession.this, profile); + } + }, mListenerExecutor); } @Override public void callSessionResumeFailed(ImsReasonInfo reasonInfo) { - if (mListener != null) { - mListener.callSessionResumeFailed(ImsCallSession.this, reasonInfo); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionResumeFailed(ImsCallSession.this, reasonInfo); + } + }, mListenerExecutor); } @Override public void callSessionResumeReceived(ImsCallProfile profile) { - if (mListener != null) { - mListener.callSessionResumeReceived(ImsCallSession.this, profile); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionResumeReceived(ImsCallSession.this, profile); + } + }, mListenerExecutor); } /** @@ -1310,15 +1341,17 @@ public class ImsCallSession { */ @Override public void callSessionMergeComplete(IImsCallSession newSession) { - if (mListener != null) { - if (newSession != null) { - // New session created after conference - mListener.callSessionMergeComplete(new ImsCallSession(newSession)); - } else { - // Session already exists. Hence no need to pass - mListener.callSessionMergeComplete(null); - } - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + if (newSession != null) { + // New session created after conference + mListener.callSessionMergeComplete(new ImsCallSession(newSession)); + } else { + // Session already exists. Hence no need to pass + mListener.callSessionMergeComplete(null); + } + } + }, mListenerExecutor); } /** @@ -1328,9 +1361,11 @@ public class ImsCallSession { */ @Override public void callSessionMergeFailed(ImsReasonInfo reasonInfo) { - if (mListener != null) { - mListener.callSessionMergeFailed(ImsCallSession.this, reasonInfo); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionMergeFailed(ImsCallSession.this, reasonInfo); + } + }, mListenerExecutor); } /** @@ -1338,23 +1373,29 @@ public class ImsCallSession { */ @Override public void callSessionUpdated(ImsCallProfile profile) { - if (mListener != null) { - mListener.callSessionUpdated(ImsCallSession.this, profile); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionUpdated(ImsCallSession.this, profile); + } + }, mListenerExecutor); } @Override public void callSessionUpdateFailed(ImsReasonInfo reasonInfo) { - if (mListener != null) { - mListener.callSessionUpdateFailed(ImsCallSession.this, reasonInfo); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionUpdateFailed(ImsCallSession.this, reasonInfo); + } + }, mListenerExecutor); } @Override public void callSessionUpdateReceived(ImsCallProfile profile) { - if (mListener != null) { - mListener.callSessionUpdateReceived(ImsCallSession.this, profile); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionUpdateReceived(ImsCallSession.this, profile); + } + }, mListenerExecutor); } /** @@ -1363,26 +1404,33 @@ public class ImsCallSession { @Override public void callSessionConferenceExtended(IImsCallSession newSession, ImsCallProfile profile) { - if (mListener != null) { - mListener.callSessionConferenceExtended(ImsCallSession.this, - new ImsCallSession(newSession), profile); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionConferenceExtended(ImsCallSession.this, + new ImsCallSession(newSession), profile); + } + }, mListenerExecutor); } @Override public void callSessionConferenceExtendFailed(ImsReasonInfo reasonInfo) { - if (mListener != null) { - mListener.callSessionConferenceExtendFailed(ImsCallSession.this, reasonInfo); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionConferenceExtendFailed( + ImsCallSession.this, reasonInfo); + } + }, mListenerExecutor); } @Override public void callSessionConferenceExtendReceived(IImsCallSession newSession, ImsCallProfile profile) { - if (mListener != null) { - mListener.callSessionConferenceExtendReceived(ImsCallSession.this, - new ImsCallSession(newSession), profile); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionConferenceExtendReceived(ImsCallSession.this, + new ImsCallSession(newSession), profile); + } + }, mListenerExecutor); } /** @@ -1391,32 +1439,41 @@ public class ImsCallSession { */ @Override public void callSessionInviteParticipantsRequestDelivered() { - if (mListener != null) { - mListener.callSessionInviteParticipantsRequestDelivered(ImsCallSession.this); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionInviteParticipantsRequestDelivered( + ImsCallSession.this); + } + }, mListenerExecutor); } @Override public void callSessionInviteParticipantsRequestFailed(ImsReasonInfo reasonInfo) { - if (mListener != null) { - mListener.callSessionInviteParticipantsRequestFailed(ImsCallSession.this, - reasonInfo); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionInviteParticipantsRequestFailed(ImsCallSession.this, + reasonInfo); + } + }, mListenerExecutor); } @Override public void callSessionRemoveParticipantsRequestDelivered() { - if (mListener != null) { - mListener.callSessionRemoveParticipantsRequestDelivered(ImsCallSession.this); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionRemoveParticipantsRequestDelivered(ImsCallSession.this); + } + }, mListenerExecutor); } @Override public void callSessionRemoveParticipantsRequestFailed(ImsReasonInfo reasonInfo) { - if (mListener != null) { - mListener.callSessionRemoveParticipantsRequestFailed(ImsCallSession.this, - reasonInfo); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionRemoveParticipantsRequestFailed(ImsCallSession.this, + reasonInfo); + } + }, mListenerExecutor); } /** @@ -1424,9 +1481,11 @@ public class ImsCallSession { */ @Override public void callSessionConferenceStateUpdated(ImsConferenceState state) { - if (mListener != null) { - mListener.callSessionConferenceStateUpdated(ImsCallSession.this, state); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionConferenceStateUpdated(ImsCallSession.this, state); + } + }, mListenerExecutor); } /** @@ -1434,9 +1493,12 @@ public class ImsCallSession { */ @Override public void callSessionUssdMessageReceived(int mode, String ussdMessage) { - if (mListener != null) { - mListener.callSessionUssdMessageReceived(ImsCallSession.this, mode, ussdMessage); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionUssdMessageReceived(ImsCallSession.this, mode, + ussdMessage); + } + }, mListenerExecutor); } /** @@ -1452,10 +1514,12 @@ public class ImsCallSession { */ @Override public void callSessionMayHandover(int srcNetworkType, int targetNetworkType) { - if (mListener != null) { - mListener.callSessionMayHandover(ImsCallSession.this, srcNetworkType, - targetNetworkType); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionMayHandover(ImsCallSession.this, srcNetworkType, + targetNetworkType); + } + }, mListenerExecutor); } /** @@ -1464,10 +1528,12 @@ public class ImsCallSession { @Override public void callSessionHandover(int srcNetworkType, int targetNetworkType, ImsReasonInfo reasonInfo) { - if (mListener != null) { - mListener.callSessionHandover(ImsCallSession.this, srcNetworkType, - targetNetworkType, reasonInfo); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionHandover(ImsCallSession.this, srcNetworkType, + targetNetworkType, reasonInfo); + } + }, mListenerExecutor); } /** @@ -1476,10 +1542,12 @@ public class ImsCallSession { @Override public void callSessionHandoverFailed(int srcNetworkType, int targetNetworkType, ImsReasonInfo reasonInfo) { - if (mListener != null) { - mListener.callSessionHandoverFailed(ImsCallSession.this, srcNetworkType, - targetNetworkType, reasonInfo); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionHandoverFailed(ImsCallSession.this, srcNetworkType, + targetNetworkType, reasonInfo); + } + }, mListenerExecutor); } /** @@ -1487,9 +1555,11 @@ public class ImsCallSession { */ @Override public void callSessionTtyModeReceived(int mode) { - if (mListener != null) { - mListener.callSessionTtyModeReceived(ImsCallSession.this, mode); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionTtyModeReceived(ImsCallSession.this, mode); + } + }, mListenerExecutor); } /** @@ -1499,16 +1569,22 @@ public class ImsCallSession { * otherwise. */ public void callSessionMultipartyStateChanged(boolean isMultiParty) { - if (mListener != null) { - mListener.callSessionMultipartyStateChanged(ImsCallSession.this, isMultiParty); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionMultipartyStateChanged(ImsCallSession.this, + isMultiParty); + } + }, mListenerExecutor); } @Override public void callSessionSuppServiceReceived(ImsSuppServiceNotification suppServiceInfo ) { - if (mListener != null) { - mListener.callSessionSuppServiceReceived(ImsCallSession.this, suppServiceInfo); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionSuppServiceReceived(ImsCallSession.this, + suppServiceInfo); + } + }, mListenerExecutor); } /** @@ -1516,9 +1592,12 @@ public class ImsCallSession { */ @Override public void callSessionRttModifyRequestReceived(ImsCallProfile callProfile) { - if (mListener != null) { - mListener.callSessionRttModifyRequestReceived(ImsCallSession.this, callProfile); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionRttModifyRequestReceived(ImsCallSession.this, + callProfile); + } + }, mListenerExecutor); } /** @@ -1526,9 +1605,11 @@ public class ImsCallSession { */ @Override public void callSessionRttModifyResponseReceived(int status) { - if (mListener != null) { - mListener.callSessionRttModifyResponseReceived(status); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionRttModifyResponseReceived(status); + } + }, mListenerExecutor); } /** @@ -1536,9 +1617,11 @@ public class ImsCallSession { */ @Override public void callSessionRttMessageReceived(String rttMessage) { - if (mListener != null) { - mListener.callSessionRttMessageReceived(rttMessage); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionRttMessageReceived(rttMessage); + } + }, mListenerExecutor); } /** @@ -1546,23 +1629,29 @@ public class ImsCallSession { */ @Override public void callSessionRttAudioIndicatorChanged(ImsStreamMediaProfile profile) { - if (mListener != null) { - mListener.callSessionRttAudioIndicatorChanged(profile); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionRttAudioIndicatorChanged(profile); + } + }, mListenerExecutor); } @Override public void callSessionTransferred() { - if (mListener != null) { - mListener.callSessionTransferred(ImsCallSession.this); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionTransferred(ImsCallSession.this); + } + }, mListenerExecutor); } @Override public void callSessionTransferFailed(@Nullable ImsReasonInfo reasonInfo) { - if (mListener != null) { - mListener.callSessionTransferFailed(ImsCallSession.this, reasonInfo); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionTransferFailed(ImsCallSession.this, reasonInfo); + } + }, mListenerExecutor); } /** @@ -1571,9 +1660,11 @@ public class ImsCallSession { */ @Override public void callSessionDtmfReceived(char dtmf) { - if (mListener != null) { - mListener.callSessionDtmfReceived(dtmf); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionDtmfReceived(dtmf); + } + }, mListenerExecutor); } /** @@ -1581,9 +1672,11 @@ public class ImsCallSession { */ @Override public void callQualityChanged(CallQuality callQuality) { - if (mListener != null) { - mListener.callQualityChanged(callQuality); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callQualityChanged(callQuality); + } + }, mListenerExecutor); } /** @@ -1593,10 +1686,12 @@ public class ImsCallSession { @Override public void callSessionRtpHeaderExtensionsReceived( @NonNull List<RtpHeaderExtension> extensions) { - if (mListener != null) { - mListener.callSessionRtpHeaderExtensionsReceived( - new ArraySet<RtpHeaderExtension>(extensions)); - } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionRtpHeaderExtensionsReceived( + new ArraySet<RtpHeaderExtension>(extensions)); + } + }, mListenerExecutor); } } diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java index 9ab5aeb9c34c..be233b82c426 100644 --- a/telephony/java/android/telephony/ims/ImsService.java +++ b/telephony/java/android/telephony/ims/ImsService.java @@ -17,6 +17,7 @@ package android.telephony.ims; import android.annotation.LongDef; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.annotation.SystemApi; @@ -41,14 +42,22 @@ import android.telephony.ims.stub.ImsRegistrationImplBase; import android.telephony.ims.stub.SipTransportImplBase; import android.util.Log; import android.util.SparseArray; +import android.util.SparseBooleanArray; import com.android.ims.internal.IImsFeatureStatusCallback; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.util.TelephonyUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.function.Supplier; /** * Main ImsService implementation, which binds via the Telephony ImsResolver. Services that extend @@ -172,8 +181,28 @@ public class ImsService extends Service { // call ImsFeature#onFeatureRemoved. private final SparseArray<SparseArray<ImsFeature>> mFeaturesBySlot = new SparseArray<>(); + // A map of slot id -> boolean array, where each entry in the boolean array corresponds to an + // ImsFeature that was created for a slot id and not a sub id for backwards compatibility + // purposes. + private final SparseArray<SparseBooleanArray> mCreateImsFeatureWithSlotIdFlagMap = + new SparseArray<>(); + private IImsServiceControllerListener mListener; + private Executor mExecutor; + /** + * Create a new ImsService. + * <p> + * Method stubs called from the framework will be called asynchronously. Vendor specifies the + * {@link Executor} that the methods stubs will be called. If mExecutor is set to null by + * vendor use Runnable::run. + */ + public ImsService() { + mExecutor = ImsService.this.getExecutor(); + if (mExecutor == null) { + mExecutor = Runnable::run; + } + } /** * Listener that notifies the framework of ImsService changes. @@ -200,79 +229,163 @@ public class ImsService extends Service { } @Override - public IImsMmTelFeature createMmTelFeature(int slotId) { - return createMmTelFeatureInternal(slotId); + public IImsMmTelFeature createMmTelFeature(int slotId, int subId) { + MmTelFeature f = (MmTelFeature) getImsFeature(slotId, ImsFeature.FEATURE_MMTEL); + if (f == null) { + return executeMethodAsyncForResult(() -> createMmTelFeatureInternal(slotId, subId), + "createMmTelFeature"); + } else { + return f.getBinder(); + } + } + + @Override + public IImsMmTelFeature createEmergencyOnlyMmTelFeature(int slotId) { + MmTelFeature f = (MmTelFeature) getImsFeature(slotId, ImsFeature.FEATURE_MMTEL); + if (f == null) { + return executeMethodAsyncForResult(() -> createEmergencyOnlyMmTelFeatureInternal( + slotId), "createEmergencyOnlyMmTelFeature"); + } else { + return f.getBinder(); + } } @Override - public IImsRcsFeature createRcsFeature(int slotId) { - return createRcsFeatureInternal(slotId); + public IImsRcsFeature createRcsFeature(int slotId, int subId) { + RcsFeature f = (RcsFeature) getImsFeature(slotId, ImsFeature.FEATURE_RCS); + if (f == null) { + return executeMethodAsyncForResult(() -> + createRcsFeatureInternal(slotId, subId), "createRcsFeature"); + } else { + return f.getBinder(); + } } @Override public void addFeatureStatusCallback(int slotId, int featureType, IImsFeatureStatusCallback c) { - ImsService.this.addImsFeatureStatusCallback(slotId, featureType, c); + executeMethodAsync(() -> ImsService.this.addImsFeatureStatusCallback( + slotId, featureType, c), "addFeatureStatusCallback"); } @Override public void removeFeatureStatusCallback(int slotId, int featureType, IImsFeatureStatusCallback c) { - ImsService.this.removeImsFeatureStatusCallback(slotId, featureType, c); + executeMethodAsync(() -> ImsService.this.removeImsFeatureStatusCallback( + slotId, featureType, c), "removeFeatureStatusCallback"); } @Override - public void removeImsFeature(int slotId, int featureType) { - ImsService.this.removeImsFeature(slotId, featureType); + public void removeImsFeature(int slotId, int featureType, boolean changeSubId) { + if (changeSubId && isImsFeatureCreatedForSlot(slotId, featureType)) { + Log.w(LOG_TAG, "Do not remove Ims feature for compatibility"); + return; + } + executeMethodAsync(() -> ImsService.this.removeImsFeature(slotId, featureType), + "removeImsFeature"); + setImsFeatureCreatedForSlot(slotId, featureType, false); } @Override public ImsFeatureConfiguration querySupportedImsFeatures() { - return ImsService.this.querySupportedImsFeatures(); + return executeMethodAsyncForResult(() -> ImsService.this.querySupportedImsFeatures(), + "ImsFeatureConfiguration"); } @Override public long getImsServiceCapabilities() { - long caps = ImsService.this.getImsServiceCapabilities(); - long sanitizedCaps = sanitizeCapabilities(caps); - if (caps != sanitizedCaps) { - Log.w(LOG_TAG, "removing invalid bits from field: 0x" - + Long.toHexString(caps ^ sanitizedCaps)); - } - return sanitizedCaps; + return executeMethodAsyncForResult(() -> { + long caps = ImsService.this.getImsServiceCapabilities(); + long sanitizedCaps = sanitizeCapabilities(caps); + if (caps != sanitizedCaps) { + Log.w(LOG_TAG, "removing invalid bits from field: 0x" + + Long.toHexString(caps ^ sanitizedCaps)); + } + return sanitizedCaps; + }, "getImsServiceCapabilities"); } @Override public void notifyImsServiceReadyForFeatureCreation() { - ImsService.this.readyForFeatureCreation(); + executeMethodAsync(() -> ImsService.this.readyForFeatureCreation(), + "notifyImsServiceReadyForFeatureCreation"); } @Override - public IImsConfig getConfig(int slotId) { - ImsConfigImplBase c = ImsService.this.getConfig(slotId); - return c != null ? c.getIImsConfig() : null; + public IImsConfig getConfig(int slotId, int subId) { + return executeMethodAsyncForResult(() -> { + ImsConfigImplBase c = + ImsService.this.getConfigForSubscription(slotId, subId); + if (c != null) { + c.setDefaultExecutor(mExecutor); + return c.getIImsConfig(); + } else { + return null; + } + }, "getConfig"); } @Override - public IImsRegistration getRegistration(int slotId) { - ImsRegistrationImplBase r = ImsService.this.getRegistration(slotId); - return r != null ? r.getBinder() : null; + public IImsRegistration getRegistration(int slotId, int subId) { + return executeMethodAsyncForResult(() -> { + ImsRegistrationImplBase r = + ImsService.this.getRegistrationForSubscription(slotId, subId); + if (r != null) { + r.setDefaultExecutor(mExecutor); + return r.getBinder(); + } else { + return null; + } + }, "getRegistration"); } @Override public ISipTransport getSipTransport(int slotId) { - SipTransportImplBase s = ImsService.this.getSipTransport(slotId); - return s != null ? s.getBinder() : null; + return executeMethodAsyncForResult(() -> { + SipTransportImplBase s = ImsService.this.getSipTransport(slotId); + if (s != null) { + s.setDefaultExecutor(mExecutor); + return s.getBinder(); + } else { + return null; + } + }, "getSipTransport"); } @Override - public void enableIms(int slotId) { - ImsService.this.enableIms(slotId); + public void enableIms(int slotId, int subId) { + executeMethodAsync(() -> + ImsService.this.enableImsForSubscription(slotId, subId), "enableIms"); } @Override - public void disableIms(int slotId) { - ImsService.this.disableIms(slotId); + public void disableIms(int slotId, int subId) { + executeMethodAsync(() -> + ImsService.this.disableImsForSubscription(slotId, subId), "disableIms"); + } + + // Call the methods with a clean calling identity on the executor and wait indefinitely for + // the future to return. + private void executeMethodAsync(Runnable r, String errorLogName) { + try { + CompletableFuture.runAsync( + () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join(); + } catch (CancellationException | CompletionException e) { + Log.w(LOG_TAG, "ImsService Binder - " + errorLogName + " exception: " + + e.getMessage()); + } + } + + private <T> T executeMethodAsyncForResult(Supplier<T> r, String errorLogName) { + CompletableFuture<T> future = CompletableFuture.supplyAsync( + () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor); + try { + return future.get(); + } catch (ExecutionException | InterruptedException e) { + Log.w(LOG_TAG, "ImsService Binder - " + errorLogName + " exception: " + + e.getMessage()); + return null; + } } }; @@ -288,28 +401,34 @@ public class ImsService extends Service { return null; } - /** - * @hide - */ - @VisibleForTesting - public SparseArray<ImsFeature> getFeatures(int slotId) { - return mFeaturesBySlot.get(slotId); + private IImsMmTelFeature createMmTelFeatureInternal(int slotId, int subscriptionId) { + MmTelFeature f = createMmTelFeatureForSubscription(slotId, subscriptionId); + if (f != null) { + setupFeature(f, slotId, ImsFeature.FEATURE_MMTEL); + f.setDefaultExecutor(mExecutor); + return f.getBinder(); + } else { + Log.e(LOG_TAG, "createMmTelFeatureInternal: null feature returned."); + return null; + } } - private IImsMmTelFeature createMmTelFeatureInternal(int slotId) { - MmTelFeature f = createMmTelFeature(slotId); + private IImsMmTelFeature createEmergencyOnlyMmTelFeatureInternal(int slotId) { + MmTelFeature f = createEmergencyOnlyMmTelFeature(slotId); if (f != null) { setupFeature(f, slotId, ImsFeature.FEATURE_MMTEL); + f.setDefaultExecutor(mExecutor); return f.getBinder(); } else { - Log.e(LOG_TAG, "createMmTelFeatureInternal: null feature returned."); + Log.e(LOG_TAG, "createEmergencyOnlyMmTelFeatureInternal: null feature returned."); return null; } } - private IImsRcsFeature createRcsFeatureInternal(int slotId) { - RcsFeature f = createRcsFeature(slotId); + private IImsRcsFeature createRcsFeatureInternal(int slotId, int subI) { + RcsFeature f = createRcsFeatureForSubscription(slotId, subI); if (f != null) { + f.setDefaultExecutor(mExecutor); setupFeature(f, slotId, ImsFeature.FEATURE_RCS); return f.getBinder(); } else { @@ -388,6 +507,49 @@ public class ImsService extends Service { f.onFeatureRemoved(); features.remove(featureType); } + + } + + /** + * @hide + */ + @VisibleForTesting + public ImsFeature getImsFeature(int slotId, int featureType) { + synchronized (mFeaturesBySlot) { + // Get SparseArray for Features, by querying slot Id + SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId); + if (features == null) { + return null; + } + return features.get(featureType); + } + } + + private void setImsFeatureCreatedForSlot(int slotId, + @ImsFeature.FeatureType int featureType, boolean createdForSlot) { + synchronized (mCreateImsFeatureWithSlotIdFlagMap) { + getImsFeatureCreatedForSlot(slotId).put(featureType, createdForSlot); + } + } + + /** + * @hide + */ + @VisibleForTesting + public boolean isImsFeatureCreatedForSlot(int slotId, + @ImsFeature.FeatureType int featureType) { + synchronized (mCreateImsFeatureWithSlotIdFlagMap) { + return getImsFeatureCreatedForSlot(slotId).get(featureType); + } + } + + private SparseBooleanArray getImsFeatureCreatedForSlot(int slotId) { + SparseBooleanArray createFlag = mCreateImsFeatureWithSlotIdFlagMap.get(slotId); + if (createFlag == null) { + createFlag = new SparseBooleanArray(); + mCreateImsFeatureWithSlotIdFlagMap.put(slotId, createFlag); + } + return createFlag; } /** @@ -446,27 +608,95 @@ public class ImsService extends Service { } /** + * The framework has enabled IMS for the subscription specified, the ImsService should register + * for IMS and perform all appropriate initialization to bring up all ImsFeatures. + * + * @param slotId The slot ID that IMS will be enabled for. + * @param subscriptionId The subscription ID that IMS will be enabled for. + */ + public void enableImsForSubscription(int slotId, int subscriptionId) { + enableIms(slotId); + } + + /** + * The framework has disabled IMS for the subscription specified. The ImsService must deregister + * for IMS and set capability status to false for all ImsFeatures. + * @param slotId The slot ID that IMS will be disabled for. + * @param subscriptionId The subscription ID that IMS will be disabled for. + */ + public void disableImsForSubscription(int slotId, int subscriptionId) { + disableIms(slotId); + } + + /** * The framework has enabled IMS for the slot specified, the ImsService should register for IMS * and perform all appropriate initialization to bring up all ImsFeatures. + * @deprecated Use {@link #enableImsForSubscription} instead. */ + @Deprecated public void enableIms(int slotId) { } /** * The framework has disabled IMS for the slot specified. The ImsService must deregister for IMS * and set capability status to false for all ImsFeatures. + * @deprecated Use {@link #disableImsForSubscription} instead. */ + @Deprecated public void disableIms(int slotId) { } /** * When called, the framework is requesting that a new {@link MmTelFeature} is created for the + * specified subscription. + * + * @param subscriptionId The subscription ID that the MMTEL Feature is being created for. + * @return The newly created {@link MmTelFeature} associated with the subscription or null if + * the feature is not supported. + */ + public @Nullable MmTelFeature createMmTelFeatureForSubscription(int slotId, + int subscriptionId) { + setImsFeatureCreatedForSlot(slotId, ImsFeature.FEATURE_MMTEL, true); + return createMmTelFeature(slotId); + } + + /** + * When called, the framework is requesting that a new {@link RcsFeature} is created for the + * specified subscription. + * + * @param subscriptionId The subscription ID that the RCS Feature is being created for. + * @return The newly created {@link RcsFeature} associated with the subscription or null if the + * feature is not supported. + */ + public @Nullable RcsFeature createRcsFeatureForSubscription(int slotId, int subscriptionId) { + setImsFeatureCreatedForSlot(slotId, ImsFeature.FEATURE_RCS, true); + return createRcsFeature(slotId); + } + + /** + * When called, the framework is requesting that a new emergency-only {@link MmTelFeature} is + * created for the specified slot. For emergency calls, there is no known Subscription Id. + * + * @param slotId The slot ID that the MMTEL Feature is being created for. + * @return An MmTelFeature instance to be used for the slot ID when there is not + * subscription inserted. Only requested when there is no subscription active on + * the specified slot. + */ + public @Nullable MmTelFeature createEmergencyOnlyMmTelFeature(int slotId) { + setImsFeatureCreatedForSlot(slotId, ImsFeature.FEATURE_MMTEL, true); + return createMmTelFeature(slotId); + } + + /** + * When called, the framework is requesting that a new {@link MmTelFeature} is created for the * specified slot. + * @deprecated Use {@link #createMmTelFeatureForSubscription} instead * * @param slotId The slot ID that the MMTEL Feature is being created for. * @return The newly created {@link MmTelFeature} associated with the slot or null if the * feature is not supported. */ + @Deprecated public MmTelFeature createMmTelFeature(int slotId) { return null; } @@ -474,32 +704,62 @@ public class ImsService extends Service { /** * When called, the framework is requesting that a new {@link RcsFeature} is created for the * specified slot. + * @deprecated Use {@link #createRcsFeatureForSubscription} instead * * @param slotId The slot ID that the RCS Feature is being created for. * @return The newly created {@link RcsFeature} associated with the slot or null if the feature * is not supported. */ + @Deprecated public RcsFeature createRcsFeature(int slotId) { return null; } /** + * Return the {@link ImsConfigImplBase} implementation associated with the provided + * subscription. This will be used by the platform to get/set specific IMS related + * configurations. + * + * @param subscriptionId The subscription ID that the IMS configuration is associated with. + * @return ImsConfig implementation that is associated with the specified subscription. + */ + public @NonNull ImsConfigImplBase getConfigForSubscription(int slotId, int subscriptionId) { + return getConfig(slotId); + } + + /** + * Return the {@link ImsRegistrationImplBase} implementation associated with the provided + * subscription. + * + * @param subscriptionId The subscription ID that is associated with the IMS Registration. + * @return the ImsRegistration implementation associated with the subscription. + */ + public @NonNull ImsRegistrationImplBase getRegistrationForSubscription(int slotId, + int subscriptionId) { + return getRegistration(slotId); + } + + /** * Return the {@link ImsConfigImplBase} implementation associated with the provided slot. This * will be used by the platform to get/set specific IMS related configurations. + * @deprecated use {@link #getConfigForSubscription} instead. * * @param slotId The slot that the IMS configuration is associated with. * @return ImsConfig implementation that is associated with the specified slot. */ + @Deprecated public ImsConfigImplBase getConfig(int slotId) { return new ImsConfigImplBase(); } /** * Return the {@link ImsRegistrationImplBase} implementation associated with the provided slot. + * @deprecated use {@link #getRegistrationForSubscription} instead. * * @param slotId The slot that is associated with the IMS Registration. * @return the ImsRegistration implementation associated with the slot. */ + @Deprecated public ImsRegistrationImplBase getRegistration(int slotId) { return new ImsRegistrationImplBase(); } @@ -562,4 +822,15 @@ public class ImsService extends Service { result.append("}"); return result.toString(); } + + /** + * The ImsService will now be able to define an Executor that the ImsService can be used to + * execute the methods. By default all ImsService level method calls will use this Executor. + * The ImsService has set the default executor as Runnable::run, + * Should be override or default executor will be used. + * @return an Executor used to execute methods called remotely by the framework. + */ + public @NonNull Executor getExecutor() { + return Runnable::run; + } } diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java index abc5606e6743..5aef8a6638ac 100644 --- a/telephony/java/android/telephony/ims/ProvisioningManager.java +++ b/telephony/java/android/telephony/ims/ProvisioningManager.java @@ -33,6 +33,7 @@ import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyFrameworkInitializer; import android.telephony.TelephonyManager; +import android.telephony.ims.aidl.IFeatureProvisioningCallback; import android.telephony.ims.aidl.IImsConfigCallback; import android.telephony.ims.aidl.IRcsConfigCallback; import android.telephony.ims.feature.MmTelFeature; @@ -53,17 +54,11 @@ import java.util.concurrent.Executor; * IMS provisioning keys are defined per carrier or OEM using OMA-DM or other provisioning * applications and may vary. It is up to the carrier and OEM applications to ensure that the * correct provisioning keys are being used when integrating with a vendor's ImsService. - * - * Note: For compatibility purposes, the integer values [0 - 99] used in - * {@link #setProvisioningIntValue(int, int)} have been reserved for existing provisioning keys - * previously defined in the Android framework. Please do not redefine new provisioning keys in this - * range or it may generate collisions with existing keys. Some common constants have also been - * defined in this class to make integrating with other system apps easier. - * @hide */ -@SystemApi public class ProvisioningManager { + private static final String TAG = "ProvisioningManager"; + /**@hide*/ @StringDef(prefix = "STRING_QUERY_RESULT_ERROR_", value = { STRING_QUERY_RESULT_ERROR_GENERIC, @@ -74,14 +69,18 @@ public class ProvisioningManager { /** * The query from {@link #getProvisioningStringValue(int)} has resulted in an unspecified error. + * @hide */ + @SystemApi public static final String STRING_QUERY_RESULT_ERROR_GENERIC = "STRING_QUERY_RESULT_ERROR_GENERIC"; /** * The query from {@link #getProvisioningStringValue(int)} has resulted in an error because the * ImsService implementation was not ready for provisioning queries. + * @hide */ + @SystemApi public static final String STRING_QUERY_RESULT_ERROR_NOT_READY = "STRING_QUERY_RESULT_ERROR_NOT_READY"; @@ -93,12 +92,16 @@ public class ProvisioningManager { /** * The integer result of provisioning for the queried key is disabled. + * @hide */ + @SystemApi public static final int PROVISIONING_VALUE_DISABLED = 0; /** * The integer result of provisioning for the queried key is enabled. + * @hide */ + @SystemApi public static final int PROVISIONING_VALUE_ENABLED = 1; @@ -443,27 +446,31 @@ public class ProvisioningManager { /** * Override the user-defined WiFi Roaming enabled setting for this subscription, defined in - * {@link SubscriptionManager#WFC_ROAMING_ENABLED_CONTENT_URI}, for the purposes of provisioning - * the subscription for WiFi Calling. + * {@link android.telephony.SubscriptionManager#WFC_ROAMING_ENABLED_CONTENT_URI}, + * for the purposes of provisioning the subscription for WiFi Calling. * - * @see #getProvisioningIntValue(int) * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + * @hide */ + @SystemApi public static final int KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE = 26; /** * Override the user-defined WiFi mode for this subscription, defined in - * {@link SubscriptionManager#WFC_MODE_CONTENT_URI}, for the purposes of provisioning - * this subscription for WiFi Calling. + * {@link android.telephony.SubscriptionManager#WFC_MODE_CONTENT_URI}, + * for the purposes of provisioning this subscription for WiFi Calling. * * Valid values for this key are: * {@link ImsMmTelManager#WIFI_MODE_WIFI_ONLY}, * {@link ImsMmTelManager#WIFI_MODE_CELLULAR_PREFERRED}, or * {@link ImsMmTelManager#WIFI_MODE_WIFI_PREFERRED}. * - * @see #getProvisioningIntValue(int) * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + * @hide */ + @SystemApi public static final int KEY_VOICE_OVER_WIFI_MODE_OVERRIDE = 27; /** @@ -862,7 +869,9 @@ public class ProvisioningManager { * <p>Value is in String format. * @see #setProvisioningStringValue(int, String) * @see #getProvisioningStringValue(int) + * @hide */ + @SystemApi public static final int KEY_VOICE_OVER_WIFI_ENTITLEMENT_ID = 67; /** @@ -884,7 +893,9 @@ public class ProvisioningManager { /** * Callback for IMS provisioning changes. + * @hide */ + @SystemApi public static class Callback { private static class CallbackBinder extends IImsConfigCallback.Stub { @@ -954,11 +965,105 @@ public class ProvisioningManager { } } + /** + * Callback for IMS provisioning feature changes. + */ + public static class FeatureProvisioningCallback { + + private static class CallbackBinder extends IFeatureProvisioningCallback.Stub { + + private final FeatureProvisioningCallback mFeatureProvisioningCallback; + private Executor mExecutor; + + private CallbackBinder(FeatureProvisioningCallback featureProvisioningCallback) { + mFeatureProvisioningCallback = featureProvisioningCallback; + } + + @Override + public final void onFeatureProvisioningChanged( + int capability, int tech, boolean isProvisioned) { + final long callingIdentity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> + mFeatureProvisioningCallback.onFeatureProvisioningChanged( + capability, tech, isProvisioned)); + } finally { + restoreCallingIdentity(callingIdentity); + } + } + + @Override + public final void onRcsFeatureProvisioningChanged( + int capability, int tech, boolean isProvisioned) { + final long callingIdentity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> + mFeatureProvisioningCallback.onRcsFeatureProvisioningChanged( + capability, tech, isProvisioned)); + } finally { + restoreCallingIdentity(callingIdentity); + } + } + + private void setExecutor(Executor executor) { + mExecutor = executor; + } + } + + private final CallbackBinder mBinder = new CallbackBinder(this); + + /** + * The IMS MMTEL provisioning has changed for a specific capability and IMS + * registration technology. + * @param capability The MMTEL capability that provisioning has changed for. + * @param tech The IMS registration technology associated with the MMTEL capability that + * provisioning has changed for. + * @param isProvisioned {@code true} if the capability is provisioned for the technology + * specified, or {@code false} if the capability is not provisioned for the technology + * specified. + */ + public void onFeatureProvisioningChanged( + @MmTelFeature.MmTelCapabilities.MmTelCapability int capability, + @ImsRegistrationImplBase.ImsRegistrationTech int tech, + boolean isProvisioned) { + // Base Implementation + } + + /** + * The IMS RCS provisioning has changed for a specific capability and IMS + * registration technology. + * @param capability The RCS capability that provisioning has changed for. + * @param tech The IMS registration technology associated with the RCS capability that + * provisioning has changed for. + * @param isProvisioned {@code true} if the capability is provisioned for the technology + * specified, or {@code false} if the capability is not provisioned for the technology + * specified. + */ + public void onRcsFeatureProvisioningChanged( + @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability, + @ImsRegistrationImplBase.ImsRegistrationTech int tech, + boolean isProvisioned) { + // Base Implementation + } + + /**@hide*/ + public final IFeatureProvisioningCallback getBinder() { + return mBinder; + } + + /**@hide*/ + public void setExecutor(Executor executor) { + mBinder.setExecutor(executor); + } + } + private int mSubId; /** * The callback for RCS provisioning changes. + * @hide */ + @SystemApi public static class RcsProvisioningCallback { private static class CallbackBinder extends IRcsConfigCallback.Stub { @@ -1096,7 +1201,9 @@ public class ProvisioningManager { * @param subId The ID of the subscription that this ProvisioningManager will use. * @see android.telephony.SubscriptionManager#getActiveSubscriptionInfoList() * @throws IllegalArgumentException if the subscription is invalid. + * @hide */ + @SystemApi public static @NonNull ProvisioningManager createForSubscriptionId(int subId) { if (!SubscriptionManager.isValidSubscriptionId(subId)) { throw new IllegalArgumentException("Invalid subscription ID"); @@ -1105,7 +1212,9 @@ public class ProvisioningManager { return new ProvisioningManager(subId); } - private ProvisioningManager(int subId) { + /**@hide*/ + //@SystemApi + public ProvisioningManager(int subId) { mSubId = subId; } @@ -1114,6 +1223,12 @@ public class ProvisioningManager { * * When the subscription associated with this callback is removed (SIM removed, ESIM swap, * etc...), this callback will automatically be removed. + * + * <p> Requires Permission: + * <ul> + * <li>{@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE},</li> + * </ul> + * * @param executor The {@link Executor} to call the callback methods on * @param callback The provisioning callbackto be registered. * @see #unregisterProvisioningChangedCallback(Callback) @@ -1124,7 +1239,9 @@ public class ProvisioningManager { * the {@link ImsService} associated with the subscription is not available. This can happen if * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed * reason. + * @hide */ + @SystemApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerProvisioningChangedCallback(@NonNull @CallbackExecutor Executor executor, @NonNull Callback callback) throws ImsException { @@ -1142,12 +1259,20 @@ public class ProvisioningManager { * Unregister an existing {@link Callback}. When the subscription associated with this * callback is removed (SIM removed, ESIM swap, etc...), this callback will automatically be * removed. If this method is called for an inactive subscription, it will result in a no-op. + * + * <p> Requires Permission: + * <ul> + * <li>{@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE},</li> + * </ul> + * * @param callback The existing {@link Callback} to be removed. * @see #registerProvisioningChangedCallback(Executor, Callback) * * @throws IllegalArgumentException if the subscription associated with this callback is * invalid. + * @hide */ + @SystemApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterProvisioningChangedCallback(@NonNull Callback callback) { try { @@ -1158,6 +1283,62 @@ public class ProvisioningManager { } /** + * Register a new {@link FeatureProvisioningCallback}, which is used to listen for + * IMS feature provisioning updates. + * <p> + * When the subscription associated with this callback is removed (SIM removed, + * ESIM swap,etc...), this callback will automatically be removed. + * + * <p> Requires Permission: + * <ul> + * <li> android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE,</li> + * <li>{@link android.Manifest.permission#READ_PRECISE_PHONE_STATE},</li> + * <li>or that the caller has carrier privileges (see + * {@link TelephonyManager#hasCarrierPrivileges()}).</li> + * </ul> + * + * @param executor The executor that the callback methods will be called on. + * @param callback The callback instance being registered. + * @throws ImsException if the subscription associated with this callback is + * valid, but the {@link ImsService the service crashed, for example. See + * {@link ImsException#getCode()} for a more detailed reason. + */ + @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE) + public void registerFeatureProvisioningChangedCallback( + @NonNull @CallbackExecutor Executor executor, + @NonNull FeatureProvisioningCallback callback) throws ImsException { + callback.setExecutor(executor); + try { + getITelephony().registerFeatureProvisioningChangedCallback(mSubId, + callback.getBinder()); + } catch (ServiceSpecificException e) { + throw new ImsException(e.getMessage(), e.errorCode); + } catch (RemoteException | IllegalStateException e) { + throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); + } + } + + /** + * Unregisters a previously registered {@link FeatureProvisioningCallback} + * instance. When the subscription associated with this + * callback is removed (SIM removed, ESIM swap, etc...), this callback will + * automatically be removed. If this method is called for an inactive + * subscription, it will result in a no-op. + * + * @param callback The existing {@link FeatureProvisioningCallback} to be removed. + * @see #registerFeatureProvisioningChangedCallback(Executor, FeatureProvisioningCallback) + */ + public void unregisterFeatureProvisioningChangedCallback( + @NonNull FeatureProvisioningCallback callback) { + try { + getITelephony().unregisterFeatureProvisioningChangedCallback(mSubId, + callback.getBinder()); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + /** * Query for the integer value associated with the provided key. * * This operation is blocking and should not be performed on the UI thread. @@ -1166,7 +1347,9 @@ public class ProvisioningManager { * @return an integer value for the provided key, or * {@link ImsConfigImplBase#CONFIG_RESULT_UNKNOWN} if the key doesn't exist. * @throws IllegalArgumentException if the key provided was invalid. + * @hide */ + @SystemApi @WorkerThread @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getProvisioningIntValue(int key) { @@ -1186,7 +1369,9 @@ public class ProvisioningManager { * @return a String value for the provided key, {@code null} if the key doesn't exist, or * {@link StringResultError} if there was an error getting the value for the provided key. * @throws IllegalArgumentException if the key provided was invalid. + * @hide */ + @SystemApi @WorkerThread @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public @Nullable @StringResultError String getProvisioningStringValue(int key) { @@ -1207,7 +1392,15 @@ public class ProvisioningManager { * @param key An integer that represents the provisioning key, which is defined by the OEM. * @param value a integer value for the provided key. * @return the result of setting the configuration value. + * @hide + * + * Note: For compatibility purposes, the integer values [0 - 99] used in + * {@link #setProvisioningIntValue(int, int)} have been reserved for existing provisioning keys + * previously defined in the Android framework. Please do not redefine new provisioning keys + * in this range or it may generate collisions with existing keys. Some common constants have + * also been defined in this class to make integrating with other system apps easier. */ + @SystemApi @WorkerThread @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public @ImsConfigImplBase.SetConfigResult int setProvisioningIntValue(int key, int value) { @@ -1227,7 +1420,9 @@ public class ProvisioningManager { * should be appropriately namespaced to avoid collision. * @param value a String value for the provided key. * @return the result of setting the configuration value. + * @hide */ + @SystemApi @WorkerThread @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public @ImsConfigImplBase.SetConfigResult int setProvisioningStringValue(int key, @@ -1247,8 +1442,14 @@ public class ProvisioningManager { * does not support the capability/technology combination specified, this operation will be a * no-op. * - * @see CarrierConfigManager#KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL - * @see CarrierConfigManager#KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL + * <p>Requires Permission: + * <ul> + * <li>{@link android.Manifest.permission#MODIFY_PHONE_STATE},</li> + * <li>or that the calling app has carrier privileges (see</li> + * <li>{@link TelephonyManager#hasCarrierPrivileges}).</li> + * </ul> + * + * @see CarrierConfigManager.Ims#KEY_MMTEL_REQUIRES_PROVISIONING_BUNDLE * @param isProvisioned true if the device is provisioned for UT over IMS, false otherwise. */ @WorkerThread @@ -1256,9 +1457,10 @@ public class ProvisioningManager { public void setProvisioningStatusForCapability( @MmTelFeature.MmTelCapabilities.MmTelCapability int capability, @ImsRegistrationImplBase.ImsRegistrationTech int tech, boolean isProvisioned) { + try { getITelephony().setImsProvisioningStatusForCapability(mSubId, capability, tech, - isProvisioned); + isProvisioned); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -1272,14 +1474,21 @@ public class ProvisioningManager { * {@link ImsRegistrationImplBase.ImsRegistrationTech} combination specified, this method will * always return {@code true}. * - * @see CarrierConfigManager#KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL - * @see CarrierConfigManager#KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL + * <p> Requires Permission: + * <ul> + * <li>android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE,</li> + * <li>{@link android.Manifest.permission#READ_PRECISE_PHONE_STATE},</li> + * <li>or that the caller has carrier privileges (see + * {@link TelephonyManager#hasCarrierPrivileges()}).</li> + * </ul> + * + * @see CarrierConfigManager.Ims#KEY_MMTEL_REQUIRES_PROVISIONING_BUNDLE * @return true if the device is provisioned for the capability or does not require * provisioning, false if the capability does require provisioning and has not been * provisioned yet. */ @WorkerThread - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE) public boolean getProvisioningStatusForCapability( @MmTelFeature.MmTelCapabilities.MmTelCapability int capability, @ImsRegistrationImplBase.ImsRegistrationTech int tech) { @@ -1297,17 +1506,55 @@ public class ProvisioningManager { * {@link RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag} this method will always return * {@code true}. * - * @see CarrierConfigManager#KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL + * @see CarrierConfigManager.Ims#KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL * @return true if the device is provisioned for the capability or does not require * provisioning, false if the capability does require provisioning and has not been * provisioned yet. + * @deprecated Use {@link #getRcsProvisioningStatusForCapability(int, int)} instead, + * as this only retrieves provisioning information for + * {@link ImsRegistrationImplBase#REGISTRATION_TECH_LTE} + * @hide */ + @Deprecated + @SystemApi @WorkerThread @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getRcsProvisioningStatusForCapability( @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability) { try { - return getITelephony().getRcsProvisioningStatusForCapability(mSubId, capability); + return getITelephony().getRcsProvisioningStatusForCapability(mSubId, capability, + ImsRegistrationImplBase.REGISTRATION_TECH_LTE); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + /** + * Get the provisioning status for the IMS RCS capability specified. + * + * If provisioning is not required for the queried + * {@link RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag} this method + * will always return {@code true}. + * + * <p> Requires Permission: + * <ul> + * <li>{@link android.Manifest.permission#READ_PRECISE_PHONE_STATE},</li> + * <li>or that the caller has carrier privileges (see + * {@link TelephonyManager#hasCarrierPrivileges()}).</li> + * </ul> + * + * @see CarrierConfigManager.Ims#KEY_RCS_REQUIRES_PROVISIONING_BUNDLE + * @return true if the device is provisioned for the capability or does not require + * provisioning, false if the capability does require provisioning and has not been + * provisioned yet. + */ + @WorkerThread + @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE) + public boolean getRcsProvisioningStatusForCapability( + @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability, + @ImsRegistrationImplBase.ImsRegistrationTech int tech) { + try { + return getITelephony().getRcsProvisioningStatusForCapability(mSubId, capability, tech); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -1316,6 +1563,13 @@ public class ProvisioningManager { /** * Set the provisioning status for the IMS RCS capability using the specified subscription. * + * <p> Requires Permission: + * <ul> + * <li>{@link android.Manifest.permission#MODIFY_PHONE_STATE}</li> + * <li>or that the caller has carrier privileges (see + * {@link TelephonyManager#hasCarrierPrivileges()}).</li> + * </ul> + * Provisioning may or may not be required, depending on the carrier configuration. If * provisioning is not required for the carrier associated with this subscription or the device * does not support the capability/technology combination specified, this operation will be a @@ -1324,7 +1578,13 @@ public class ProvisioningManager { * @see CarrierConfigManager#KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL * @param isProvisioned true if the device is provisioned for the RCS capability specified, * false otherwise. + * @deprecated Use {@link #setRcsProvisioningStatusForCapability(int, int, boolean)} instead, + * as this method only sets provisioning information for + * {@link ImsRegistrationImplBase#REGISTRATION_TECH_LTE} + * @hide */ + @Deprecated + @SystemApi @WorkerThread @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public void setRcsProvisioningStatusForCapability( @@ -1332,28 +1592,121 @@ public class ProvisioningManager { boolean isProvisioned) { try { getITelephony().setRcsProvisioningStatusForCapability(mSubId, capability, - isProvisioned); + ImsRegistrationImplBase.REGISTRATION_TECH_LTE, isProvisioned); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } } /** + * Set the provisioning status for the IMS RCS capability using the specified subscription. + * + * Provisioning may or may not be required, depending on the carrier configuration. If + * provisioning is not required for the carrier associated with this subscription or the device + * does not support the capability/technology combination specified, this operation will be a + * no-op. + * + * <p> Requires Permission: + * <ul> + * <li>{@link android.Manifest.permission#MODIFY_PHONE_STATE},</li> + * <li>or that the caller has carrier privileges (see + * {@link TelephonyManager#hasCarrierPrivileges()}).</li> + * </ul> + * + * @see CarrierConfigManager.Ims#KEY_RCS_REQUIRES_PROVISIONING_BUNDLE + * @param isProvisioned true if the device is provisioned for the RCS capability specified, + * false otherwise. + */ + @WorkerThread + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + public void setRcsProvisioningStatusForCapability( + @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability, + @ImsRegistrationImplBase.ImsRegistrationTech int tech, boolean isProvisioned) { + try { + getITelephony().setRcsProvisioningStatusForCapability(mSubId, capability, + tech, isProvisioned); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + /** + * Indicates whether provisioning for the MMTEL capability and IMS registration technology + * specified is required or not + * + * <p> Requires Permission: + * <ul> + * <li> android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE,</li> + * <li>{@link android.Manifest.permission#READ_PRECISE_PHONE_STATE},</li> + * <li> or that the caller has carrier privileges (see + * {@link TelephonyManager#hasCarrierPrivileges()}).</li> + * </ul> + * + * @return true if provisioning is required for the MMTEL capability and IMS + * registration technology specified, false if it is not required. + */ + @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE) + public boolean isProvisioningRequiredForCapability( + @MmTelFeature.MmTelCapabilities.MmTelCapability int capability, + @ImsRegistrationImplBase.ImsRegistrationTech int tech) { + try { + return getITelephony().isProvisioningRequiredForCapability(mSubId, capability, tech); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + + /** + * Indicates whether provisioning for the RCS capability and IMS registration technology + * specified is required or not + * + * <p> Requires Permission: + * <ul> + * <li> android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE,</li> + * <li>{@link android.Manifest.permission#READ_PRECISE_PHONE_STATE},</li> + * <li> or that the caller has carrier privileges (see + * {@link TelephonyManager#hasCarrierPrivileges()}).</li> + * </ul> + * + * @return true if provisioning is required for the RCS capability and IMS + * registration technology specified, false if it is not required. + */ + @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE) + public boolean isRcsProvisioningRequiredForCapability( + @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability, + @ImsRegistrationImplBase.ImsRegistrationTech int tech) { + try { + return getITelephony().isRcsProvisioningRequiredForCapability(mSubId, capability, tech); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + + /** * Notify the framework that an RCS autoconfiguration XML file has been received for * provisioning. - * <p> - * Requires Permission: Manifest.permission.MODIFY_PHONE_STATE or that the calling app has - * carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}). + * + * <p>Requires Permission: + * <ul> + * <li>{@link Manifest.permission#MODIFY_PHONE_STATE},</li> + * <li>or that the calling app has carrier privileges (see + * {@link TelephonyManager#hasCarrierPrivileges()}).</li> + * </ul> + * * @param config The XML file to be read. ASCII/UTF8 encoded text if not compressed. * @param isCompressed The XML file is compressed in gzip format and must be decompressed * before being read. - * + * @hide */ + @SystemApi @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public void notifyRcsAutoConfigurationReceived(@NonNull byte[] config, boolean isCompressed) { if (config == null) { throw new IllegalArgumentException("Must include a non-null config XML file."); } + try { getITelephony().notifyRcsAutoConfigurationReceived(mSubId, config, isCompressed); } catch (RemoteException e) { @@ -1372,7 +1725,9 @@ public class ProvisioningManager { * <p>Contains {@link #EXTRA_SUBSCRIPTION_ID} to specify the subscription index for which * the intent is valid. and {@link #EXTRA_STATUS} to specify RCS VoLTE single registration * status. + * @hide */ + @SystemApi @RequiresPermission(Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE = @@ -1380,7 +1735,9 @@ public class ProvisioningManager { /** * Integer extra to specify subscription index. + * @hide */ + @SystemApi public static final String EXTRA_SUBSCRIPTION_ID = "android.telephony.ims.extra.SUBSCRIPTION_ID"; @@ -1390,22 +1747,30 @@ public class ProvisioningManager { * <p>The value can be {@link #STATUS_CAPABLE}, {@link #STATUS_DEVICE_NOT_CAPABLE}, * {@link #STATUS_CARRIER_NOT_CAPABLE}, or bitwise OR of * {@link #STATUS_DEVICE_NOT_CAPABLE} and {@link #STATUS_CARRIER_NOT_CAPABLE}. + * @hide */ + @SystemApi public static final String EXTRA_STATUS = "android.telephony.ims.extra.STATUS"; /** * RCS VoLTE single registration is supported by the device and carrier. + * @hide */ + @SystemApi public static final int STATUS_CAPABLE = 0; /** * RCS VoLTE single registration is not supported by the device. + * @hide */ + @SystemApi public static final int STATUS_DEVICE_NOT_CAPABLE = 0x01; /** * RCS VoLTE single registration is not supported by the carrier + * @hide */ + @SystemApi public static final int STATUS_CARRIER_NOT_CAPABLE = 0x01 << 1; /** @@ -1415,11 +1780,14 @@ public class ProvisioningManager { * provisioning is done using autoconfiguration, then these parameters shall be * sent in the HTTP get request to fetch the RCS provisioning. RCS client * configuration must be provided by the application before registering for the - * provisioning status events {@link #registerRcsProvisioningCallback()} + * provisioning status events + * {@link #registerRcsProvisioningCallback(Executor, RcsProvisioningCallback)} * When the IMS/RCS service receives the RCS client configuration, it will detect * the change in the configuration, and trigger the auto-configuration as needed. * @param rcc RCS client configuration {@link RcsClientConfiguration} + * @hide */ + @SystemApi @RequiresPermission(Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void setRcsClientConfiguration( @NonNull RcsClientConfiguration rcc) throws ImsException { @@ -1440,18 +1808,21 @@ public class ProvisioningManager { * <ul> * <li>{@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE},</li> * <li>{@link android.Manifest.permission#PERFORM_IMS_SINGLE_REGISTRATION},</li> - * <li>or that the caller has carrier privileges (see + * <li>or that the calling app has carrier privileges (see * {@link TelephonyManager#hasCarrierPrivileges()}).</li> * </ul> + * * @return true if IMS single registration is capable at this time, or false otherwise - * @throws ImsException If the remote ImsService is not available for - * any reason or the subscription associated with this instance is no - * longer active. See {@link ImsException#getCode()} for more - * information. + * @throws ImsException If the remote ImsService is not available for any reason or + * the subscription associated with this instance is no longer active. + * See {@link ImsException#getCode()} for more information. * @see PackageManager#FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION for whether or not this * device supports IMS single registration. + * @hide */ - @RequiresPermission(anyOf = {Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + @SystemApi + @RequiresPermission(anyOf = { + Manifest.permission.READ_PRIVILEGED_PHONE_STATE, Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public boolean isRcsVolteSingleRegistrationCapable() throws ImsException { try { @@ -1478,8 +1849,6 @@ public class ProvisioningManager { * <ul> * <li>{@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE},</li> * <li>{@link android.Manifest.permission#PERFORM_IMS_SINGLE_REGISTRATION},</li> - * <li>or that the caller has carrier privileges (see - * {@link TelephonyManager#hasCarrierPrivileges()}).</li> * </ul> * * @param executor The {@link Executor} to call the callback methods on @@ -1497,8 +1866,11 @@ public class ProvisioningManager { * params (See {@link #setRcsClientConfiguration}) and re register the * callback. * See {@link ImsException#getCode()} for a more detailed reason. + * @hide */ - @RequiresPermission(anyOf = {Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + @SystemApi + @RequiresPermission(anyOf = { + Manifest.permission.READ_PRIVILEGED_PHONE_STATE, Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public void registerRcsProvisioningCallback( @NonNull @CallbackExecutor Executor executor, @@ -1525,8 +1897,6 @@ public class ProvisioningManager { * <ul> * <li>{@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE},</li> * <li>{@link android.Manifest.permission#PERFORM_IMS_SINGLE_REGISTRATION},</li> - * <li>or that the caller has carrier privileges (see - * {@link TelephonyManager#hasCarrierPrivileges()}).</li> * </ul> * * @param callback The existing {@link RcsProvisioningCallback} to be @@ -1534,8 +1904,11 @@ public class ProvisioningManager { * @see #registerRcsProvisioningCallback(Executor, RcsProvisioningCallback) * @throws IllegalArgumentException if the subscription associated with * this callback is invalid. + * @hide */ - @RequiresPermission(anyOf = {Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + @SystemApi + @RequiresPermission(anyOf = { + Manifest.permission.READ_PRIVILEGED_PHONE_STATE, Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public void unregisterRcsProvisioningCallback( @NonNull RcsProvisioningCallback callback) { @@ -1556,9 +1929,10 @@ public class ProvisioningManager { * {@link RcsProvisioningCallback} may expect to receive * {@link RcsProvisioningCallback#onConfigurationReset}, then * {@link RcsProvisioningCallback#onConfigurationChanged} when the new - * RCS configuration is received and notified by - * {@link #notifyRcsAutoConfigurationReceived} + * RCS configuration is received and notified by {@link #notifyRcsAutoConfigurationReceived} + * @hide */ + @SystemApi @RequiresPermission(Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void triggerRcsReconfiguration() { try { diff --git a/telephony/java/android/telephony/ims/RcsClientConfiguration.java b/telephony/java/android/telephony/ims/RcsClientConfiguration.java index c25ace0c6a62..f367e404a35b 100644 --- a/telephony/java/android/telephony/ims/RcsClientConfiguration.java +++ b/telephony/java/android/telephony/ims/RcsClientConfiguration.java @@ -34,7 +34,7 @@ public final class RcsClientConfiguration implements Parcelable { /**@hide*/ @StringDef(prefix = "RCS_PROFILE_", - value = {RCS_PROFILE_1_0, RCS_PROFILE_2_3}) + value = {RCS_PROFILE_1_0, RCS_PROFILE_2_3, RCS_PROFILE_2_4}) public @interface StringRcsProfile {} /** @@ -45,6 +45,10 @@ public final class RcsClientConfiguration implements Parcelable { * RCS profile UP 2.3 */ public static final String RCS_PROFILE_2_3 = "UP_2.3"; + /** + * RCS profile UP 2.4 + */ + public static final String RCS_PROFILE_2_4 = "UP_2.4"; private String mRcsVersion; private String mRcsProfile; @@ -58,8 +62,8 @@ public final class RcsClientConfiguration implements Parcelable { * @param rcsVersion The parameter identifies the RCS version supported * by the client. Refer to GSMA RCC.07 "rcs_version" parameter. * @param rcsProfile Identifies a fixed set of RCS services that are - * supported by the client. See {@link #RCS_PROFILE_1_0 } or - * {@link #RCS_PROFILE_2_3 } + * supported by the client. See {@link #RCS_PROFILE_1_0 }, + * {@link #RCS_PROFILE_2_3 } or {@link #RCS_PROFILE_2_4 } * @param clientVendor Identifies the vendor providing the RCS client. * @param clientVersion Identifies the RCS client version. Refer to GSMA * RCC.07 "client_version" parameter. @@ -80,8 +84,8 @@ public final class RcsClientConfiguration implements Parcelable { * @param rcsVersion The parameter identifies the RCS version supported * by the client. Refer to GSMA RCC.07 "rcs_version" parameter. * @param rcsProfile Identifies a fixed set of RCS services that are - * supported by the client. See {@link #RCS_PROFILE_1_0 } or - * {@link #RCS_PROFILE_2_3 } + * supported by the client. See {@link #RCS_PROFILE_1_0 }, + * {@link #RCS_PROFILE_2_3 } or {@link #RCS_PROFILE_2_4 } * @param clientVendor Identifies the vendor providing the RCS client. * @param clientVersion Identifies the RCS client version. Refer to GSMA * RCC.07 "client_version" parameter. diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java index 91121187a19a..9c36db8176b9 100644 --- a/telephony/java/android/telephony/ims/RcsContactUceCapability.java +++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java @@ -221,6 +221,15 @@ public final class RcsContactUceCapability implements Parcelable { } /** + * Set the entity URI related to the contact whose capabilities were requested. + * @param entityUri the 'pres' URL of the PRESENTITY publishing presence document. + */ + public @NonNull PresenceBuilder setEntityUri(@NonNull Uri entityUri) { + mCapabilities.mEntityUri = entityUri; + return this; + } + + /** * @return the RcsContactUceCapability instance. */ public @NonNull RcsContactUceCapability build() { @@ -232,6 +241,7 @@ public final class RcsContactUceCapability implements Parcelable { private @SourceType int mSourceType; private @CapabilityMechanism int mCapabilityMechanism; private @RequestResult int mRequestResult; + private Uri mEntityUri; private final Set<String> mFeatureTags = new HashSet<>(); private final List<RcsContactPresenceTuple> mPresenceTuples = new ArrayList<>(); @@ -248,6 +258,7 @@ public final class RcsContactUceCapability implements Parcelable { mCapabilityMechanism = in.readInt(); mSourceType = in.readInt(); mRequestResult = in.readInt(); + mEntityUri = in.readParcelable(Uri.class.getClassLoader(), android.net.Uri.class); List<String> featureTagList = new ArrayList<>(); in.readStringList(featureTagList); mFeatureTags.addAll(featureTagList); @@ -260,6 +271,7 @@ public final class RcsContactUceCapability implements Parcelable { out.writeInt(mCapabilityMechanism); out.writeInt(mSourceType); out.writeInt(mRequestResult); + out.writeParcelable(mEntityUri, flags); out.writeStringList(new ArrayList<>(mFeatureTags)); out.writeParcelableList(mPresenceTuples, flags); } @@ -361,6 +373,15 @@ public final class RcsContactUceCapability implements Parcelable { return mContactUri; } + /** + * Retrieve the entity URI of the contact whose presence information is being requested for. + * @return the URI representing the 'pres' URL of the PRESENTITY publishing presence document + * or {@code null} if the entity uri does not exist in the presence document. + */ + public @Nullable Uri getEntityUri() { + return mEntityUri; + } + @Override public String toString() { StringBuilder builder = new StringBuilder("RcsContactUceCapability"); @@ -382,6 +403,13 @@ public final class RcsContactUceCapability implements Parcelable { builder.append(mSourceType); builder.append(", requestResult="); builder.append(mRequestResult); + if (Build.IS_ENG) { + builder.append("entity uri="); + builder.append(mEntityUri != null ? mEntityUri : "null"); + } else { + builder.append("entity uri (isNull)="); + builder.append(mEntityUri != null ? "XXX" : "null"); + } if (mCapabilityMechanism == CAPABILITY_MECHANISM_PRESENCE) { builder.append(", presenceTuples={"); diff --git a/apex/media/aidl/private/android/media/Session2Command.aidl b/telephony/java/android/telephony/ims/aidl/IFeatureProvisioningCallback.aidl index 43a7b123ed29..63ec4aaf1f48 100644 --- a/apex/media/aidl/private/android/media/Session2Command.aidl +++ b/telephony/java/android/telephony/ims/aidl/IFeatureProvisioningCallback.aidl @@ -1,5 +1,5 @@ /* - * Copyright 2018 The Android Open Source Project + * Copyright (c) 2022 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. @@ -14,6 +14,15 @@ * limitations under the License. */ -package android.media; -parcelable Session2Command; +package android.telephony.ims.aidl; + +/** + * Provides callback interface for FeatureProvisioning when a value has changed. + * + * {@hide} + */ +oneway interface IFeatureProvisioningCallback { + void onFeatureProvisioningChanged(int capability, int tech, boolean isProvisioned); + void onRcsFeatureProvisioningChanged(int capability, int tech, boolean isProvisioned); +} diff --git a/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl b/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl index c6966b3cf53e..ae6166fea02a 100644 --- a/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl +++ b/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl @@ -32,18 +32,19 @@ import com.android.ims.internal.IImsFeatureStatusCallback; */ interface IImsServiceController { void setListener(IImsServiceControllerListener l); - IImsMmTelFeature createMmTelFeature(int slotId); - IImsRcsFeature createRcsFeature(int slotId); + IImsMmTelFeature createMmTelFeature(int slotId, int subId); + IImsMmTelFeature createEmergencyOnlyMmTelFeature(int slotId); + IImsRcsFeature createRcsFeature(int slotId, int subId); ImsFeatureConfiguration querySupportedImsFeatures(); long getImsServiceCapabilities(); void addFeatureStatusCallback(int slotId, int featureType, in IImsFeatureStatusCallback c); void removeFeatureStatusCallback(int slotId, int featureType, in IImsFeatureStatusCallback c); // Synchronous call to ensure the ImsService is ready before continuing with feature creation. void notifyImsServiceReadyForFeatureCreation(); - void removeImsFeature(int slotId, int featureType); - IImsConfig getConfig(int slotId); - IImsRegistration getRegistration(int slotId); + void removeImsFeature(int slotId, int featureType, boolean changeSubId); + IImsConfig getConfig(int slotId, int subId); + IImsRegistration getRegistration(int slotId, int subId); ISipTransport getSipTransport(int slotId); - oneway void enableIms(int slotId); - oneway void disableIms(int slotId); + oneway void enableIms(int slotId, int subId); + oneway void disableIms(int slotId, int subId); } diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java index 9a3f592480d1..ad2e9e133a11 100644 --- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java +++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java @@ -40,16 +40,25 @@ import android.telephony.ims.stub.ImsRegistrationImplBase; import android.telephony.ims.stub.ImsSmsImplBase; import android.telephony.ims.stub.ImsUtImplBase; import android.util.ArraySet; +import android.util.Log; import com.android.ims.internal.IImsCallSession; import com.android.ims.internal.IImsEcbm; import com.android.ims.internal.IImsMultiEndpoint; import com.android.ims.internal.IImsUt; +import com.android.internal.telephony.util.TelephonyUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; import java.util.Set; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; /** * Base implementation for Voice and SMS (IR-92) and Video (IR-94) IMS support. @@ -60,6 +69,7 @@ import java.util.Set; public class MmTelFeature extends ImsFeature { private static final String LOG_TAG = "MmTelFeature"; + private Executor mExecutor; /** * @hide @@ -68,160 +78,261 @@ public class MmTelFeature extends ImsFeature { public MmTelFeature() { } + /** + * Create a new MmTelFeature using the Executor specified for methods being called by the + * framework. + * @param executor The executor for the framework to use when executing the methods overridden + * by the implementation of MmTelFeature. + * @hide + */ + @SystemApi + public MmTelFeature(@NonNull Executor executor) { + super(); + mExecutor = executor; + } + private final IImsMmTelFeature mImsMMTelBinder = new IImsMmTelFeature.Stub() { @Override public void setListener(IImsMmTelListener l) { - MmTelFeature.this.setListener(l); + executeMethodAsyncNoException(() -> MmTelFeature.this.setListener(l), "setListener"); } @Override public int getFeatureState() throws RemoteException { - try { - return MmTelFeature.this.getFeatureState(); - } catch (Exception e) { - throw new RemoteException(e.getMessage()); - } + return executeMethodAsyncForResult(() -> MmTelFeature.this.getFeatureState(), + "getFeatureState"); } - @Override public ImsCallProfile createCallProfile(int callSessionType, int callType) throws RemoteException { - synchronized (mLock) { - try { - return MmTelFeature.this.createCallProfile(callSessionType, callType); - } catch (Exception e) { - throw new RemoteException(e.getMessage()); - } - } + return executeMethodAsyncForResult(() -> MmTelFeature.this.createCallProfile( + callSessionType, callType), "createCallProfile"); } @Override public void changeOfferedRtpHeaderExtensionTypes(List<RtpHeaderExtensionType> types) throws RemoteException { - synchronized (mLock) { - try { - MmTelFeature.this.changeOfferedRtpHeaderExtensionTypes(new ArraySet<>(types)); - } catch (Exception e) { - throw new RemoteException(e.getMessage()); - } - } + executeMethodAsync(() -> MmTelFeature.this.changeOfferedRtpHeaderExtensionTypes( + new ArraySet<>(types)), "changeOfferedRtpHeaderExtensionTypes"); } @Override public IImsCallSession createCallSession(ImsCallProfile profile) throws RemoteException { - synchronized (mLock) { - return createCallSessionInterface(profile); + AtomicReference<RemoteException> exceptionRef = new AtomicReference<>(); + IImsCallSession result = executeMethodAsyncForResult(() -> { + try { + return createCallSessionInterface(profile); + } catch (RemoteException e) { + exceptionRef.set(e); + return null; + } + }, "createCallSession"); + + if (exceptionRef.get() != null) { + throw exceptionRef.get(); } + + return result; } @Override public int shouldProcessCall(String[] numbers) { - synchronized (mLock) { - return MmTelFeature.this.shouldProcessCall(numbers); + Integer result = executeMethodAsyncForResultNoException(() -> + MmTelFeature.this.shouldProcessCall(numbers), "shouldProcessCall"); + if (result != null) { + return result.intValue(); + } else { + return PROCESS_CALL_CSFB; } } @Override public IImsUt getUtInterface() throws RemoteException { - synchronized (mLock) { - return MmTelFeature.this.getUtInterface(); + AtomicReference<RemoteException> exceptionRef = new AtomicReference<>(); + IImsUt result = executeMethodAsyncForResult(() -> { + try { + return MmTelFeature.this.getUtInterface(); + } catch (RemoteException e) { + exceptionRef.set(e); + return null; + } + }, "getUtInterface"); + + if (exceptionRef.get() != null) { + throw exceptionRef.get(); } + + return result; } @Override public IImsEcbm getEcbmInterface() throws RemoteException { - synchronized (mLock) { - return MmTelFeature.this.getEcbmInterface(); + AtomicReference<RemoteException> exceptionRef = new AtomicReference<>(); + IImsEcbm result = executeMethodAsyncForResult(() -> { + try { + return MmTelFeature.this.getEcbmInterface(); + } catch (RemoteException e) { + exceptionRef.set(e); + return null; + } + }, "getEcbmInterface"); + + if (exceptionRef.get() != null) { + throw exceptionRef.get(); } + + return result; } @Override public void setUiTtyMode(int uiTtyMode, Message onCompleteMessage) throws RemoteException { - synchronized (mLock) { - try { - MmTelFeature.this.setUiTtyMode(uiTtyMode, onCompleteMessage); - } catch (Exception e) { - throw new RemoteException(e.getMessage()); - } - } + executeMethodAsync(() -> MmTelFeature.this.setUiTtyMode(uiTtyMode, onCompleteMessage), + "setUiTtyMode"); } @Override public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException { - synchronized (mLock) { - return MmTelFeature.this.getMultiEndpointInterface(); + AtomicReference<RemoteException> exceptionRef = new AtomicReference<>(); + IImsMultiEndpoint result = executeMethodAsyncForResult(() -> { + try { + return MmTelFeature.this.getMultiEndpointInterface(); + } catch (RemoteException e) { + exceptionRef.set(e); + return null; + } + }, "getMultiEndpointInterface"); + + if (exceptionRef.get() != null) { + throw exceptionRef.get(); } + + return result; } @Override public int queryCapabilityStatus() { - return MmTelFeature.this.queryCapabilityStatus().mCapabilities; + Integer result = executeMethodAsyncForResultNoException(() -> MmTelFeature.this + .queryCapabilityStatus().mCapabilities, "queryCapabilityStatus"); + + if (result != null) { + return result.intValue(); + } else { + return 0; + } } @Override public void addCapabilityCallback(IImsCapabilityCallback c) { - // no need to lock, structure already handles multithreading. - MmTelFeature.this.addCapabilityCallback(c); + executeMethodAsyncNoException(() -> MmTelFeature.this + .addCapabilityCallback(c), "addCapabilityCallback"); } @Override public void removeCapabilityCallback(IImsCapabilityCallback c) { - // no need to lock, structure already handles multithreading. - MmTelFeature.this.removeCapabilityCallback(c); + executeMethodAsyncNoException(() -> MmTelFeature.this + .removeCapabilityCallback(c), "removeCapabilityCallback"); } @Override public void changeCapabilitiesConfiguration(CapabilityChangeRequest request, IImsCapabilityCallback c) { - MmTelFeature.this.requestChangeEnabledCapabilities(request, c); + executeMethodAsyncNoException(() -> MmTelFeature.this + .requestChangeEnabledCapabilities(request, c), + "changeCapabilitiesConfiguration"); } @Override public void queryCapabilityConfiguration(int capability, int radioTech, IImsCapabilityCallback c) { - queryCapabilityConfigurationInternal(capability, radioTech, c); + executeMethodAsyncNoException(() -> queryCapabilityConfigurationInternal( + capability, radioTech, c), "queryCapabilityConfiguration"); } @Override public void setSmsListener(IImsSmsListener l) { - MmTelFeature.this.setSmsListener(l); + executeMethodAsyncNoException(() -> MmTelFeature.this.setSmsListener(l), + "setSmsListener"); } @Override public void sendSms(int token, int messageRef, String format, String smsc, boolean retry, byte[] pdu) { - synchronized (mLock) { - MmTelFeature.this.sendSms(token, messageRef, format, smsc, retry, pdu); - } + executeMethodAsyncNoException(() -> MmTelFeature.this + .sendSms(token, messageRef, format, smsc, retry, pdu), "sendSms"); } @Override public void acknowledgeSms(int token, int messageRef, int result) { - synchronized (mLock) { - MmTelFeature.this.acknowledgeSms(token, messageRef, result); - } + executeMethodAsyncNoException(() -> MmTelFeature.this + .acknowledgeSms(token, messageRef, result), "acknowledgeSms"); } @Override public void acknowledgeSmsReport(int token, int messageRef, int result) { - synchronized (mLock) { - MmTelFeature.this.acknowledgeSmsReport(token, messageRef, result); - } + executeMethodAsyncNoException(() -> MmTelFeature.this + .acknowledgeSmsReport(token, messageRef, result), "acknowledgeSmsReport"); } @Override public String getSmsFormat() { - synchronized (mLock) { - return MmTelFeature.this.getSmsFormat(); - } + return executeMethodAsyncForResultNoException(() -> MmTelFeature.this + .getSmsFormat(), "getSmsFormat"); } @Override public void onSmsReady() { - synchronized (mLock) { - MmTelFeature.this.onSmsReady(); + executeMethodAsyncNoException(() -> MmTelFeature.this.onSmsReady(), + "onSmsReady"); + } + + // Call the methods with a clean calling identity on the executor and wait indefinitely for + // the future to return. + private void executeMethodAsync(Runnable r, String errorLogName) throws RemoteException { + try { + CompletableFuture.runAsync( + () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join(); + } catch (CancellationException | CompletionException e) { + Log.w(LOG_TAG, "MmTelFeature Binder - " + errorLogName + " exception: " + + e.getMessage()); + throw new RemoteException(e.getMessage()); + } + } + + private void executeMethodAsyncNoException(Runnable r, String errorLogName) { + try { + CompletableFuture.runAsync( + () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join(); + } catch (CancellationException | CompletionException e) { + Log.w(LOG_TAG, "MmTelFeature Binder - " + errorLogName + " exception: " + + e.getMessage()); + } + } + + private <T> T executeMethodAsyncForResult(Supplier<T> r, + String errorLogName) throws RemoteException { + CompletableFuture<T> future = CompletableFuture.supplyAsync( + () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor); + try { + return future.get(); + } catch (ExecutionException | InterruptedException e) { + Log.w(LOG_TAG, "MmTelFeature Binder - " + errorLogName + " exception: " + + e.getMessage()); + throw new RemoteException(e.getMessage()); + } + } + + private <T> T executeMethodAsyncForResultNoException(Supplier<T> r, + String errorLogName) { + CompletableFuture<T> future = CompletableFuture.supplyAsync( + () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor); + try { + return future.get(); + } catch (ExecutionException | InterruptedException e) { + Log.w(LOG_TAG, "MmTelFeature Binder - " + errorLogName + " exception: " + + e.getMessage()); + return null; } } }; @@ -283,6 +394,13 @@ public class MmTelFeature extends ImsFeature { public @interface MmTelCapability {} /** + * Undefined capability type for initialization + * This is used to check the upper range of MmTel capability + * {@hide} + */ + public static final int CAPABILITY_TYPE_NONE = 0; + + /** * This MmTelFeature supports Voice calling (IR.92) */ public static final int CAPABILITY_TYPE_VOICE = 1 << 0; @@ -308,6 +426,12 @@ public class MmTelFeature extends ImsFeature { public static final int CAPABILITY_TYPE_CALL_COMPOSER = 1 << 4; /** + * This is used to check the upper range of MmTel capability + * {@hide} + */ + public static final int CAPABILITY_TYPE_MAX = CAPABILITY_TYPE_CALL_COMPOSER + 1; + + /** * @hide */ @Override @@ -672,7 +796,12 @@ public class MmTelFeature extends ImsFeature { public IImsCallSession createCallSessionInterface(ImsCallProfile profile) throws RemoteException { ImsCallSessionImplBase s = MmTelFeature.this.createCallSession(profile); - return s != null ? s.getServiceImpl() : null; + if (s != null) { + s.setDefaultExecutor(mExecutor); + return s.getServiceImpl(); + } else { + return null; + } } /** @@ -713,7 +842,12 @@ public class MmTelFeature extends ImsFeature { */ protected IImsUt getUtInterface() throws RemoteException { ImsUtImplBase utImpl = getUt(); - return utImpl != null ? utImpl.getInterface() : null; + if (utImpl != null) { + utImpl.setDefaultExecutor(mExecutor); + return utImpl.getInterface(); + } else { + return null; + } } /** @@ -721,7 +855,12 @@ public class MmTelFeature extends ImsFeature { */ protected IImsEcbm getEcbmInterface() throws RemoteException { ImsEcbmImplBase ecbmImpl = getEcbm(); - return ecbmImpl != null ? ecbmImpl.getImsEcbm() : null; + if (ecbmImpl != null) { + ecbmImpl.setDefaultExecutor(mExecutor); + return ecbmImpl.getImsEcbm(); + } else { + return null; + } } /** @@ -729,7 +868,12 @@ public class MmTelFeature extends ImsFeature { */ public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException { ImsMultiEndpointImplBase multiendpointImpl = getMultiEndpoint(); - return multiendpointImpl != null ? multiendpointImpl.getIImsMultiEndpoint() : null; + if (multiendpointImpl != null) { + multiendpointImpl.setDefaultExecutor(mExecutor); + return multiendpointImpl.getIImsMultiEndpoint(); + } else { + return null; + } } /** @@ -859,4 +1003,16 @@ public class MmTelFeature extends ImsFeature { public final IImsMmTelFeature getBinder() { return mImsMMTelBinder; } + + /** + * Set default Executor from ImsService. + * @param executor The default executor for the framework to use when executing the methods + * overridden by the implementation of MmTelFeature. + * @hide + */ + public final void setDefaultExecutor(@NonNull Executor executor) { + if (mExecutor == null) { + mExecutor = executor; + } + } } diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java index 18cc37d7fbda..70e4ef1f1a3a 100644 --- a/telephony/java/android/telephony/ims/feature/RcsFeature.java +++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java @@ -59,9 +59,7 @@ import java.util.function.Supplier; /** * Base implementation of the RcsFeature APIs. Any ImsService wishing to support RCS should extend * this class and provide implementations of the RcsFeature methods that they support. - * @hide */ -@SystemApi public class RcsFeature extends ImsFeature { private static final String LOG_TAG = "RcsFeature"; @@ -70,7 +68,7 @@ public class RcsFeature extends ImsFeature { // Reference the outer class in order to have better test coverage metrics instead of // creating a inner class referencing the outer class directly. private final RcsFeature mReference; - private final Executor mExecutor; + private Executor mExecutor; RcsFeatureBinder(RcsFeature classRef, @CallbackExecutor Executor executor) { mReference = classRef; @@ -186,14 +184,14 @@ public class RcsFeature extends ImsFeature { * Contains the capabilities defined and supported by a {@link RcsFeature} in the * form of a bitmask. The capabilities that are used in the RcsFeature are * defined as: - * {@link RcsUceAdatper.RcsImsCapabilityFlag#CAPABILITY_TYPE_OPTIONS_UCE} - * {@link RceUceAdapter.RcsImsCapabilityFlag#CAPABILITY_TYPE_PRESENCE_UCE} + * {RcsUceAdapter.RcsImsCapabilityFlag#CAPABILITY_TYPE_OPTIONS_UCE} + * {RcsUceAdapter.RcsImsCapabilityFlag#CAPABILITY_TYPE_PRESENCE_UCE} * * The enabled capabilities of this RcsFeature will be set by the framework - * using {@link #changeEnabledCapabilities(CapabilityChangeRequest, CapabilityCallbackProxy)}. + * using {#changeEnabledCapabilities(CapabilityChangeRequest, CapabilityCallbackProxy)}. * After the capabilities have been set, the RcsFeature may then perform the necessary bring up * of the capability and notify the capability status as true using - * {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)}. This will signal to the + * {#notifyCapabilitiesStatusChanged(RcsImsCapabilities)}. This will signal to the * framework that the capability is available for usage. */ public static class RcsImsCapabilities extends Capabilities { @@ -227,10 +225,18 @@ public class RcsFeature extends ImsFeature { public static final int CAPABILITY_TYPE_PRESENCE_UCE = 1 << 1; /** + * This is used to check the upper range of RCS capability + * {@hide} + */ + public static final int CAPABILITY_TYPE_MAX = CAPABILITY_TYPE_PRESENCE_UCE + 1; + + /** * Create a new {@link RcsImsCapabilities} instance with the provided capabilities. * @param capabilities The capabilities that are supported for RCS in the form of a * bitfield. + * @hide */ + @SystemApi public RcsImsCapabilities(@RcsUceAdapter.RcsImsCapabilityFlag int capabilities) { super(capabilities); } @@ -243,23 +249,35 @@ public class RcsFeature extends ImsFeature { super(capabilities.getMask()); } + /** + * @hide + */ @Override + @SystemApi public void addCapabilities(@RcsUceAdapter.RcsImsCapabilityFlag int capabilities) { super.addCapabilities(capabilities); } + /** + * @hide + */ @Override + @SystemApi public void removeCapabilities(@RcsUceAdapter.RcsImsCapabilityFlag int capabilities) { super.removeCapabilities(capabilities); } + /** + * @hide + */ @Override + @SystemApi public boolean isCapable(@RcsUceAdapter.RcsImsCapabilityFlag int capabilities) { return super.isCapable(capabilities); } } - private final Executor mExecutor; + private Executor mExecutor; private final RcsFeatureBinder mImsRcsBinder; private RcsCapabilityExchangeImplBase mCapabilityExchangeImpl; private CapabilityExchangeEventListener mCapExchangeEventListener; @@ -270,13 +288,11 @@ public class RcsFeature extends ImsFeature { * Method stubs called from the framework will be called asynchronously. To specify the * {@link Executor} that the methods stubs will be called, use * {@link RcsFeature#RcsFeature(Executor)} instead. - * - * @deprecated Use {@link #RcsFeature(Executor)} to create the RcsFeature. + * @hide */ - @Deprecated + @SystemApi public RcsFeature() { super(); - mExecutor = Runnable::run; // Run on the Binder threads that call them. mImsRcsBinder = new RcsFeatureBinder(this, mExecutor); } @@ -286,7 +302,9 @@ public class RcsFeature extends ImsFeature { * framework. * @param executor The executor for the framework to use when executing the methods overridden * by the implementation of RcsFeature. + * @hide */ + @SystemApi public RcsFeature(@NonNull Executor executor) { super(); if (executor == null) { @@ -305,7 +323,7 @@ public class RcsFeature extends ImsFeature { * @hide */ @Override - public void initialize(Context context, int slotId) { + public void initialize(@NonNull Context context, @NonNull int slotId) { super.initialize(context, slotId); // Notify that the RcsFeature is ready. mExecutor.execute(() -> onFeatureReady()); @@ -317,8 +335,10 @@ public class RcsFeature extends ImsFeature { * requests. To change the status of the capabilities * {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)} should be called. * @return A copy of the current RcsFeature capability status. + * @hide */ @Override + @SystemApi public @NonNull final RcsImsCapabilities queryCapabilityStatus() { return new RcsImsCapabilities(super.queryCapabilityStatus()); } @@ -328,7 +348,9 @@ public class RcsFeature extends ImsFeature { * this signals to the framework that the capability has been initialized and is ready. * Call {@link #queryCapabilityStatus()} to return the current capability status. * @param capabilities The current capability status of the RcsFeature. + * @hide */ + @SystemApi public final void notifyCapabilitiesStatusChanged(@NonNull RcsImsCapabilities capabilities) { if (capabilities == null) { throw new IllegalArgumentException("RcsImsCapabilities must be non-null!"); @@ -345,7 +367,9 @@ public class RcsFeature extends ImsFeature { * @param capability The capability that we are querying the configuration for. * @param radioTech The radio technology type that we are querying. * @return true if the capability is enabled, false otherwise. + * @hide */ + @SystemApi public boolean queryCapabilityConfiguration( @RcsUceAdapter.RcsImsCapabilityFlag int capability, @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) { @@ -368,8 +392,10 @@ public class RcsFeature extends ImsFeature { * be called for each capability change that resulted in an error. * @param request The request to change the capability. * @param callback To notify the framework that the result of the capability changes. + * @hide */ @Override + @SystemApi public void changeEnabledCapabilities(@NonNull CapabilityChangeRequest request, @NonNull CapabilityCallbackProxy callback) { // Base Implementation - Override to provide functionality @@ -389,7 +415,9 @@ public class RcsFeature extends ImsFeature { * event to the framework. * @return An instance of {@link RcsCapabilityExchangeImplBase} that implements capability * exchange if it is supported by the device. + * @hide */ + @SystemApi public @NonNull RcsCapabilityExchangeImplBase createCapabilityExchangeImpl( @NonNull CapabilityExchangeEventListener listener) { // Base Implementation, override to implement functionality @@ -399,20 +427,28 @@ public class RcsFeature extends ImsFeature { /** * Remove the given CapabilityExchangeImplBase instance. * @param capExchangeImpl The {@link RcsCapabilityExchangeImplBase} instance to be destroyed. + * @hide */ + @SystemApi public void destroyCapabilityExchangeImpl( @NonNull RcsCapabilityExchangeImplBase capExchangeImpl) { // Override to implement the process of destroying RcsCapabilityExchangeImplBase instance. } - /**{@inheritDoc}*/ + /**{@inheritDoc} + * @hide + */ @Override + @SystemApi public void onFeatureRemoved() { } - /**{@inheritDoc}*/ + /**{@inheritDoc} + * @hide + */ @Override + @SystemApi public void onFeatureReady() { } @@ -477,4 +513,17 @@ public class RcsFeature extends ImsFeature { return mCapabilityExchangeImpl; } } + + /** + * Set default Executor from ImsService. + * @param executor The default executor for the framework to use when executing the methods + * overridden by the implementation of RcsFeature. + * @hide + */ + public final void setDefaultExecutor(@NonNull Executor executor) { + if (mImsRcsBinder.mExecutor == null) { + mExecutor = executor; + mImsRcsBinder.mExecutor = executor; + } + } } diff --git a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java index a3a6cb864fa5..e8100957517f 100644 --- a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java @@ -30,12 +30,20 @@ import android.telephony.ims.RtpHeaderExtension; import android.telephony.ims.RtpHeaderExtensionType; import android.telephony.ims.aidl.IImsCallSessionListener; import android.util.ArraySet; +import android.util.Log; import com.android.ims.internal.IImsCallSession; import com.android.ims.internal.IImsVideoCallProvider; +import com.android.internal.telephony.util.TelephonyUtils; import java.util.List; import java.util.Set; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.function.Supplier; /** * Base implementation of IImsCallSession, which implements stub versions of the methods available. @@ -48,6 +56,8 @@ import java.util.Set; // DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you // will break other implementations of ImsCallSession maintained by other ImsServices. public class ImsCallSessionImplBase implements AutoCloseable { + + private static final String LOG_TAG = "ImsCallSessionImplBase"; /** * Notify USSD Mode. */ @@ -110,185 +120,235 @@ public class ImsCallSessionImplBase implements AutoCloseable { } } + private Executor mExecutor = Runnable::run; + // Non-final for injection by tests private IImsCallSession mServiceImpl = new IImsCallSession.Stub() { @Override public void close() { - ImsCallSessionImplBase.this.close(); + executeMethodAsync(() -> ImsCallSessionImplBase.this.close(), "close"); } @Override public String getCallId() { - return ImsCallSessionImplBase.this.getCallId(); + return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.getCallId(), + "getCallId"); } @Override public ImsCallProfile getCallProfile() { - return ImsCallSessionImplBase.this.getCallProfile(); + return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.getCallProfile(), + "getCallProfile"); } @Override public ImsCallProfile getLocalCallProfile() { - return ImsCallSessionImplBase.this.getLocalCallProfile(); + return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this + .getLocalCallProfile(), "getLocalCallProfile"); } @Override public ImsCallProfile getRemoteCallProfile() { - return ImsCallSessionImplBase.this.getRemoteCallProfile(); + return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this + .getRemoteCallProfile(), "getRemoteCallProfile"); } @Override public String getProperty(String name) { - return ImsCallSessionImplBase.this.getProperty(name); + return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.getProperty(name), + "getProperty"); } @Override public int getState() { - return ImsCallSessionImplBase.this.getState(); + return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.getState(), + "getState"); } @Override public boolean isInCall() { - return ImsCallSessionImplBase.this.isInCall(); + return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.isInCall(), + "isInCall"); } @Override public void setListener(IImsCallSessionListener listener) { - ImsCallSessionImplBase.this.setListener(new ImsCallSessionListener(listener)); + executeMethodAsync(() -> ImsCallSessionImplBase.this.setListener( + new ImsCallSessionListener(listener)), "setListener"); } @Override public void setMute(boolean muted) { - ImsCallSessionImplBase.this.setMute(muted); + executeMethodAsync(() -> ImsCallSessionImplBase.this.setMute(muted), "setMute"); } @Override public void start(String callee, ImsCallProfile profile) { - ImsCallSessionImplBase.this.start(callee, profile); + executeMethodAsync(() -> ImsCallSessionImplBase.this.start(callee, profile), "start"); } @Override public void startConference(String[] participants, ImsCallProfile profile) throws RemoteException { - ImsCallSessionImplBase.this.startConference(participants, profile); + executeMethodAsync(() -> ImsCallSessionImplBase.this.startConference(participants, + profile), "startConference"); } @Override public void accept(int callType, ImsStreamMediaProfile profile) { - ImsCallSessionImplBase.this.accept(callType, profile); + executeMethodAsync(() -> ImsCallSessionImplBase.this.accept(callType, profile), + "accept"); } @Override public void deflect(String deflectNumber) { - ImsCallSessionImplBase.this.deflect(deflectNumber); + executeMethodAsync(() -> ImsCallSessionImplBase.this.deflect(deflectNumber), + "deflect"); } @Override public void reject(int reason) { - ImsCallSessionImplBase.this.reject(reason); + executeMethodAsync(() -> ImsCallSessionImplBase.this.reject(reason), "reject"); } @Override public void transfer(@NonNull String number, boolean isConfirmationRequired) { - ImsCallSessionImplBase.this.transfer(number, isConfirmationRequired); + executeMethodAsync(() -> ImsCallSessionImplBase.this.transfer(number, + isConfirmationRequired), "transfer"); } @Override public void consultativeTransfer(@NonNull IImsCallSession transferToSession) { - ImsCallSessionImplBase otherSession = new ImsCallSessionImplBase(); - otherSession.setServiceImpl(transferToSession); - ImsCallSessionImplBase.this.transfer(otherSession); + executeMethodAsync(() -> { + ImsCallSessionImplBase otherSession = new ImsCallSessionImplBase(); + otherSession.setServiceImpl(transferToSession); + ImsCallSessionImplBase.this.transfer(otherSession); + }, "consultativeTransfer"); } @Override public void terminate(int reason) { - ImsCallSessionImplBase.this.terminate(reason); + executeMethodAsync(() -> ImsCallSessionImplBase.this.terminate(reason), "terminate"); } @Override public void hold(ImsStreamMediaProfile profile) { - ImsCallSessionImplBase.this.hold(profile); + executeMethodAsync(() -> ImsCallSessionImplBase.this.hold(profile), "hold"); } @Override public void resume(ImsStreamMediaProfile profile) { - ImsCallSessionImplBase.this.resume(profile); + executeMethodAsync(() -> ImsCallSessionImplBase.this.resume(profile), "resume"); } @Override public void merge() { - ImsCallSessionImplBase.this.merge(); + executeMethodAsync(() -> ImsCallSessionImplBase.this.merge(), "merge"); } @Override public void update(int callType, ImsStreamMediaProfile profile) { - ImsCallSessionImplBase.this.update(callType, profile); + executeMethodAsync(() -> ImsCallSessionImplBase.this.update(callType, profile), + "update"); } @Override public void extendToConference(String[] participants) { - ImsCallSessionImplBase.this.extendToConference(participants); + executeMethodAsync(() -> ImsCallSessionImplBase.this.extendToConference(participants), + "extendToConference"); } @Override public void inviteParticipants(String[] participants) { - ImsCallSessionImplBase.this.inviteParticipants(participants); + executeMethodAsync(() -> ImsCallSessionImplBase.this.inviteParticipants(participants), + "inviteParticipants"); } @Override public void removeParticipants(String[] participants) { - ImsCallSessionImplBase.this.removeParticipants(participants); + executeMethodAsync(() -> ImsCallSessionImplBase.this.removeParticipants(participants), + "removeParticipants"); } @Override public void sendDtmf(char c, Message result) { - ImsCallSessionImplBase.this.sendDtmf(c, result); + executeMethodAsync(() -> ImsCallSessionImplBase.this.sendDtmf(c, result), "sendDtmf"); } @Override public void startDtmf(char c) { - ImsCallSessionImplBase.this.startDtmf(c); + executeMethodAsync(() -> ImsCallSessionImplBase.this.startDtmf(c), "startDtmf"); } @Override public void stopDtmf() { - ImsCallSessionImplBase.this.stopDtmf(); + executeMethodAsync(() -> ImsCallSessionImplBase.this.stopDtmf(), "stopDtmf"); } @Override public void sendUssd(String ussdMessage) { - ImsCallSessionImplBase.this.sendUssd(ussdMessage); + executeMethodAsync(() -> ImsCallSessionImplBase.this.sendUssd(ussdMessage), "sendUssd"); } @Override public IImsVideoCallProvider getVideoCallProvider() { - return ImsCallSessionImplBase.this.getVideoCallProvider(); + return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this + .getVideoCallProvider(), "getVideoCallProvider"); } @Override public boolean isMultiparty() { - return ImsCallSessionImplBase.this.isMultiparty(); + return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.isMultiparty(), + "isMultiparty"); } @Override public void sendRttModifyRequest(ImsCallProfile toProfile) { - ImsCallSessionImplBase.this.sendRttModifyRequest(toProfile); + executeMethodAsync(() -> ImsCallSessionImplBase.this.sendRttModifyRequest(toProfile), + "sendRttModifyRequest"); } @Override public void sendRttModifyResponse(boolean status) { - ImsCallSessionImplBase.this.sendRttModifyResponse(status); + executeMethodAsync(() -> ImsCallSessionImplBase.this.sendRttModifyResponse(status), + "sendRttModifyResponse"); } @Override public void sendRttMessage(String rttMessage) { - ImsCallSessionImplBase.this.sendRttMessage(rttMessage); + executeMethodAsync(() -> ImsCallSessionImplBase.this.sendRttMessage(rttMessage), + "sendRttMessage"); } @Override public void sendRtpHeaderExtensions(@NonNull List<RtpHeaderExtension> extensions) { - ImsCallSessionImplBase.this.sendRtpHeaderExtensions( - new ArraySet<RtpHeaderExtension>(extensions)); + executeMethodAsync(() -> ImsCallSessionImplBase.this.sendRtpHeaderExtensions( + new ArraySet<RtpHeaderExtension>(extensions)), "sendRtpHeaderExtensions"); + } + + // Call the methods with a clean calling identity on the executor and wait indefinitely for + // the future to return. + private void executeMethodAsync(Runnable r, String errorLogName) { + try { + CompletableFuture.runAsync( + () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join(); + } catch (CancellationException | CompletionException e) { + Log.w(LOG_TAG, "ImsCallSessionImplBase Binder - " + errorLogName + " exception: " + + e.getMessage()); + } + } + + private <T> T executeMethodAsyncForResult(Supplier<T> r, + String errorLogName) { + CompletableFuture<T> future = CompletableFuture.supplyAsync( + () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor); + try { + return future.get(); + } catch (ExecutionException | InterruptedException e) { + Log.w(LOG_TAG, "ImsCallSessionImplBase Binder - " + errorLogName + " exception: " + + e.getMessage()); + return null; + } } }; @@ -674,4 +734,14 @@ public class ImsCallSessionImplBase implements AutoCloseable { public void setServiceImpl(IImsCallSession serviceImpl) { mServiceImpl = serviceImpl; } + + /** + * Set default Executor from MmTelFeature. + * @param executor The default executor for the framework to use when executing the methods + * overridden by the implementation of ImsCallSession. + * @hide + */ + public final void setDefaultExecutor(@NonNull Executor executor) { + mExecutor = executor; + } } diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java index d75da9035124..11fc328a42c7 100644 --- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java @@ -33,12 +33,21 @@ import android.util.Log; import com.android.ims.ImsConfig; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.util.RemoteCallbackListExt; +import com.android.internal.telephony.util.TelephonyUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; import java.util.Arrays; import java.util.HashMap; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; + /** * Controls the modification of IMS specific configurations. For more information on the supported @@ -81,21 +90,48 @@ public class ImsConfigImplBase { WeakReference<ImsConfigImplBase> mImsConfigImplBaseWeakReference; private HashMap<Integer, Integer> mProvisionedIntValue = new HashMap<>(); private HashMap<Integer, String> mProvisionedStringValue = new HashMap<>(); + private final Object mLock = new Object(); + private Executor mExecutor; @VisibleForTesting - public ImsConfigStub(ImsConfigImplBase imsConfigImplBase) { + public ImsConfigStub(ImsConfigImplBase imsConfigImplBase, Executor executor) { + mExecutor = executor; mImsConfigImplBaseWeakReference = new WeakReference<ImsConfigImplBase>(imsConfigImplBase); } @Override public void addImsConfigCallback(IImsConfigCallback c) throws RemoteException { - getImsConfigImpl().addImsConfigCallback(c); + AtomicReference<RemoteException> exceptionRef = new AtomicReference<>(); + executeMethodAsync(()-> { + try { + getImsConfigImpl().addImsConfigCallback(c); + } catch (RemoteException e) { + exceptionRef.set(e); + } + }, "addImsConfigCallback"); + + if (exceptionRef.get() != null) { + Log.d(TAG, "ImsConfigImplBase Exception addImsConfigCallback"); + throw exceptionRef.get(); + } } @Override public void removeImsConfigCallback(IImsConfigCallback c) throws RemoteException { - getImsConfigImpl().removeImsConfigCallback(c); + AtomicReference<RemoteException> exceptionRef = new AtomicReference<>(); + executeMethodAsync(()-> { + try { + getImsConfigImpl().removeImsConfigCallback(c); + } catch (RemoteException e) { + exceptionRef.set(e); + } + }, "removeImsConfigCallback"); + + if (exceptionRef.get() != null) { + Log.d(TAG, "ImsConfigImplBase Exception removeImsConfigCallback"); + throw exceptionRef.get(); + } } /** @@ -108,16 +144,34 @@ public class ImsConfigImplBase { * unavailable. */ @Override - public synchronized int getConfigInt(int item) throws RemoteException { - if (mProvisionedIntValue.containsKey(item)) { - return mProvisionedIntValue.get(item); - } else { - int retVal = getImsConfigImpl().getConfigInt(item); - if (retVal != ImsConfig.OperationStatusConstants.UNKNOWN) { - updateCachedValue(item, retVal, false); + public int getConfigInt(int item) throws RemoteException { + AtomicReference<RemoteException> exceptionRef = new AtomicReference<>(); + int retVal = executeMethodAsyncForResult(()-> { + int returnVal = ImsConfig.OperationStatusConstants.UNKNOWN; + synchronized (mLock) { + if (mProvisionedIntValue.containsKey(item)) { + return mProvisionedIntValue.get(item); + } else { + try { + returnVal = getImsConfigImpl().getConfigInt(item); + if (returnVal != ImsConfig.OperationStatusConstants.UNKNOWN) { + mProvisionedIntValue.put(item, returnVal); + } + } catch (RemoteException e) { + exceptionRef.set(e); + return returnVal; + } + } } - return retVal; + return returnVal; + }, "getConfigInt"); + + if (exceptionRef.get() != null) { + Log.d(TAG, "ImsConfigImplBase Exception getConfigString"); + throw exceptionRef.get(); } + + return retVal; } /** @@ -129,16 +183,34 @@ public class ImsConfigImplBase { * @return value in String format. */ @Override - public synchronized String getConfigString(int item) throws RemoteException { - if (mProvisionedStringValue.containsKey(item)) { - return mProvisionedStringValue.get(item); - } else { - String retVal = getImsConfigImpl().getConfigString(item); - if (retVal != null) { - updateCachedValue(item, retVal, false); + public String getConfigString(int item) throws RemoteException { + AtomicReference<RemoteException> exceptionRef = new AtomicReference<>(); + String retVal = executeMethodAsyncForResult(()-> { + String returnVal = null; + synchronized (mLock) { + if (mProvisionedStringValue.containsKey(item)) { + returnVal = mProvisionedStringValue.get(item); + } else { + try { + returnVal = getImsConfigImpl().getConfigString(item); + if (returnVal != null) { + mProvisionedStringValue.put(item, returnVal); + } + } catch (RemoteException e) { + exceptionRef.set(e); + return returnVal; + } + } } - return retVal; + return returnVal; + }, "getConfigString"); + + if (exceptionRef.get() != null) { + Log.d(TAG, "ImsConfigImplBase Exception getConfigString"); + throw exceptionRef.get(); } + + return retVal; } /** @@ -153,14 +225,32 @@ public class ImsConfigImplBase { * {@link #CONFIG_RESULT_FAILED} or {@link #CONFIG_RESULT_SUCCESS}. */ @Override - public synchronized int setConfigInt(int item, int value) throws RemoteException { - mProvisionedIntValue.remove(item); - int retVal = getImsConfigImpl().setConfig(item, value); - if (retVal == ImsConfig.OperationStatusConstants.SUCCESS) { - updateCachedValue(item, value, true); - } else { - Log.d(TAG, "Set provision value of " + item + - " to " + value + " failed with error code " + retVal); + public int setConfigInt(int item, int value) throws RemoteException { + AtomicReference<RemoteException> exceptionRef = new AtomicReference<>(); + int retVal = executeMethodAsyncForResult(()-> { + int returnVal = ImsConfig.OperationStatusConstants.UNKNOWN; + try { + synchronized (mLock) { + mProvisionedIntValue.remove(item); + returnVal = getImsConfigImpl().setConfig(item, value); + if (returnVal == ImsConfig.OperationStatusConstants.SUCCESS) { + mProvisionedIntValue.put(item, value); + } else { + Log.d(TAG, "Set provision value of " + item + + " to " + value + " failed with error code " + returnVal); + } + } + notifyImsConfigChanged(item, value); + return returnVal; + } catch (RemoteException e) { + exceptionRef.set(e); + return returnVal; + } + }, "setConfigInt"); + + if (exceptionRef.get() != null) { + Log.d(TAG, "ImsConfigImplBase Exception setConfigInt"); + throw exceptionRef.get(); } return retVal; @@ -178,12 +268,30 @@ public class ImsConfigImplBase { * {@link #CONFIG_RESULT_FAILED} or {@link #CONFIG_RESULT_SUCCESS}. */ @Override - public synchronized int setConfigString(int item, String value) + public int setConfigString(int item, String value) throws RemoteException { - mProvisionedStringValue.remove(item); - int retVal = getImsConfigImpl().setConfig(item, value); - if (retVal == ImsConfig.OperationStatusConstants.SUCCESS) { - updateCachedValue(item, value, true); + AtomicReference<RemoteException> exceptionRef = new AtomicReference<>(); + int retVal = executeMethodAsyncForResult(()-> { + int returnVal = ImsConfig.OperationStatusConstants.UNKNOWN; + try { + synchronized (mLock) { + mProvisionedStringValue.remove(item); + returnVal = getImsConfigImpl().setConfig(item, value); + if (returnVal == ImsConfig.OperationStatusConstants.SUCCESS) { + mProvisionedStringValue.put(item, value); + } + } + notifyImsConfigChanged(item, value); + return returnVal; + } catch (RemoteException e) { + exceptionRef.set(e); + return returnVal; + } + }, "setConfigString"); + + if (exceptionRef.get() != null) { + Log.d(TAG, "ImsConfigImplBase Exception setConfigInt"); + throw exceptionRef.get(); } return retVal; @@ -191,7 +299,19 @@ public class ImsConfigImplBase { @Override public void updateImsCarrierConfigs(PersistableBundle bundle) throws RemoteException { - getImsConfigImpl().updateImsCarrierConfigs(bundle); + AtomicReference<RemoteException> exceptionRef = new AtomicReference<>(); + executeMethodAsync(()-> { + try { + getImsConfigImpl().updateImsCarrierConfigs(bundle); + } catch (RemoteException e) { + exceptionRef.set(e); + } + }, "updateImsCarrierConfigs"); + + if (exceptionRef.get() != null) { + Log.d(TAG, "ImsConfigImplBase Exception updateImsCarrierConfigs"); + throw exceptionRef.get(); + } } private ImsConfigImplBase getImsConfigImpl() throws RemoteException { @@ -206,13 +326,37 @@ public class ImsConfigImplBase { @Override public void notifyRcsAutoConfigurationReceived(byte[] config, boolean isCompressed) throws RemoteException { - getImsConfigImpl().onNotifyRcsAutoConfigurationReceived(config, isCompressed); + AtomicReference<RemoteException> exceptionRef = new AtomicReference<>(); + executeMethodAsync(()-> { + try { + getImsConfigImpl().onNotifyRcsAutoConfigurationReceived(config, isCompressed); + } catch (RemoteException e) { + exceptionRef.set(e); + } + }, "notifyRcsAutoConfigurationReceived"); + + if (exceptionRef.get() != null) { + Log.d(TAG, "ImsConfigImplBase Exception notifyRcsAutoConfigurationReceived"); + throw exceptionRef.get(); + } } @Override public void notifyRcsAutoConfigurationRemoved() throws RemoteException { - getImsConfigImpl().onNotifyRcsAutoConfigurationRemoved(); + AtomicReference<RemoteException> exceptionRef = new AtomicReference<>(); + executeMethodAsync(()-> { + try { + getImsConfigImpl().onNotifyRcsAutoConfigurationRemoved(); + } catch (RemoteException e) { + exceptionRef.set(e); + } + }, "notifyRcsAutoConfigurationRemoved"); + + if (exceptionRef.get() != null) { + Log.d(TAG, "ImsConfigImplBase Exception notifyRcsAutoConfigurationRemoved"); + throw exceptionRef.get(); + } } private void notifyImsConfigChanged(int item, int value) throws RemoteException { @@ -223,50 +367,144 @@ public class ImsConfigImplBase { getImsConfigImpl().notifyConfigChanged(item, value); } - protected synchronized void updateCachedValue(int item, int value, boolean notifyChange) - throws RemoteException { - mProvisionedIntValue.put(item, value); - if (notifyChange) { - notifyImsConfigChanged(item, value); + protected void updateCachedValue(int item, int value) { + synchronized (mLock) { + mProvisionedIntValue.put(item, value); } } - protected synchronized void updateCachedValue(int item, String value, - boolean notifyChange) throws RemoteException { - mProvisionedStringValue.put(item, value); - if (notifyChange) { - notifyImsConfigChanged(item, value); + protected void updateCachedValue(int item, String value) { + synchronized (mLock) { + mProvisionedStringValue.put(item, value); } } @Override public void addRcsConfigCallback(IRcsConfigCallback c) throws RemoteException { - getImsConfigImpl().addRcsConfigCallback(c); + AtomicReference<RemoteException> exceptionRef = new AtomicReference<>(); + executeMethodAsync(()-> { + try { + getImsConfigImpl().addRcsConfigCallback(c); + } catch (RemoteException e) { + exceptionRef.set(e); + } + }, "addRcsConfigCallback"); + + if (exceptionRef.get() != null) { + Log.d(TAG, "ImsConfigImplBase Exception addRcsConfigCallback"); + throw exceptionRef.get(); + } } @Override public void removeRcsConfigCallback(IRcsConfigCallback c) throws RemoteException { - getImsConfigImpl().removeRcsConfigCallback(c); + AtomicReference<RemoteException> exceptionRef = new AtomicReference<>(); + executeMethodAsync(()-> { + try { + getImsConfigImpl().removeRcsConfigCallback(c); + } catch (RemoteException e) { + exceptionRef.set(e); + } + }, "removeRcsConfigCallback"); + + if (exceptionRef.get() != null) { + Log.d(TAG, "ImsConfigImplBase Exception removeRcsConfigCallback"); + throw exceptionRef.get(); + } } @Override public void triggerRcsReconfiguration() throws RemoteException { - getImsConfigImpl().triggerAutoConfiguration(); + AtomicReference<RemoteException> exceptionRef = new AtomicReference<>(); + executeMethodAsync(()-> { + try { + getImsConfigImpl().triggerAutoConfiguration(); + } catch (RemoteException e) { + exceptionRef.set(e); + } + }, "triggerRcsReconfiguration"); + + if (exceptionRef.get() != null) { + Log.d(TAG, "ImsConfigImplBase Exception triggerRcsReconfiguration"); + throw exceptionRef.get(); + } } @Override public void setRcsClientConfiguration(RcsClientConfiguration rcc) throws RemoteException { - getImsConfigImpl().setRcsClientConfiguration(rcc); + AtomicReference<RemoteException> exceptionRef = new AtomicReference<>(); + executeMethodAsync(()-> { + try { + getImsConfigImpl().setRcsClientConfiguration(rcc); + } catch (RemoteException e) { + exceptionRef.set(e); + } + }, "setRcsClientConfiguration"); + + if (exceptionRef.get() != null) { + Log.d(TAG, "ImsConfigImplBase Exception setRcsClientConfiguration"); + throw exceptionRef.get(); + } } @Override public void notifyIntImsConfigChanged(int item, int value) throws RemoteException { - notifyImsConfigChanged(item, value); + AtomicReference<RemoteException> exceptionRef = new AtomicReference<>(); + executeMethodAsync(()-> { + try { + notifyImsConfigChanged(item, value); + } catch (RemoteException e) { + exceptionRef.set(e); + } + }, "notifyIntImsConfigChanged"); + + if (exceptionRef.get() != null) { + Log.d(TAG, "ImsConfigImplBase Exception notifyIntImsConfigChanged"); + throw exceptionRef.get(); + } } @Override public void notifyStringImsConfigChanged(int item, String value) throws RemoteException { - notifyImsConfigChanged(item, value); + AtomicReference<RemoteException> exceptionRef = new AtomicReference<>(); + executeMethodAsync(()-> { + try { + notifyImsConfigChanged(item, value); + } catch (RemoteException e) { + exceptionRef.set(e); + } + }, "notifyStringImsConfigChanged"); + + if (exceptionRef.get() != null) { + Log.d(TAG, "ImsConfigImplBase Exception notifyStringImsConfigChanged"); + throw exceptionRef.get(); + } + } + + // Call the methods with a clean calling identity on the executor and wait indefinitely for + // the future to return. + private void executeMethodAsync(Runnable r, String errorLogName) throws RemoteException { + try { + CompletableFuture.runAsync( + () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join(); + } catch (CancellationException | CompletionException e) { + Log.w(TAG, "ImsConfigImplBase Binder - " + errorLogName + " exception: " + + e.getMessage()); + throw new RemoteException(e.getMessage()); + } + } + + private <T> T executeMethodAsyncForResult(Supplier<T> r, + String errorLogName) throws RemoteException { + CompletableFuture<T> future = CompletableFuture.supplyAsync( + () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor); + try { + return future.get(); + } catch (ExecutionException | InterruptedException e) { + Log.w(TAG, "ImsConfigImplBase Binder - " + errorLogName + " exception: " + + e.getMessage()); + throw new RemoteException(e.getMessage()); + } } } @@ -303,15 +541,24 @@ public class ImsConfigImplBase { ImsConfigStub mImsConfigStub; /** - * Used for compatibility between older versions of the ImsService. + * Create a ImsConfig using the Executor specified for methods being called by the + * framework. + * @param executor The executor for the framework to use when executing the methods overridden + * by the implementation of ImsConfig. + */ + public ImsConfigImplBase(@NonNull Executor executor) { + mImsConfigStub = new ImsConfigStub(this, executor); + } + + /** * @hide */ - public ImsConfigImplBase(Context context) { - mImsConfigStub = new ImsConfigStub(this); + public ImsConfigImplBase(@NonNull Context context) { + mImsConfigStub = new ImsConfigStub(this, null); } public ImsConfigImplBase() { - mImsConfigStub = new ImsConfigStub(this); + mImsConfigStub = new ImsConfigStub(this, null); } /** @@ -427,8 +674,10 @@ public class ImsConfigImplBase { * @param value in Integer format. */ public final void notifyProvisionedValueChanged(int item, int value) { + mImsConfigStub.updateCachedValue(item, value); + try { - mImsConfigStub.updateCachedValue(item, value, true); + mImsConfigStub.notifyImsConfigChanged(item, value); } catch (RemoteException e) { Log.w(TAG, "notifyProvisionedValueChanged(int): Framework connection is dead."); } @@ -443,8 +692,10 @@ public class ImsConfigImplBase { * @param value in String format. */ public final void notifyProvisionedValueChanged(int item, String value) { + mImsConfigStub.updateCachedValue(item, value); + try { - mImsConfigStub.updateCachedValue(item, value, true); + mImsConfigStub.notifyImsConfigChanged(item, value); } catch (RemoteException e) { Log.w(TAG, "notifyProvisionedValueChanged(string): Framework connection is dead."); } @@ -582,4 +833,16 @@ public class ImsConfigImplBase { } }); } + + /** + * Set default Executor from ImsService. + * @param executor The default executor for the framework to use when executing the methods + * overridden by the implementation of ImsConfig. + * @hide + */ + public final void setDefaultExecutor(@NonNull Executor executor) { + if (mImsConfigStub.mExecutor == null) { + mImsConfigStub.mExecutor = executor; + } + } } diff --git a/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java index 8ad40ed1032c..84b2253e1b27 100644 --- a/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java @@ -16,14 +16,21 @@ package android.telephony.ims.stub; +import android.annotation.NonNull; import android.annotation.SystemApi; import android.os.RemoteException; import android.util.Log; import com.android.ims.internal.IImsEcbm; import com.android.ims.internal.IImsEcbmListener; +import com.android.internal.telephony.util.TelephonyUtils; import java.util.Objects; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.Executor; + /** * Base implementation of ImsEcbm, which implements stub versions of the methods @@ -40,10 +47,12 @@ public class ImsEcbmImplBase { private final Object mLock = new Object(); private IImsEcbmListener mListener; + private Executor mExecutor = Runnable::run; + private final IImsEcbm mImsEcbm = new IImsEcbm.Stub() { @Override public void setListener(IImsEcbmListener listener) { - synchronized (mLock) { + executeMethodAsync(() -> { if (mListener != null && !mListener.asBinder().isBinderAlive()) { Log.w(TAG, "setListener: discarding dead Binder"); mListener = null; @@ -62,12 +71,25 @@ public class ImsEcbmImplBase { + "listener"); mListener = listener; } - } + }, "setListener"); } @Override public void exitEmergencyCallbackMode() { - ImsEcbmImplBase.this.exitEmergencyCallbackMode(); + executeMethodAsync(() -> ImsEcbmImplBase.this.exitEmergencyCallbackMode(), + "exitEmergencyCallbackMode"); + } + + // Call the methods with a clean calling identity on the executor and wait indefinitely for + // the future to return. + private void executeMethodAsync(Runnable r, String errorLogName) { + try { + CompletableFuture.runAsync( + () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join(); + } catch (CancellationException | CompletionException e) { + Log.w(TAG, "ImsEcbmImplBase Binder - " + errorLogName + " exception: " + + e.getMessage()); + } } }; @@ -123,4 +145,14 @@ public class ImsEcbmImplBase { } } } + + /** + * Set default Executor from MmTelFeature. + * @param executor The default executor for the framework to use when executing the methods + * overridden by the implementation of ImsEcbm. + * @hide + */ + public final void setDefaultExecutor(@NonNull Executor executor) { + mExecutor = executor; + } } diff --git a/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java index ec1c7b3a92a8..a723cd8b118c 100644 --- a/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java @@ -16,6 +16,7 @@ package android.telephony.ims.stub; +import android.annotation.NonNull; import android.annotation.SystemApi; import android.os.RemoteException; import android.telephony.ims.ImsExternalCallState; @@ -23,9 +24,14 @@ import android.util.Log; import com.android.ims.internal.IImsExternalCallStateListener; import com.android.ims.internal.IImsMultiEndpoint; +import com.android.internal.telephony.util.TelephonyUtils; import java.util.List; import java.util.Objects; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.Executor; /** * Base implementation of ImsMultiEndpoint, which implements stub versions of the methods @@ -43,11 +49,13 @@ public class ImsMultiEndpointImplBase { private IImsExternalCallStateListener mListener; private final Object mLock = new Object(); + private Executor mExecutor = Runnable::run; + private final IImsMultiEndpoint mImsMultiEndpoint = new IImsMultiEndpoint.Stub() { @Override public void setListener(IImsExternalCallStateListener listener) throws RemoteException { - synchronized (mLock) { + executeMethodAsync(() -> { if (mListener != null && !mListener.asBinder().isBinderAlive()) { Log.w(TAG, "setListener: discarding dead Binder"); mListener = null; @@ -67,12 +75,25 @@ public class ImsMultiEndpointImplBase { + "listener"); mListener = listener; } - } + }, "setListener"); } @Override public void requestImsExternalCallStateInfo() throws RemoteException { - ImsMultiEndpointImplBase.this.requestImsExternalCallStateInfo(); + executeMethodAsync(() -> ImsMultiEndpointImplBase.this + .requestImsExternalCallStateInfo(), "requestImsExternalCallStateInfo"); + } + + // Call the methods with a clean calling identity on the executor and wait indefinitely for + // the future to return. + private void executeMethodAsync(Runnable r, String errorLogName) { + try { + CompletableFuture.runAsync( + () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join(); + } catch (CancellationException | CompletionException e) { + Log.w(TAG, "ImsMultiEndpointImplBase Binder - " + errorLogName + " exception: " + + e.getMessage()); + } } }; @@ -108,4 +129,14 @@ public class ImsMultiEndpointImplBase { public void requestImsExternalCallStateInfo() { Log.d(TAG, "requestImsExternalCallStateInfo() not implemented"); } + + /** + * Set default Executor from MmTelFeature. + * @param executor The default executor for the framework to use when executing the methods + * overridden by the implementation of ImsMultiEndpoint. + * @hide + */ + public final void setDefaultExecutor(@NonNull Executor executor) { + mExecutor = executor; + } } diff --git a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java index 02bcdec621c1..ac5565bea810 100644 --- a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java @@ -31,10 +31,18 @@ import android.telephony.ims.aidl.IImsRegistrationCallback; import android.util.Log; import com.android.internal.telephony.util.RemoteCallbackListExt; +import com.android.internal.telephony.util.TelephonyUtils; import com.android.internal.util.ArrayUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; /** * Controls IMS registration for this ImsService and notifies the framework when the IMS @@ -42,9 +50,7 @@ import java.lang.annotation.RetentionPolicy; * <p> * Note: There is no guarantee on the thread that the calls from the framework will be called on. It * is the implementors responsibility to handle moving the calls to a working thread if required. - * @hide */ -@SystemApi public class ImsRegistrationImplBase { private static final String LOG_TAG = "ImsRegistrationImplBase"; @@ -85,6 +91,12 @@ public class ImsRegistrationImplBase { */ public static final int REGISTRATION_TECH_NR = 3; + /** + * This is used to check the upper range of registration tech + * {@hide} + */ + public static final int REGISTRATION_TECH_MAX = REGISTRATION_TECH_NR + 1; + // Registration states, used to notify new ImsRegistrationImplBase#Callbacks of the current // state. // The unknown state is set as the initialization state. This is so that we do not call back @@ -92,39 +104,118 @@ public class ImsRegistrationImplBase { // yet. private static final int REGISTRATION_STATE_UNKNOWN = -1; + private Executor mExecutor; + + /** + * Create a new ImsRegistration. + * <p> + * Method stubs called from the framework will be called asynchronously. To specify the + * {@link Executor} that the methods stubs will be called, use + * {@link ImsRegistrationImplBase#ImsRegistrationImplBase(Executor)} instead. + * @hide This API is not part of the Android public SDK API + */ + @SystemApi + public ImsRegistrationImplBase() { + super(); + } + + /** + * Create a ImsRegistration using the Executor specified for methods being called by the + * framework. + * @param executor The executor for the framework to use when executing the methods overridden + * by the implementation of ImsRegistration. + * @hide This API is not part of the Android public SDK API + */ + @SystemApi + public ImsRegistrationImplBase(@NonNull Executor executor) { + super(); + mExecutor = executor; + } + private final IImsRegistration mBinder = new IImsRegistration.Stub() { @Override public @ImsRegistrationTech int getRegistrationTechnology() throws RemoteException { - synchronized (mLock) { - return (mRegistrationAttributes == null) ? REGISTRATION_TECH_NONE - : mRegistrationAttributes.getRegistrationTechnology(); - } + return executeMethodAsyncForResult(() -> (mRegistrationAttributes == null) + ? REGISTRATION_TECH_NONE : mRegistrationAttributes.getRegistrationTechnology(), + "getRegistrationTechnology"); } @Override public void addRegistrationCallback(IImsRegistrationCallback c) throws RemoteException { - ImsRegistrationImplBase.this.addRegistrationCallback(c); + AtomicReference<RemoteException> exceptionRef = new AtomicReference<>(); + executeMethodAsync(() -> { + try { + ImsRegistrationImplBase.this.addRegistrationCallback(c); + } catch (RemoteException e) { + exceptionRef.set(e); + } + }, "addRegistrationCallback"); + + if (exceptionRef.get() != null) { + throw exceptionRef.get(); + } } @Override public void removeRegistrationCallback(IImsRegistrationCallback c) throws RemoteException { - ImsRegistrationImplBase.this.removeRegistrationCallback(c); + executeMethodAsync(() -> ImsRegistrationImplBase.this.removeRegistrationCallback(c), + "removeRegistrationCallback"); } @Override public void triggerFullNetworkRegistration(int sipCode, String sipReason) { - ImsRegistrationImplBase.this.triggerFullNetworkRegistration(sipCode, sipReason); + executeMethodAsyncNoException(() -> ImsRegistrationImplBase.this + .triggerFullNetworkRegistration(sipCode, sipReason), + "triggerFullNetworkRegistration"); } @Override public void triggerUpdateSipDelegateRegistration() { - ImsRegistrationImplBase.this.updateSipDelegateRegistration(); + executeMethodAsyncNoException(() -> ImsRegistrationImplBase.this + .updateSipDelegateRegistration(), "triggerUpdateSipDelegateRegistration"); } @Override public void triggerSipDelegateDeregistration() { - ImsRegistrationImplBase.this.triggerSipDelegateDeregistration(); + executeMethodAsyncNoException(() -> ImsRegistrationImplBase.this + .triggerSipDelegateDeregistration(), "triggerSipDelegateDeregistration"); + } + + // Call the methods with a clean calling identity on the executor and wait indefinitely for + // the future to return. + private void executeMethodAsync(Runnable r, String errorLogName) throws RemoteException { + try { + CompletableFuture.runAsync( + () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join(); + } catch (CancellationException | CompletionException e) { + Log.w(LOG_TAG, "ImsRegistrationImplBase Binder - " + errorLogName + " exception: " + + e.getMessage()); + throw new RemoteException(e.getMessage()); + } + } + + private void executeMethodAsyncNoException(Runnable r, String errorLogName) { + try { + CompletableFuture.runAsync( + () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join(); + } catch (CancellationException | CompletionException e) { + Log.w(LOG_TAG, "ImsRegistrationImplBase Binder - " + errorLogName + " exception: " + + e.getMessage()); + } + } + + private <T> T executeMethodAsyncForResult(Supplier<T> r, + String errorLogName) throws RemoteException { + CompletableFuture<T> future = CompletableFuture.supplyAsync( + () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor); + try { + return future.get(); + } catch (ExecutionException | InterruptedException e) { + Log.w(LOG_TAG, "ImsRegistrationImplBase Binder - " + errorLogName + " exception: " + + e.getMessage()); + throw new RemoteException(e.getMessage()); + } } }; @@ -166,7 +257,9 @@ public class ImsRegistrationImplBase { * If the SIP delegate feature tag configuration has changed, then this method will be * called in order to let the ImsService know that it can pick up these changes in the IMS * registration. + * @hide This API is not part of the Android public SDK API */ + @SystemApi public void updateSipDelegateRegistration() { // Stub implementation, ImsService should implement this } @@ -182,7 +275,9 @@ public class ImsRegistrationImplBase { * <p> * This should not affect the registration of features managed by the ImsService itself, such as * feature tags related to MMTEL registration. + * @hide This API is not part of the Android public SDK API */ + @SystemApi public void triggerSipDelegateDeregistration() { // Stub implementation, ImsService should implement this } @@ -200,7 +295,9 @@ public class ImsRegistrationImplBase { * be carrier specific. * @param sipReason The reason associated with the SIP error code. {@code null} if there was no * reason associated with the error. + * @hide This API is not part of the Android public SDK API */ + @SystemApi public void triggerFullNetworkRegistration(@IntRange(from = 100, to = 699) int sipCode, @Nullable String sipReason) { // Stub implementation, ImsService should implement this @@ -211,7 +308,9 @@ public class ImsRegistrationImplBase { * Notify the framework that the device is connected to the IMS network. * * @param imsRadioTech the radio access technology. + * @hide This API is not part of the Android public SDK API */ + @SystemApi public final void onRegistered(@ImsRegistrationTech int imsRadioTech) { onRegistered(new ImsRegistrationAttributes.Builder(imsRadioTech).build()); } @@ -220,7 +319,9 @@ public class ImsRegistrationImplBase { * Notify the framework that the device is connected to the IMS network. * * @param attributes The attributes associated with the IMS registration. + * @hide This API is not part of the Android public SDK API */ + @SystemApi public final void onRegistered(@NonNull ImsRegistrationAttributes attributes) { updateToState(attributes, RegistrationManager.REGISTRATION_STATE_REGISTERED); mCallbacks.broadcastAction((c) -> { @@ -236,7 +337,9 @@ public class ImsRegistrationImplBase { * Notify the framework that the device is trying to connect the IMS network. * * @param imsRadioTech the radio access technology. + * @hide This API is not part of the Android public SDK API */ + @SystemApi public final void onRegistering(@ImsRegistrationTech int imsRadioTech) { onRegistering(new ImsRegistrationAttributes.Builder(imsRadioTech).build()); } @@ -245,7 +348,9 @@ public class ImsRegistrationImplBase { * Notify the framework that the device is trying to connect the IMS network. * * @param attributes The attributes associated with the IMS registration. + * @hide This API is not part of the Android public SDK API */ + @SystemApi public final void onRegistering(@NonNull ImsRegistrationAttributes attributes) { updateToState(attributes, RegistrationManager.REGISTRATION_STATE_REGISTERING); mCallbacks.broadcastAction((c) -> { @@ -272,7 +377,9 @@ public class ImsRegistrationImplBase { * result. * * @param info the {@link ImsReasonInfo} associated with why registration was disconnected. + * @hide This API is not part of the Android public SDK API */ + @SystemApi public final void onDeregistered(ImsReasonInfo info) { updateToDisconnectedState(info); // ImsReasonInfo should never be null. @@ -293,7 +400,9 @@ public class ImsRegistrationImplBase { * {@link #REGISTRATION_TECH_LTE}, {@link #REGISTRATION_TECH_IWLAN} and * {@link #REGISTRATION_TECH_CROSS_SIM}. * @param info The {@link ImsReasonInfo} for the failure to change technology. + * @hide This API is not part of the Android public SDK API */ + @SystemApi public final void onTechnologyChangeFailed(@ImsRegistrationTech int imsRadioTech, ImsReasonInfo info) { final ImsReasonInfo reasonInfo = (info != null) ? info : new ImsReasonInfo(); @@ -312,7 +421,9 @@ public class ImsRegistrationImplBase { * * The {@link Uri}s are not guaranteed to be different between subsequent calls. * @param uris changed uris + * @hide This API is not part of the Android public SDK API */ + @SystemApi public final void onSubscriberAssociatedUriChanged(Uri[] uris) { synchronized (mLock) { mUris = ArrayUtils.cloneOrNull(uris); @@ -394,4 +505,16 @@ public class ImsRegistrationImplBase { onSubscriberAssociatedUriChanged(c, uris); } } + + /** + * Set default Executor from ImsService. + * @param executor The default executor for the framework to use when executing the methods + * overridden by the implementation of Registration. + * @hide + */ + public final void setDefaultExecutor(@NonNull Executor executor) { + if (mExecutor == null) { + mExecutor = executor; + } + } } diff --git a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java index eb3e8ed5a8e4..11cdeed10c5a 100644 --- a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java @@ -27,10 +27,17 @@ import android.util.Log; import com.android.ims.internal.IImsUt; import com.android.ims.internal.IImsUtListener; +import com.android.internal.telephony.util.TelephonyUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Objects; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.function.Supplier; /** * Base implementation of IMS UT interface, which implements stubs. Override these methods to @@ -119,96 +126,108 @@ public class ImsUtImplBase { */ public static final int INVALID_RESULT = -1; + private Executor mExecutor = Runnable::run; + private final IImsUt.Stub mServiceImpl = new IImsUt.Stub() { private final Object mLock = new Object(); private ImsUtListener mUtListener; @Override public void close() throws RemoteException { - ImsUtImplBase.this.close(); + executeMethodAsync(() ->ImsUtImplBase.this.close(), "close"); } @Override public int queryCallBarring(int cbType) throws RemoteException { - return ImsUtImplBase.this.queryCallBarring(cbType); + return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCallBarring(cbType), + "queryCallBarring"); } @Override public int queryCallForward(int condition, String number) throws RemoteException { - return ImsUtImplBase.this.queryCallForward(condition, number); + return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCallForward( + condition, number), "queryCallForward"); } @Override public int queryCallWaiting() throws RemoteException { - return ImsUtImplBase.this.queryCallWaiting(); + return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCallWaiting(), + "queryCallWaiting"); } @Override public int queryCLIR() throws RemoteException { - return ImsUtImplBase.this.queryCLIR(); + return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCLIR(), "queryCLIR"); } @Override public int queryCLIP() throws RemoteException { - return ImsUtImplBase.this.queryCLIP(); + return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCLIP(), "queryCLIP"); } @Override public int queryCOLR() throws RemoteException { - return ImsUtImplBase.this.queryCOLR(); + return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCOLR(), "queryCOLR"); } @Override public int queryCOLP() throws RemoteException { - return ImsUtImplBase.this.queryCOLP(); + return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCOLP(), "queryCOLP"); } @Override public int transact(Bundle ssInfo) throws RemoteException { - return ImsUtImplBase.this.transact(ssInfo); + return executeMethodAsyncForResult(() -> ImsUtImplBase.this.transact(ssInfo), + "transact"); } @Override public int updateCallBarring(int cbType, int action, String[] barrList) throws RemoteException { - return ImsUtImplBase.this.updateCallBarring(cbType, action, barrList); + return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCallBarring( + cbType, action, barrList), "updateCallBarring"); } @Override public int updateCallForward(int action, int condition, String number, int serviceClass, int timeSeconds) throws RemoteException { - return ImsUtImplBase.this.updateCallForward(action, condition, number, serviceClass, - timeSeconds); + return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCallForward( + action, condition, number, serviceClass, timeSeconds), "updateCallForward"); } @Override public int updateCallWaiting(boolean enable, int serviceClass) throws RemoteException { - return ImsUtImplBase.this.updateCallWaiting(enable, serviceClass); + return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCallWaiting( + enable, serviceClass), "updateCallWaiting"); } @Override public int updateCLIR(int clirMode) throws RemoteException { - return ImsUtImplBase.this.updateCLIR(clirMode); + return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCLIR(clirMode), + "updateCLIR"); } @Override public int updateCLIP(boolean enable) throws RemoteException { - return ImsUtImplBase.this.updateCLIP(enable); + return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCLIP(enable), + "updateCLIP"); } @Override public int updateCOLR(int presentation) throws RemoteException { - return ImsUtImplBase.this.updateCOLR(presentation); + return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCOLR(presentation), + "updateCOLR"); } @Override public int updateCOLP(boolean enable) throws RemoteException { - return ImsUtImplBase.this.updateCOLP(enable); + return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCOLP(enable), + "updateCOLP"); } @Override public void setListener(IImsUtListener listener) throws RemoteException { - synchronized (mLock) { + executeMethodAsync(() -> { if (mUtListener != null && !mUtListener.getListenerInterface().asBinder().isBinderAlive()) { Log.w(TAG, "setListener: discarding dead Binder"); @@ -229,29 +248,59 @@ public class ImsUtImplBase { + "listener"); mUtListener = new ImsUtListener(listener); } - } - ImsUtImplBase.this.setListener(mUtListener); + ImsUtImplBase.this.setListener(mUtListener); + }, "setListener"); } @Override public int queryCallBarringForServiceClass(int cbType, int serviceClass) throws RemoteException { - return ImsUtImplBase.this.queryCallBarringForServiceClass(cbType, serviceClass); + return executeMethodAsyncForResult(() -> ImsUtImplBase.this + .queryCallBarringForServiceClass(cbType, serviceClass), + "queryCallBarringForServiceClass"); } @Override public int updateCallBarringForServiceClass(int cbType, int action, String[] barrList, int serviceClass) throws RemoteException { - return ImsUtImplBase.this.updateCallBarringForServiceClass( - cbType, action, barrList, serviceClass); + return executeMethodAsyncForResult(() -> ImsUtImplBase.this + .updateCallBarringForServiceClass(cbType, action, barrList, serviceClass), + "updateCallBarringForServiceClass"); } @Override public int updateCallBarringWithPassword(int cbType, int action, String[] barrList, int serviceClass, String password) throws RemoteException { - return ImsUtImplBase.this.updateCallBarringWithPassword( - cbType, action, barrList, serviceClass, password); + return executeMethodAsyncForResult(() -> ImsUtImplBase.this + .updateCallBarringWithPassword(cbType, action, barrList, serviceClass, + password), "updateCallBarringWithPassword"); + } + + // Call the methods with a clean calling identity on the executor and wait indefinitely for + // the future to return. + private void executeMethodAsync(Runnable r, String errorLogName) throws RemoteException { + try { + CompletableFuture.runAsync( + () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join(); + } catch (CancellationException | CompletionException e) { + Log.w(TAG, "ImsUtImplBase Binder - " + errorLogName + " exception: " + + e.getMessage()); + throw new RemoteException(e.getMessage()); + } + } + + private <T> T executeMethodAsyncForResult(Supplier<T> r, + String errorLogName) throws RemoteException { + CompletableFuture<T> future = CompletableFuture.supplyAsync( + () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor); + try { + return future.get(); + } catch (ExecutionException | InterruptedException e) { + Log.w(TAG, "ImsUtImplBase Binder - " + errorLogName + " exception: " + + e.getMessage()); + throw new RemoteException(e.getMessage()); + } } }; @@ -470,4 +519,14 @@ public class ImsUtImplBase { public IImsUt getInterface() { return mServiceImpl; } + + /** + * Set default Executor from MmTelFeature. + * @param executor The default executor for the framework to use when executing the methods + * overridden by the implementation of ImsUT. + * @hide + */ + public final void setDefaultExecutor(@NonNull Executor executor) { + mExecutor = executor; + } } diff --git a/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java b/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java index 13ea99735ab4..52538cb4e2df 100644 --- a/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java +++ b/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java @@ -86,10 +86,21 @@ public class SipTransportImplBase { } }; - private final Executor mBinderExecutor; + private Executor mBinderExecutor; private final ArrayList<SipDelegateAidlWrapper> mDelegates = new ArrayList<>(); /** + * Create a new SipTransport. + * <p> + * Method stubs called from the framework will be called asynchronously. To specify the + * {@link Executor} that the methods stubs will be called, use + * {@link SipTransportImplBase#SipTransportImplBase(Executor)} instead. + */ + public SipTransportImplBase() { + super(); + } + + /** * Create an implementation of SipTransportImplBase. * * @param executor The executor that remote calls from the framework will be called on. This @@ -212,4 +223,16 @@ public class SipTransportImplBase { public ISipTransport getBinder() { return mSipTransportImpl; } + + /** + * Set default Executor from ImsService. + * @param executor The default executor for the framework to use when executing the methods + * overridden by the implementation of SipTransport. + * @hide + */ + public final void setDefaultExecutor(@NonNull Executor executor) { + if (mBinderExecutor == null) { + mBinderExecutor = executor; + } + } } diff --git a/telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl b/telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl index f5f67bd36ec3..416096b1f6ec 100644 --- a/telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl +++ b/telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl @@ -23,11 +23,11 @@ import com.android.ims.ImsFeatureContainer; * {@hide} */ oneway interface IImsServiceFeatureCallback { - void imsFeatureCreated(in ImsFeatureContainer feature); + void imsFeatureCreated(in ImsFeatureContainer feature, int subId); // Reason defined in FeatureConnector.UnavailableReason void imsFeatureRemoved(int reason); // Status defined in ImsFeature.ImsState. - void imsStatusChanged(int status); + void imsStatusChanged(int status, int subId); //Capabilities defined in ImsService.ImsServiceCapability void updateCapabilities(long capabilities); }
\ No newline at end of file diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 167aa07f3ac2..0ac7cf957ecf 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -55,6 +55,7 @@ import android.telephony.VisualVoicemailSmsFilterSettings; import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.RcsClientConfiguration; import android.telephony.ims.RcsContactUceCapability; +import android.telephony.ims.aidl.IFeatureProvisioningCallback; import android.telephony.ims.aidl.IImsCapabilityCallback; import android.telephony.ims.aidl.IImsConfig; import android.telephony.ims.aidl.IImsConfigCallback; @@ -2027,6 +2028,18 @@ interface ITelephony { void unregisterImsProvisioningChangedCallback(int subId, IImsConfigCallback callback); /** + * Register an IMS provisioning change callback with Telephony. + */ + void registerFeatureProvisioningChangedCallback(int subId, + IFeatureProvisioningCallback callback); + + /** + * unregister an existing IMS provisioning change callback. + */ + void unregisterFeatureProvisioningChangedCallback(int subId, + IFeatureProvisioningCallback callback); + + /** * Set the provisioning status for the IMS MmTel capability using the specified subscription. */ void setImsProvisioningStatusForCapability(int subId, int capability, int tech, @@ -2040,19 +2053,12 @@ interface ITelephony { /** * Get the provisioning status for the IMS Rcs capability specified. */ - boolean getRcsProvisioningStatusForCapability(int subId, int capability); + boolean getRcsProvisioningStatusForCapability(int subId, int capability, int tech); /** * Set the provisioning status for the IMS Rcs capability using the specified subscription. */ - void setRcsProvisioningStatusForCapability(int subId, int capability, - boolean isProvisioned); - - /** Is the capability and tech flagged as provisioned in the cache */ - boolean isMmTelCapabilityProvisionedInCache(int subId, int capability, int tech); - - /** Set the provisioning for the capability and tech in the cache */ - void cacheMmTelCapabilityProvisioning(int subId, int capability, int tech, + void setRcsProvisioningStatusForCapability(int subId, int capability, int tech, boolean isProvisioned); /** @@ -2555,4 +2561,18 @@ interface ITelephony { * @return the service name of the modem service which bind to. */ String getModemService(); + + /** + * Is Provisioning required for capability + * @return true if provisioning is required for the MMTEL capability and IMS + * registration technology specified, false if it is not required. + */ + boolean isProvisioningRequiredForCapability(int subId, int capability, int tech); + + /** + * Is RCS Provisioning required for capability + * @return true if provisioning is required for the RCS capability and IMS + * registration technology specified, false if it is not required. + */ + boolean isRcsProvisioningRequiredForCapability(int subId, int capability, int tech); } diff --git a/test-base/Android.bp b/test-base/Android.bp index 8be732452228..527159a78ebf 100644 --- a/test-base/Android.bp +++ b/test-base/Android.bp @@ -72,11 +72,16 @@ java_sdk_library { // Build the android.test.base_static library // ========================================== -// This is only intended for inclusion in the android.test.runner-minus-junit, -// robolectric_android-all-stub and repackaged.android.test.* libraries. +// This is only intended for use by the android.test.runner-minus-junit +// library. +// // Must not be used elsewhere. +// java_library_static { name: "android.test.base_static", + visibility: [ + "//frameworks/base/test-runner", + ], installable: false, srcs: [":android-test-base-sources"], @@ -91,28 +96,10 @@ java_library_static { sdk_version: "current", } -// Build the repackaged.android.test.base library -// ============================================== -// This contains repackaged versions of the classes from -// android.test.base. -java_library_static { - name: "repackaged.android.test.base", - - sdk_version: "current", - static_libs: ["android.test.base_static"], - - jarjar_rules: "jarjar-rules.txt", - // Pin java_version until jarjar is certified to support later versions. http://b/72703434 - java_version: "1.8", -} - // Build the android.test.base-minus-junit library // =============================================== // This contains the android.test classes from android.test.base plus -// the com.android.internal.util.Predicate[s] classes. This is only -// intended for inclusion in android.test.legacy and in -// android.test.base-hiddenapi-annotations to avoid a dependency cycle and must -// not be used elsewhere. +// the com.android.internal.util.Predicate[s] classes. java_library_static { name: "android.test.base-minus-junit", diff --git a/test-base/jarjar-rules.txt b/test-base/jarjar-rules.txt deleted file mode 100644 index fd8555c8931c..000000000000 --- a/test-base/jarjar-rules.txt +++ /dev/null @@ -1,3 +0,0 @@ -rule junit.** repackaged.junit.@1 -rule android.test.** repackaged.android.test.@1 -rule com.android.internal.util.** repackaged.com.android.internal.util.@1 diff --git a/test-runner/Android.bp b/test-runner/Android.bp index 2a19af9f8cd2..13a5dac9eb38 100644 --- a/test-runner/Android.bp +++ b/test-runner/Android.bp @@ -79,32 +79,6 @@ java_library { ], } -// Build the repackaged.android.test.runner library -// ================================================ -java_library_static { - name: "repackaged.android.test.runner", - - srcs: [":android-test-runner-sources"], - exclude_srcs: [ - "src/android/test/ActivityUnitTestCase.java", - "src/android/test/ApplicationTestCase.java", - "src/android/test/IsolatedContext.java", - "src/android/test/ProviderTestCase.java", - "src/android/test/ProviderTestCase2.java", - "src/android/test/RenamingDelegatingContext.java", - "src/android/test/ServiceTestCase.java", - ], - - sdk_version: "current", - libs: [ - "android.test.base_static", - ], - - jarjar_rules: "jarjar-rules.txt", - // Pin java_version until jarjar is certified to support later versions. http://b/72703434 - java_version: "1.8", -} - // Make the current.txt available for use by the cts/tests/signature tests. // ======================================================================== filegroup { diff --git a/test-runner/jarjar-rules.txt b/test-runner/jarjar-rules.txt deleted file mode 120000 index f6f79139d511..000000000000 --- a/test-runner/jarjar-rules.txt +++ /dev/null @@ -1 +0,0 @@ -../test-base/jarjar-rules.txt
\ No newline at end of file diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/Android.bp b/tests/Camera2Tests/SmartCamera/SimpleCamera/Android.bp new file mode 100644 index 000000000000..4fff969359c8 --- /dev/null +++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/Android.bp @@ -0,0 +1,34 @@ +// Copyright (C) 2013 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 { + // See: http://go/android-license-faq + default_applicable_licenses: [ + "frameworks_base_license", + ], +} + +android_test { + name: "SmartCamera", + optimize: { + enabled: false, + }, + // comment it out for now since we need use some hidden APIs + sdk_version: "current", + static_libs: ["android-ex-camera2"], + srcs: [ + "src/**/*.java", + ], + jni_libs: ["libsmartcamera_jni"], +} diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/Android.mk b/tests/Camera2Tests/SmartCamera/SimpleCamera/Android.mk deleted file mode 100644 index 6003628ffb0d..000000000000 --- a/tests/Camera2Tests/SmartCamera/SimpleCamera/Android.mk +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright (C) 2013 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. - -ifneq ($(TARGET_BUILD_JAVA_SUPPORT_LEVEL),) - -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE_TAGS := tests - -LOCAL_PROGUARD_ENABLED := disabled - -# comment it out for now since we need use some hidden APIs -LOCAL_SDK_VERSION := current - -LOCAL_STATIC_JAVA_LIBRARIES := android-ex-camera2 - -LOCAL_SRC_FILES := \ - $(call all-java-files-under, src) \ - $(call all-renderscript-files-under, src) - -LOCAL_PACKAGE_NAME := SmartCamera -LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 -LOCAL_LICENSE_CONDITIONS := notice -LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../../NOTICE -LOCAL_JNI_SHARED_LIBRARIES := libsmartcamera_jni - -include $(BUILD_PACKAGE) - -# Include packages in subdirectories -include $(call all-makefiles-under,$(LOCAL_PATH)) - -endif diff --git a/tests/benchmarks/Android.bp b/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.bp index f87ca2ef928b..5edb1de9586e 100644 --- a/tests/benchmarks/Android.bp +++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.bp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 The Android Open Source Project +// Copyright (C) 2013 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. @@ -11,28 +11,26 @@ // 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. - -// build framework base core benchmarks -// ============================================================ +// package { // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "frameworks_base_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["frameworks_base_license"], + default_applicable_licenses: [ + "frameworks_base_license", + ], } -java_library { - name: "networkStatsFactory-benchmarks", - installable: true, - +android_test { + name: "SmartCamera-tests", + platform_apis: true, srcs: ["src/**/*.java"], - - libs: [ - "caliper-api-target", - "services.core", + libs: ["android.test.base"], + static_libs: [ + "guava", + "junit", ], - + optimize: { + enabled: false, + }, + instrumentation_for: "SmartCamera", } diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk b/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk deleted file mode 100644 index c23d593d4f86..000000000000 --- a/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright (C) 2013 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. -# - -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_MODULE_TAGS := tests - -# LOCAL_SDK_VERSION := current -LOCAL_PRIVATE_PLATFORM_APIS := true - -LOCAL_PACKAGE_NAME := SmartCamera-tests -LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 -LOCAL_LICENSE_CONDITIONS := notice -LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../../../NOTICE - -LOCAL_SRC_FILES += $(call all-java-files-under, src) - -LOCAL_JAVA_LIBRARIES := android.test.base -LOCAL_STATIC_JAVA_LIBRARIES := guava junit - -LOCAL_PROGUARD_ENABLED := disabled - -LOCAL_INSTRUMENTATION_FOR := SmartCamera - -include $(BUILD_PACKAGE) diff --git a/tests/CanvasCompare/Android.bp b/tests/CanvasCompare/Android.bp new file mode 100644 index 000000000000..98831154ddc2 --- /dev/null +++ b/tests/CanvasCompare/Android.bp @@ -0,0 +1,63 @@ +// +// Copyright (C) 2012 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 { + // See: http://go/android-license-faq + default_applicable_licenses: [ + "frameworks_base_license", + ], +} + +android_test { + name: "CanvasCompare", + srcs: [ + "src/**/*.java", + ":CanvasCompare-rscript{CanvasCompare.srcjar}", + ], + resource_zips: [ + ":CanvasCompare-rscript{CanvasCompare.res.zip}", + ], + platform_apis: true, + libs: [ + "android.test.runner", + "android.test.base", + ], + static_libs: ["junit"], +} + +genrule { + name: "CanvasCompare-rscript", + srcs: [ + "src/**/*.rscript", + ":rs_script_api", + ":rs_clang_headers", + ], + tools: [ + "llvm-rs-cc", + "soong_zip", + ], + out: [ + "CanvasCompare.srcjar", + "CanvasCompare.res.zip", + ], + cmd: "for f in $(locations src/**/*.rscript); do " + + " $(location llvm-rs-cc) -o $(genDir)/res/raw -p $(genDir)/src " + + " -I $$(dirname $$(echo $(locations :rs_script_api) | awk '{ print $$1 }')) " + + " -I $$(dirname $$(echo $(locations :rs_clang_headers) | awk '{ print $$1 }')) $${f}; " + + "done && " + + "$(location soong_zip) -srcjar -o $(location CanvasCompare.srcjar) -C $(genDir)/src -D $(genDir)/src &&" + + "$(location soong_zip) -o $(location CanvasCompare.res.zip) -C $(genDir)/res -D $(genDir)/res", +} diff --git a/tests/CanvasCompare/Android.mk b/tests/CanvasCompare/Android.mk deleted file mode 100644 index b82ae65b4356..000000000000 --- a/tests/CanvasCompare/Android.mk +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright (C) 2012 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. -# - -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src) - -LOCAL_PACKAGE_NAME := CanvasCompare -LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 -LOCAL_LICENSE_CONDITIONS := notice -LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE -LOCAL_PRIVATE_PLATFORM_APIS := true - -LOCAL_MODULE_TAGS := tests - -LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base -LOCAL_STATIC_JAVA_LIBRARIES := junit - -include $(BUILD_PACKAGE) diff --git a/tests/SilkFX/AndroidManifest.xml b/tests/SilkFX/AndroidManifest.xml index c30d76137f76..21256d8c9d0b 100644 --- a/tests/SilkFX/AndroidManifest.xml +++ b/tests/SilkFX/AndroidManifest.xml @@ -20,17 +20,20 @@ <uses-sdk android:minSdkVersion="30"/> <uses-permission android:name="android.permission.CONTROL_DISPLAY_BRIGHTNESS" /> + <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> <application android:label="SilkFX" android:theme="@android:style/Theme.Material"> <activity android:name=".Main" android:label="SilkFX Demos" + android:banner="@drawable/background1" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.LAUNCHER"/> + <category android:name="android.intent.category.LEANBACK_LAUNCHER"/> </intent-filter> </activity> @@ -41,13 +44,16 @@ <activity android:name=".materials.GlassActivity" android:label="Glass Examples" - android:banner="@drawable/background1" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN"/> - <category android:name="android.intent.category.LEANBACK_LAUNCHER" /> </intent-filter> </activity> + <activity android:name=".materials.BackgroundBlurActivity" + android:theme="@style/Theme.BackgroundBlurTheme" + android:exported="true"> + </activity> + </application> </manifest> diff --git a/tests/SilkFX/res/drawable/background_blur_drawable.xml b/tests/SilkFX/res/drawable/background_blur_drawable.xml new file mode 100644 index 000000000000..173ca99bdfdf --- /dev/null +++ b/tests/SilkFX/res/drawable/background_blur_drawable.xml @@ -0,0 +1,20 @@ +<!-- + ~ Copyright (C) 2022 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. + --> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="#20FFFFFF"/> + <corners android:radius="10dp"/> +</shape> diff --git a/tests/SilkFX/res/drawable/blur_activity_background_drawable_white.xml b/tests/SilkFX/res/drawable/blur_activity_background_drawable_white.xml new file mode 100644 index 000000000000..bd8942d46383 --- /dev/null +++ b/tests/SilkFX/res/drawable/blur_activity_background_drawable_white.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2022 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. + --> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <corners android:radius="10dp"/> +</shape> diff --git a/tests/SilkFX/res/layout/activity_background_blur.xml b/tests/SilkFX/res/layout/activity_background_blur.xml new file mode 100644 index 000000000000..f13c0883cb01 --- /dev/null +++ b/tests/SilkFX/res/layout/activity_background_blur.xml @@ -0,0 +1,173 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2022 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. + --> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/background" + android:layout_width="390dp" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:padding="15dp" + android:orientation="vertical" + tools:context=".materials.BackgroundBlurActivity"> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center_horizontal" + android:padding="10dp" + android:textColor="#ffffffff" + android:text="Hello blurry world!"/> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1" + android:textColor="#ffffffff" + android:text="Background blur"/> + + <SeekBar + android:id="@+id/set_background_blur" + android:min="0" + android:max="300" + android:layout_width="160dp" + android:layout_height="wrap_content"/> + <TextView + android:id="@+id/background_blur_radius" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textColor="#ffffffff" + android:ems="3" + android:gravity="center" + android:paddingLeft="10dp" + android:paddingRight="10dp" + android:text="TODO"/> + </LinearLayout> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1" + android:textColor="#ffffffff" + android:text="Background alpha"/> + + <SeekBar + android:id="@+id/set_background_alpha" + android:min="0" + android:max="100" + android:layout_width="160dp" + android:layout_height="wrap_content" /> + <TextView + android:id="@+id/background_alpha" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textColor="#ffffffff" + android:ems="3" + android:gravity="center" + android:paddingLeft="10dp" + android:paddingRight="10dp" + android:text="TODO"/> + </LinearLayout> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1" + android:textColor="#ffffffff" + android:text="Blur behind"/> + + <SeekBar + android:id="@+id/set_blur_behind" + android:min="0" + android:max="300" + android:layout_width="160dp" + android:layout_height="wrap_content" /> + <TextView + android:id="@+id/blur_behind_radius" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="center" + android:textColor="#ffffffff" + android:paddingLeft="10dp" + android:paddingRight="10dp" + android:ems="3" + android:text="TODO"/> + </LinearLayout> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1" + android:textColor="#ffffffff" + android:text="Dim amount"/> + + <SeekBar + android:id="@+id/set_dim_amount" + android:min="0" + android:max="100" + android:layout_width="160dp" + android:layout_height="wrap_content" /> + <TextView + android:id="@+id/dim_amount" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="center" + android:textColor="#ffffffff" + android:paddingLeft="10dp" + android:paddingRight="10dp" + android:ems="3" + android:text="TODO"/> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:layout_marginTop="5dp" + android:orientation="vertical" + android:gravity="center"> + + <Button + android:id="@+id/toggle_blur_enabled" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="Disable blur" + android:onClick="toggleForceBlurDisabled"/> + + <Button + android:id="@+id/toggle_battery_saving_mode" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="TODO" + android:onClick="toggleBatterySavingMode"/> + </LinearLayout> + <requestFocus/> + +</LinearLayout> diff --git a/tests/SilkFX/res/values/style.xml b/tests/SilkFX/res/values/style.xml new file mode 100644 index 000000000000..66edbb5c9382 --- /dev/null +++ b/tests/SilkFX/res/values/style.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2022 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. + --> +<!-- Styles for immersive actions UI. --> +<resources xmlns:android="http://schemas.android.com/apk/res/android"> + <style name="Theme.BackgroundBlurTheme" parent= "Theme.AppCompat.Dialog"> + <item name="android:windowIsTranslucent">true</item> + <item name="android:windowBlurBehindEnabled">true</item> + <item name="android:backgroundDimEnabled">false</item> + <item name="android:windowElevation">0dp</item> + <item name="buttonStyle">@style/AppTheme.Button</item> + <item name="colorAccent">#bbffffff</item> + </style> + <style name="AppTheme.Button" parent="Widget.AppCompat.Button"> + <item name="android:textColor">#ffffffff</item> + </style> + +</resources> diff --git a/tests/SilkFX/src/com/android/test/silkfx/Main.kt b/tests/SilkFX/src/com/android/test/silkfx/Main.kt index 9ed8d2f5edf7..7132ae8772ea 100644 --- a/tests/SilkFX/src/com/android/test/silkfx/Main.kt +++ b/tests/SilkFX/src/com/android/test/silkfx/Main.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Android Open Source Project + * Copyright (C) 2022 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. @@ -30,6 +30,7 @@ import com.android.test.silkfx.app.EXTRA_LAYOUT import com.android.test.silkfx.app.EXTRA_TITLE import com.android.test.silkfx.hdr.GlowActivity import com.android.test.silkfx.materials.GlassActivity +import com.android.test.silkfx.materials.BackgroundBlurActivity import kotlin.reflect.KClass class Demo(val name: String, val makeIntent: (Context) -> Intent) { @@ -51,7 +52,8 @@ private val AllDemos = listOf( Demo("Blingy Notifications", R.layout.bling_notifications) )), DemoGroup("Materials", listOf( - Demo("Glass", GlassActivity::class) + Demo("Glass", GlassActivity::class), + Demo("Background Blur", BackgroundBlurActivity::class) )) ) @@ -126,4 +128,4 @@ class Main : Activity() { AllDemos.forEachIndexed { index, _ -> list.expandGroup(index) } } -}
\ No newline at end of file +} diff --git a/tests/SilkFX/src/com/android/test/silkfx/materials/BackgroundBlurActivity.kt b/tests/SilkFX/src/com/android/test/silkfx/materials/BackgroundBlurActivity.kt new file mode 100644 index 000000000000..9d17d38d4298 --- /dev/null +++ b/tests/SilkFX/src/com/android/test/silkfx/materials/BackgroundBlurActivity.kt @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2022 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 com.android.test.silkfx.materials + +import android.app.Activity +import android.content.Intent +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.graphics.drawable.PaintDrawable +import android.graphics.drawable.Drawable +import android.os.Bundle +import android.provider.Settings +import android.util.TypedValue +import android.view.View +import android.view.WindowManager +import android.widget.ImageView +import android.widget.SeekBar +import android.widget.Switch +import android.widget.TextView +import com.android.test.silkfx.R +import com.android.internal.graphics.drawable.BackgroundBlurDrawable +import android.widget.LinearLayout +import android.widget.Button + +import android.view.ViewRootImpl + +class BackgroundBlurActivity : Activity(), SeekBar.OnSeekBarChangeListener { + var mBackgroundDrawable = PaintDrawable(Color.WHITE) + var mBackgroundBlurRadius = 50 + var mAlphaWithBlur = 0.2f + var mAlphaNoBlur = 0.5f + + var mBlurBehindRadius = 10 + var mDimAmountWithBlur = 0.2f + var mDimAmountNoBlur = 0.2f + + var mBlurForceDisabled = false + var mBatterySavingModeOn = false + + lateinit var blurBackgroundSeekBar: SeekBar + lateinit var backgroundAlphaSeekBar : SeekBar + lateinit var blurBehindSeekBar : SeekBar + lateinit var dimAmountSeekBar : SeekBar + + val blurEnabledListener = { enabled : Boolean -> + blurBackgroundSeekBar.setProgress(mBackgroundBlurRadius) + blurBehindSeekBar.setProgress(mBlurBehindRadius) + + if (enabled) { + setBackgroundBlur(mBackgroundBlurRadius) + setBackgroundColorAlpha(mAlphaWithBlur) + + setBlurBehind(mBlurBehindRadius) + setDimAmount(mDimAmountWithBlur) + + backgroundAlphaSeekBar.setProgress((mAlphaWithBlur * 100).toInt()) + dimAmountSeekBar.setProgress((mDimAmountWithBlur * 100).toInt()) + } else { + setBackgroundColorAlpha(mAlphaNoBlur) + setDimAmount(mDimAmountNoBlur) + + backgroundAlphaSeekBar.setProgress((mAlphaNoBlur * 100).toInt()) + dimAmountSeekBar.setProgress((mDimAmountNoBlur * 100).toInt()) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_background_blur) + + window.addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND) + window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) + + mBackgroundDrawable.setCornerRadius(30f) + window.setBackgroundDrawable(mBackgroundDrawable) + + mBatterySavingModeOn = + Settings.Global.getInt(getContentResolver(), Settings.Global.LOW_POWER_MODE, 0) == 1 + setBatterySavingModeOn(mBatterySavingModeOn) + + blurBackgroundSeekBar = requireViewById(R.id.set_background_blur) + backgroundAlphaSeekBar = requireViewById(R.id.set_background_alpha) + blurBehindSeekBar = requireViewById(R.id.set_blur_behind) + dimAmountSeekBar = requireViewById(R.id.set_dim_amount) + + arrayOf(blurBackgroundSeekBar, backgroundAlphaSeekBar, blurBehindSeekBar, dimAmountSeekBar) + .forEach { + it.setOnSeekBarChangeListener(this) + } + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + getWindowManager().addCrossWindowBlurEnabledListener(blurEnabledListener) + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + getWindowManager().removeCrossWindowBlurEnabledListener(blurEnabledListener) + } + + override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { + when (seekBar) { + blurBackgroundSeekBar -> setBackgroundBlur(progress) + backgroundAlphaSeekBar -> setBackgroundColorAlpha(progress / 100.0f) + blurBehindSeekBar -> setBlurBehind(progress) + dimAmountSeekBar -> setDimAmount(progress / 100.0f) + else -> throw IllegalArgumentException("Unknown seek bar") + } + } + + override fun onStartTrackingTouch(seekBar: SeekBar?) {} + override fun onStopTrackingTouch(seekBar: SeekBar?) {} + + fun setBlurDisabled(disabled: Boolean) { + mBlurForceDisabled = disabled + Settings.Global.putInt(getContentResolver(), Settings.Global.DISABLE_WINDOW_BLURS, + if (mBlurForceDisabled) 1 else 0) + (findViewById(R.id.toggle_blur_enabled) as Button) + .setText(if (mBlurForceDisabled) "Enable blurs" else "Disable blurs") + } + + fun toggleForceBlurDisabled(v: View) { + setBlurDisabled(!mBlurForceDisabled) + } + + fun setBackgroundBlur(radius: Int) { + mBackgroundBlurRadius = radius + (findViewById(R.id.background_blur_radius) as TextView).setText(radius.toString()) + window.setBackgroundBlurRadius(mBackgroundBlurRadius) + } + + fun setBlurBehind(radius: Int) { + mBlurBehindRadius = radius + (findViewById(R.id.blur_behind_radius) as TextView).setText(radius.toString()) + window.getAttributes().setBlurBehindRadius(mBlurBehindRadius) + window.setAttributes(window.getAttributes()) + } + + fun setDimAmount(amount: Float) { + if (getWindowManager().isCrossWindowBlurEnabled()) { + mDimAmountWithBlur = amount + } else { + mDimAmountNoBlur = amount + } + (findViewById(R.id.dim_amount) as TextView).setText("%.2f".format(amount)) + window.getAttributes().dimAmount = amount + window.setAttributes(window.getAttributes()) + } + + fun setBatterySavingModeOn(on: Boolean) { + mBatterySavingModeOn = on + Settings.Global.putInt(getContentResolver(), + Settings.Global.LOW_POWER_MODE, if (on) 1 else 0) + (findViewById(R.id.toggle_battery_saving_mode) as Button).setText( + if (on) "Exit low power mode" else "Enter low power mode") + } + + fun toggleBatterySavingMode(v: View) { + setBatterySavingModeOn(!mBatterySavingModeOn) + } + + fun setBackgroundColorAlpha(alpha: Float) { + if (getWindowManager().isCrossWindowBlurEnabled()) { + mAlphaWithBlur = alpha + } else { + mAlphaNoBlur = alpha + } + (findViewById(R.id.background_alpha) as TextView).setText("%.2f".format(alpha)) + mBackgroundDrawable.setAlpha((alpha * 255f).toInt()) + getWindowManager().updateViewLayout(window.getDecorView(), window.getAttributes()) + } +} diff --git a/tests/TrustTests/OWNERS b/tests/TrustTests/OWNERS new file mode 100644 index 000000000000..e2c6ce15b51e --- /dev/null +++ b/tests/TrustTests/OWNERS @@ -0,0 +1 @@ +include /core/java/android/service/trust/OWNERS diff --git a/tests/benchmarks/src/com/android/server/net/NetworkStatsFactoryBenchmark.java b/tests/benchmarks/src/com/android/server/net/NetworkStatsFactoryBenchmark.java deleted file mode 100644 index ef014f0d4e53..000000000000 --- a/tests/benchmarks/src/com/android/server/net/NetworkStatsFactoryBenchmark.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2012 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 com.android.server.net; - -import android.net.NetworkStats; -import android.os.SystemClock; -import com.android.server.net.NetworkStatsFactory; -import com.google.caliper.AfterExperiment; -import com.google.caliper.BeforeExperiment; -import java.io.File; - -public class NetworkStatsFactoryBenchmark { - private File mStats; - - // TODO: consider staging stats file with different number of rows - - @BeforeExperiment - protected void setUp() { - mStats = new File("/proc/net/xt_qtaguid/stats"); - } - - @AfterExperiment - protected void tearDown() { - mStats = null; - } - - public void timeReadNetworkStatsDetailJava(int reps) throws Exception { - for (int i = 0; i < reps; i++) { - NetworkStatsFactory.javaReadNetworkStatsDetail(mStats, NetworkStats.UID_ALL, - // Looks like this was broken by change d0c5b9abed60b7bc056d026bf0f2b2235410fb70 - // Fixed compilation problem but needs addressing properly. - new String[0], 999); - } - } - - public void timeReadNetworkStatsDetailNative(int reps) { - for (int i = 0; i < reps; i++) { - final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0); - NetworkStatsFactory.nativeReadNetworkStatsDetail( - stats, mStats.getAbsolutePath(), NetworkStats.UID_ALL, - // Looks like this was broken by change d0c5b9abed60b7bc056d026bf0f2b2235410fb70 - // Fixed compilation problem but needs addressing properly. - new String[0], 999, false); - } - } -} diff --git a/tests/benchmarks/src/com/android/server/net/OWNERS b/tests/benchmarks/src/com/android/server/net/OWNERS deleted file mode 100644 index aa87958f1d53..000000000000 --- a/tests/benchmarks/src/com/android/server/net/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /services/core/java/com/android/server/net/OWNERS diff --git a/tests/vcn/Android.bp b/tests/vcn/Android.bp index 41f73cd9c706..228520e8545b 100644 --- a/tests/vcn/Android.bp +++ b/tests/vcn/Android.bp @@ -18,6 +18,7 @@ android_test { "java/**/*.kt", ], platform_apis: true, + defaults: ["framework-connectivity-test-defaults"], test_suites: ["device-tests"], certificate: "platform", static_libs: [ @@ -28,6 +29,7 @@ android_test { "net-tests-utils", "platform-test-annotations", "services.core", + "service-connectivity-tiramisu-pre-jarjar", ], libs: [ "android.test.runner", diff --git a/tests/vcn/AndroidManifest.xml b/tests/vcn/AndroidManifest.xml index 2ad9aac67029..a8f657c89f76 100644 --- a/tests/vcn/AndroidManifest.xml +++ b/tests/vcn/AndroidManifest.xml @@ -16,7 +16,8 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.frameworks.tests.vcn"> - + <uses-sdk android:minSdkVersion="33" + android:targetSdkVersion="33"/> <application> <uses-library android:name="android.test.runner" /> </application> diff --git a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java index 978bf3ed2e92..7b1f7a599519 100644 --- a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java +++ b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java @@ -174,7 +174,7 @@ public class TelephonySubscriptionTrackerTest { private IntentFilter getIntentFilter() { final ArgumentCaptor<IntentFilter> captor = ArgumentCaptor.forClass(IntentFilter.class); - verify(mContext).registerReceiver(any(), captor.capture(), any(), any()); + verify(mContext).registerReceiver(any(), captor.capture(), any(), any(), anyInt()); return captor.getValue(); } @@ -258,7 +258,8 @@ public class TelephonySubscriptionTrackerTest { eq(mTelephonySubscriptionTracker), any(IntentFilter.class), any(), - eq(mHandler)); + eq(mHandler), + eq(Context.RECEIVER_NOT_EXPORTED)); final IntentFilter filter = getIntentFilter(); assertEquals(2, filter.countActions()); assertTrue(filter.hasAction(ACTION_CARRIER_CONFIG_CHANGED)); diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index e547400fff73..4cfa93b4ecf9 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -307,7 +307,10 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection ncCaptor.capture(), lpCaptor.capture(), any(), - argThat(nac -> nac.getLegacyType() == ConnectivityManager.TYPE_MOBILE), + // Subtype integer/name and extras do not have getters; cannot be tested. + argThat(nac -> nac.getLegacyType() == ConnectivityManager.TYPE_MOBILE + && nac.getLegacyTypeName().equals( + VcnGatewayConnection.NETWORK_INFO_NETWORK_TYPE_STRING)), any(), any(), any()); diff --git a/tools/aapt/Android.bp b/tools/aapt/Android.bp index 01eb4f69f842..cc10db9e1523 100644 --- a/tools/aapt/Android.bp +++ b/tools/aapt/Android.bp @@ -61,16 +61,6 @@ cc_defaults { enabled: true, }, }, - - // This tool is prebuilt if we're doing an app-only build. - product_variables: { - pdk: { - enabled: false, - }, - unbundled_build: { - enabled: false, - }, - }, } // ========================================================== diff --git a/tools/bit/command.cpp b/tools/bit/command.cpp index f95ea117a96e..6c68e0b0ff6b 100644 --- a/tools/bit/command.cpp +++ b/tools/bit/command.cpp @@ -192,10 +192,11 @@ exec_with_path_search(const char* prog, char const* const* argv, char const* con if (strchr(prog, '/') != NULL) { return execve(prog, (char*const*)argv, (char*const*)envp); } else { - char* pathEnv = strdup(getenv("PATH")); - if (pathEnv == NULL) { + const char* pathEnvRaw = getenv("PATH"); + if (pathEnvRaw == NULL) { return 1; } + char* pathEnv = strdup(pathEnvRaw); char* dir = pathEnv; while (dir) { char* next = strchr(dir, ':'); diff --git a/tools/streaming_proto/Android.bp b/tools/streaming_proto/Android.bp index 1ec83a360048..b18bdff7263f 100644 --- a/tools/streaming_proto/Android.bp +++ b/tools/streaming_proto/Android.bp @@ -69,7 +69,6 @@ java_library { "test/**/*.proto", ], proto: { - plugin: "javastream", + type: "stream", }, - static_libs: ["libprotobuf-java-lite"], } |