Merge "Avoid cutting off AVD on splash screen."
diff --git a/Android.bp b/Android.bp
index 7d02d7d..ee5db70 100644
--- a/Android.bp
+++ b/Android.bp
@@ -109,6 +109,7 @@
":platform-compat-native-aidl",
// AIDL sources from external directories
+ ":android.hardware.graphics.common-V3-java-source",
":android.hardware.security.keymint-V1-java-source",
":android.hardware.security.secureclock-V1-java-source",
":android.hardware.tv.tuner-V1-java-source",
@@ -288,6 +289,7 @@
// TODO: remove when moved to the below package
"frameworks/base/packages/ConnectivityT/framework-t/aidl-export",
"packages/modules/Connectivity/framework/aidl-export",
+ "hardware/interfaces/graphics/common/aidl",
],
},
dxflags: [
@@ -537,6 +539,7 @@
// TODO: remove when moved to the below package
"frameworks/base/packages/ConnectivityT/framework-t/aidl-export",
"packages/modules/Connectivity/framework/aidl-export",
+ "hardware/interfaces/graphics/common/aidl",
],
},
// These are libs from framework-internal-utils that are required (i.e. being referenced)
diff --git a/INPUT_OWNERS b/INPUT_OWNERS
new file mode 100644
index 0000000..6041f637f
--- /dev/null
+++ b/INPUT_OWNERS
@@ -0,0 +1,3 @@
+michaelwr@google.com
+prabirmsp@google.com
+svv@google.com
diff --git a/apct-tests/perftests/core/OWNERS b/apct-tests/perftests/core/OWNERS
index 18486af..2b3564e 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 0000000..5e56c25
--- /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 7216244..54b79b4 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.XmlPullParserException;
import java.io.IOException;
+import java.util.Random;
/**
* Benchmarks for {@link android.content.res.Resources}.
@@ -222,4 +223,24 @@
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 b3e81b9..e867586 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/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
index 96114dc..ffa534e 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
@@ -1376,6 +1376,11 @@
}
}
+ private boolean isAllowedBlobAccess(int uid, String packageName) {
+ return (!Process.isSupplemental(uid) && !Process.isIsolated(uid)
+ && !mPackageManagerInternal.isInstantApp(packageName, UserHandle.getUserId(uid)));
+ }
+
private class PackageChangedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
@@ -1437,8 +1442,7 @@
final int callingUid = Binder.getCallingUid();
verifyCallingPackage(callingUid, packageName);
- if (Process.isIsolated(callingUid) || mPackageManagerInternal.isInstantApp(
- packageName, UserHandle.getUserId(callingUid))) {
+ if (!isAllowedBlobAccess(callingUid, packageName)) {
throw new SecurityException("Caller not allowed to create session; "
+ "callingUid=" + callingUid + ", callingPackage=" + packageName);
}
@@ -1487,8 +1491,7 @@
final int callingUid = Binder.getCallingUid();
verifyCallingPackage(callingUid, packageName);
- if (Process.isIsolated(callingUid) || mPackageManagerInternal.isInstantApp(
- packageName, UserHandle.getUserId(callingUid))) {
+ if (!isAllowedBlobAccess(callingUid, packageName)) {
throw new SecurityException("Caller not allowed to open blob; "
+ "callingUid=" + callingUid + ", callingPackage=" + packageName);
}
@@ -1519,8 +1522,7 @@
final int callingUid = Binder.getCallingUid();
verifyCallingPackage(callingUid, packageName);
- if (Process.isIsolated(callingUid) || mPackageManagerInternal.isInstantApp(
- packageName, UserHandle.getUserId(callingUid))) {
+ if (!isAllowedBlobAccess(callingUid, packageName)) {
throw new SecurityException("Caller not allowed to open blob; "
+ "callingUid=" + callingUid + ", callingPackage=" + packageName);
}
@@ -1544,8 +1546,7 @@
final int callingUid = Binder.getCallingUid();
verifyCallingPackage(callingUid, packageName);
- if (Process.isIsolated(callingUid) || mPackageManagerInternal.isInstantApp(
- packageName, UserHandle.getUserId(callingUid))) {
+ if (!isAllowedBlobAccess(callingUid, packageName)) {
throw new SecurityException("Caller not allowed to open blob; "
+ "callingUid=" + callingUid + ", callingPackage=" + packageName);
}
@@ -1628,8 +1629,7 @@
final int callingUid = Binder.getCallingUid();
verifyCallingPackage(callingUid, packageName);
- if (Process.isIsolated(callingUid) || mPackageManagerInternal.isInstantApp(
- packageName, UserHandle.getUserId(callingUid))) {
+ if (!isAllowedBlobAccess(callingUid, packageName)) {
throw new SecurityException("Caller not allowed to open blob; "
+ "callingUid=" + callingUid + ", callingPackage=" + packageName);
}
diff --git a/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java b/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
index 6d2bd47..2682dd7 100644
--- a/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
@@ -16,7 +16,7 @@
package com.android.server.job;
-import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.job.JobInfo;
import android.app.job.JobParameters;
import android.util.proto.ProtoOutputStream;
@@ -47,9 +47,9 @@
void removeBackingUpUid(int uid);
void clearAllBackingUpUids();
- /** Returns the package responsible for backing up media on the device. */
- @NonNull
- String getMediaBackupPackage();
+ /** Returns the package responsible for providing media from the cloud to the device. */
+ @Nullable
+ String getCloudMediaProviderPackage(int userId);
/**
* The user has started interacting with the app. Take any appropriate action.
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index c706a3a..8237383 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -25,6 +25,7 @@
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AlarmManager;
@@ -127,28 +128,47 @@
<pre>
digraph {
+ subgraph cluster_legend {
+ label="Legend"
+
+ wakeup_alarm [label="Entering this state requires a wakeup alarm",color=red,shape=box]
+ nonwakeup_alarm [
+ label="This state can be entered from a non-wakeup alarm",color=blue,shape=oval
+ ]
+ no_alarm [label="This state doesn't require an alarm",color=black,shape=diamond]
+ }
+
subgraph deep {
label="deep";
- STATE_ACTIVE [label="STATE_ACTIVE\nScreen on OR Charging OR Alarm going off soon"]
- STATE_INACTIVE [label="STATE_INACTIVE\nScreen off AND Not charging"]
+ STATE_ACTIVE [
+ label="STATE_ACTIVE\nScreen on OR Charging OR Alarm going off soon",
+ color=black,shape=diamond
+ ]
+ STATE_INACTIVE [
+ label="STATE_INACTIVE\nScreen off AND Not charging",color=black,shape=diamond
+ ]
STATE_QUICK_DOZE_DELAY [
label="STATE_QUICK_DOZE_DELAY\n"
+ "Screen off AND Not charging\n"
- + "Location, motion detection, and significant motion monitoring turned off"
+ + "Location, motion detection, and significant motion monitoring turned off",
+ color=black,shape=diamond
]
STATE_IDLE_PENDING [
- label="STATE_IDLE_PENDING\nSignificant motion monitoring turned on"
+ label="STATE_IDLE_PENDING\nSignificant motion monitoring turned on",
+ color=red,shape=box
]
- STATE_SENSING [label="STATE_SENSING\nMonitoring for ANY motion"]
+ STATE_SENSING [label="STATE_SENSING\nMonitoring for ANY motion",color=red,shape=box]
STATE_LOCATING [
- label="STATE_LOCATING\nRequesting location, motion monitoring still on"
+ label="STATE_LOCATING\nRequesting location, motion monitoring still on",
+ color=red,shape=box
]
STATE_IDLE [
label="STATE_IDLE\nLocation and motion detection turned off\n"
- + "Significant motion monitoring state unchanged"
+ + "Significant motion monitoring state unchanged",
+ color=red,shape=box
]
- STATE_IDLE_MAINTENANCE [label="STATE_IDLE_MAINTENANCE\n"]
+ STATE_IDLE_MAINTENANCE [label="STATE_IDLE_MAINTENANCE\n",color=red,shape=box]
STATE_ACTIVE -> STATE_INACTIVE [
label="becomeInactiveIfAppropriateLocked() AND Quick Doze not enabled"
@@ -213,19 +233,22 @@
label="light"
LIGHT_STATE_ACTIVE [
- label="LIGHT_STATE_ACTIVE\nScreen on OR Charging OR Alarm going off soon"
+ label="LIGHT_STATE_ACTIVE\nScreen on OR Charging OR Alarm going off soon",
+ color=black,shape=diamond
]
- LIGHT_STATE_INACTIVE [label="LIGHT_STATE_INACTIVE\nScreen off AND Not charging"]
- LIGHT_STATE_PRE_IDLE [
- label="LIGHT_STATE_PRE_IDLE\n"
- + "Delay going into LIGHT_STATE_IDLE due to some running jobs or alarms"
+ LIGHT_STATE_INACTIVE [
+ label="LIGHT_STATE_INACTIVE\nScreen off AND Not charging",
+ color=black,shape=diamond
]
- LIGHT_STATE_IDLE [label="LIGHT_STATE_IDLE\n"]
+ LIGHT_STATE_IDLE [label="LIGHT_STATE_IDLE\n",color=blue,shape=oval]
LIGHT_STATE_WAITING_FOR_NETWORK [
label="LIGHT_STATE_WAITING_FOR_NETWORK\n"
- + "Coming out of LIGHT_STATE_IDLE, waiting for network"
+ + "Coming out of LIGHT_STATE_IDLE, waiting for network",
+ color=black,shape=diamond
]
- LIGHT_STATE_IDLE_MAINTENANCE [label="LIGHT_STATE_IDLE_MAINTENANCE\n"]
+ LIGHT_STATE_IDLE_MAINTENANCE [
+ label="LIGHT_STATE_IDLE_MAINTENANCE\n",color=red,shape=box
+ ]
LIGHT_STATE_OVERRIDE [
label="LIGHT_STATE_OVERRIDE\nDevice in deep doze, light no longer changing states"
]
@@ -236,16 +259,9 @@
LIGHT_STATE_ACTIVE -> LIGHT_STATE_OVERRIDE [label="deep goes to STATE_IDLE"]
LIGHT_STATE_INACTIVE -> LIGHT_STATE_ACTIVE [label="becomeActiveLocked()"]
- LIGHT_STATE_INACTIVE -> LIGHT_STATE_PRE_IDLE [label="active jobs"]
- LIGHT_STATE_INACTIVE -> LIGHT_STATE_IDLE [label="no active jobs"]
+ LIGHT_STATE_INACTIVE -> LIGHT_STATE_IDLE [label="some time transpires"]
LIGHT_STATE_INACTIVE -> LIGHT_STATE_OVERRIDE [label="deep goes to STATE_IDLE"]
- LIGHT_STATE_PRE_IDLE -> LIGHT_STATE_ACTIVE [label="becomeActiveLocked()"]
- LIGHT_STATE_PRE_IDLE -> LIGHT_STATE_IDLE [
- label="stepLightIdleStateLocked(), exitMaintenanceEarlyIfNeededLocked()"
- ]
- LIGHT_STATE_PRE_IDLE -> LIGHT_STATE_OVERRIDE [label="deep goes to STATE_IDLE"]
-
LIGHT_STATE_IDLE -> LIGHT_STATE_ACTIVE [label="becomeActiveLocked()"]
LIGHT_STATE_IDLE -> LIGHT_STATE_WAITING_FOR_NETWORK [label="no network"]
LIGHT_STATE_IDLE -> LIGHT_STATE_IDLE_MAINTENANCE
@@ -421,9 +437,6 @@
/** Device is inactive (screen off) and we are waiting to for the first light idle. */
@VisibleForTesting
static final int LIGHT_STATE_INACTIVE = 1;
- /** Device is about to go idle for the first time, wait for current work to complete. */
- @VisibleForTesting
- static final int LIGHT_STATE_PRE_IDLE = 3;
/** Device is in the light idle state, trying to stay asleep as much as possible. */
@VisibleForTesting
static final int LIGHT_STATE_IDLE = 4;
@@ -434,7 +447,7 @@
/** Device is in the light idle state, but temporarily out of idle to do regular maintenance. */
@VisibleForTesting
static final int LIGHT_STATE_IDLE_MAINTENANCE = 6;
- /** Device light idle state is overriden, now applying deep doze state. */
+ /** Device light idle state is overridden, now applying deep doze state. */
@VisibleForTesting
static final int LIGHT_STATE_OVERRIDE = 7;
@@ -443,7 +456,6 @@
switch (state) {
case LIGHT_STATE_ACTIVE: return "ACTIVE";
case LIGHT_STATE_INACTIVE: return "INACTIVE";
- case LIGHT_STATE_PRE_IDLE: return "PRE_IDLE";
case LIGHT_STATE_IDLE: return "IDLE";
case LIGHT_STATE_WAITING_FOR_NETWORK: return "WAITING_FOR_NETWORK";
case LIGHT_STATE_IDLE_MAINTENANCE: return "IDLE_MAINTENANCE";
@@ -468,10 +480,10 @@
@GuardedBy("this")
private long mNextLightIdleDelay;
@GuardedBy("this")
- private long mNextLightIdleDelayFlex;
- @GuardedBy("this")
private long mNextLightAlarmTime;
@GuardedBy("this")
+ private long mNextLightMaintenanceAlarmTime;
+ @GuardedBy("this")
private long mNextSensingTimeoutAlarmTime;
/** How long a light idle maintenance window should last. */
@@ -658,13 +670,21 @@
}
};
- private final AlarmManager.OnAlarmListener mLightAlarmListener
- = new AlarmManager.OnAlarmListener() {
- @Override
- public void onAlarm() {
- synchronized (DeviceIdleController.this) {
- stepLightIdleStateLocked("s:alarm");
- }
+ private final AlarmManager.OnAlarmListener mLightAlarmListener = () -> {
+ if (DEBUG) {
+ Slog.d(TAG, "Light progression alarm fired");
+ }
+ synchronized (DeviceIdleController.this) {
+ stepLightIdleStateLocked("s:alarm");
+ }
+ };
+
+ private final AlarmManager.OnAlarmListener mLightMaintenanceAlarmListener = () -> {
+ if (DEBUG) {
+ Slog.d(TAG, "Light maintenance alarm fired");
+ }
+ synchronized (DeviceIdleController.this) {
+ stepLightIdleStateLocked("s:alarm");
}
};
@@ -928,11 +948,7 @@
private static final String KEY_FLEX_TIME_SHORT = "flex_time_short";
private static final String KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT =
"light_after_inactive_to";
- private static final String KEY_LIGHT_PRE_IDLE_TIMEOUT = "light_pre_idle_to";
private static final String KEY_LIGHT_IDLE_TIMEOUT = "light_idle_to";
- private static final String KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX =
- "light_idle_to_initial_flex";
- private static final String KEY_LIGHT_MAX_IDLE_TIMEOUT_FLEX = "light_max_idle_to_flex";
private static final String KEY_LIGHT_IDLE_FACTOR = "light_idle_factor";
private static final String KEY_LIGHT_MAX_IDLE_TIMEOUT = "light_max_idle_to";
private static final String KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET =
@@ -978,15 +994,9 @@
private static final long DEFAULT_FLEX_TIME_SHORT =
!COMPRESS_TIME ? 60 * 1000L : 5 * 1000L;
private static final long DEFAULT_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT =
- !COMPRESS_TIME ? 60 * 1000L : 15 * 1000L;
- private static final long DEFAULT_LIGHT_PRE_IDLE_TIMEOUT =
- !COMPRESS_TIME ? 3 * 60 * 1000L : 30 * 1000L;
+ !COMPRESS_TIME ? 4 * 60 * 1000L : 30 * 1000L;
private static final long DEFAULT_LIGHT_IDLE_TIMEOUT =
!COMPRESS_TIME ? 5 * 60 * 1000L : 15 * 1000L;
- private static final long DEFAULT_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX =
- !COMPRESS_TIME ? 60 * 1000L : 5 * 1000L;
- private static final long DEFAULT_LIGHT_MAX_IDLE_TIMEOUT_FLEX =
- !COMPRESS_TIME ? 15 * 60 * 1000L : 60 * 1000L;
private static final float DEFAULT_LIGHT_IDLE_FACTOR = 2f;
private static final long DEFAULT_LIGHT_MAX_IDLE_TIMEOUT =
!COMPRESS_TIME ? 15 * 60 * 1000L : 60 * 1000L;
@@ -1054,15 +1064,6 @@
public long LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT = DEFAULT_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT;
/**
- * This is amount of time we will wait from the point where we decide we would
- * like to go idle until we actually do, while waiting for jobs and other current
- * activity to finish.
- *
- * @see #KEY_LIGHT_PRE_IDLE_TIMEOUT
- */
- public long LIGHT_PRE_IDLE_TIMEOUT = DEFAULT_LIGHT_PRE_IDLE_TIMEOUT;
-
- /**
* This is the initial time that we will run in light idle maintenance mode.
*
* @see #KEY_LIGHT_IDLE_TIMEOUT
@@ -1070,21 +1071,6 @@
public long LIGHT_IDLE_TIMEOUT = DEFAULT_LIGHT_IDLE_TIMEOUT;
/**
- * This is the initial alarm window size that we will tolerate for light idle maintenance
- * timing.
- *
- * @see #KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX
- */
- public long LIGHT_IDLE_TIMEOUT_INITIAL_FLEX = DEFAULT_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX;
-
- /**
- * This is the maximum value that {@link #LIGHT_IDLE_TIMEOUT_INITIAL_FLEX} should take.
- *
- * @see #KEY_LIGHT_MAX_IDLE_TIMEOUT_FLEX
- */
- public long LIGHT_MAX_IDLE_TIMEOUT_FLEX = DEFAULT_LIGHT_MAX_IDLE_TIMEOUT_FLEX;
-
- /**
* Scaling factor to apply to the light idle mode time each time we complete a cycle.
*
* @see #KEY_LIGHT_IDLE_FACTOR
@@ -1327,24 +1313,10 @@
KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT,
DEFAULT_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT);
break;
- case KEY_LIGHT_PRE_IDLE_TIMEOUT:
- LIGHT_PRE_IDLE_TIMEOUT = properties.getLong(
- KEY_LIGHT_PRE_IDLE_TIMEOUT, DEFAULT_LIGHT_PRE_IDLE_TIMEOUT);
- break;
case KEY_LIGHT_IDLE_TIMEOUT:
LIGHT_IDLE_TIMEOUT = properties.getLong(
KEY_LIGHT_IDLE_TIMEOUT, DEFAULT_LIGHT_IDLE_TIMEOUT);
break;
- case KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX:
- LIGHT_IDLE_TIMEOUT_INITIAL_FLEX = properties.getLong(
- KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX,
- DEFAULT_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX);
- break;
- case KEY_LIGHT_MAX_IDLE_TIMEOUT_FLEX:
- LIGHT_MAX_IDLE_TIMEOUT_FLEX = properties.getLong(
- KEY_LIGHT_MAX_IDLE_TIMEOUT_FLEX,
- DEFAULT_LIGHT_MAX_IDLE_TIMEOUT_FLEX);
- break;
case KEY_LIGHT_IDLE_FACTOR:
LIGHT_IDLE_FACTOR = Math.max(1, properties.getFloat(
KEY_LIGHT_IDLE_FACTOR, DEFAULT_LIGHT_IDLE_FACTOR));
@@ -1497,22 +1469,10 @@
TimeUtils.formatDuration(LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT, pw);
pw.println();
- pw.print(" "); pw.print(KEY_LIGHT_PRE_IDLE_TIMEOUT); pw.print("=");
- TimeUtils.formatDuration(LIGHT_PRE_IDLE_TIMEOUT, pw);
- pw.println();
-
pw.print(" "); pw.print(KEY_LIGHT_IDLE_TIMEOUT); pw.print("=");
TimeUtils.formatDuration(LIGHT_IDLE_TIMEOUT, pw);
pw.println();
- pw.print(" "); pw.print(KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX); pw.print("=");
- TimeUtils.formatDuration(LIGHT_IDLE_TIMEOUT_INITIAL_FLEX, pw);
- pw.println();
-
- pw.print(" "); pw.print(KEY_LIGHT_MAX_IDLE_TIMEOUT_FLEX); pw.print("=");
- TimeUtils.formatDuration(LIGHT_MAX_IDLE_TIMEOUT_FLEX, pw);
- pw.println();
-
pw.print(" "); pw.print(KEY_LIGHT_IDLE_FACTOR); pw.print("=");
pw.print(LIGHT_IDLE_FACTOR);
pw.println();
@@ -3088,7 +3048,7 @@
if (conn != mNetworkConnected) {
mNetworkConnected = conn;
if (conn && mLightState == LIGHT_STATE_WAITING_FOR_NETWORK) {
- stepLightIdleStateLocked("network");
+ stepLightIdleStateLocked("network", /* forceProgression */ true);
}
}
}
@@ -3343,7 +3303,11 @@
if (DEBUG) Slog.d(TAG, "Moved from LIGHT_STATE_ACTIVE to LIGHT_STATE_INACTIVE");
resetLightIdleManagementLocked();
scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT,
- mConstants.FLEX_TIME_SHORT, true);
+ mConstants.FLEX_TIME_SHORT);
+ // After moving in INACTIVE, the maintenance window should start the time inactive
+ // timeout and a single light idle period.
+ scheduleLightMaintenanceAlarmLocked(
+ mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT + mConstants.LIGHT_IDLE_TIMEOUT);
EventLogTags.writeDeviceIdleLight(mLightState, "no activity");
}
}
@@ -3364,9 +3328,9 @@
@GuardedBy("this")
private void resetLightIdleManagementLocked() {
- mNextLightIdleDelay = 0;
- mNextLightIdleDelayFlex = 0;
- mCurLightIdleBudget = 0;
+ mNextLightIdleDelay = mConstants.LIGHT_IDLE_TIMEOUT;
+ mMaintenanceStartTime = 0;
+ mCurLightIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
cancelLightAlarmLocked();
}
@@ -3401,90 +3365,115 @@
}
@GuardedBy("this")
- void stepLightIdleStateLocked(String reason) {
- if (mLightState == LIGHT_STATE_OVERRIDE) {
+ private void stepLightIdleStateLocked(String reason) {
+ stepLightIdleStateLocked(reason, false);
+ }
+
+ @GuardedBy("this")
+ @VisibleForTesting
+ @SuppressLint("WakelockTimeout")
+ void stepLightIdleStateLocked(String reason, boolean forceProgression) {
+ if (mLightState == LIGHT_STATE_ACTIVE || mLightState == LIGHT_STATE_OVERRIDE) {
// If we are already in deep device idle mode, then
// there is nothing left to do for light mode.
return;
}
- if (DEBUG) Slog.d(TAG, "stepLightIdleStateLocked: mLightState=" + mLightState);
+ if (DEBUG) {
+ Slog.d(TAG, "stepLightIdleStateLocked: mLightState=" + lightStateToString(mLightState)
+ + " force=" + forceProgression);
+ }
EventLogTags.writeDeviceIdleLightStep();
- switch (mLightState) {
- case LIGHT_STATE_INACTIVE:
- mCurLightIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
- // Reset the upcoming idle delays.
- mNextLightIdleDelay = mConstants.LIGHT_IDLE_TIMEOUT;
- mNextLightIdleDelayFlex = mConstants.LIGHT_IDLE_TIMEOUT_INITIAL_FLEX;
- mMaintenanceStartTime = 0;
- if (!isOpsInactiveLocked()) {
- // We have some active ops going on... give them a chance to finish
- // before going in to our first idle.
- mLightState = LIGHT_STATE_PRE_IDLE;
- EventLogTags.writeDeviceIdleLight(mLightState, reason);
- scheduleLightAlarmLocked(mConstants.LIGHT_PRE_IDLE_TIMEOUT,
- mConstants.FLEX_TIME_SHORT, true);
- break;
+ final long nowElapsed = mInjector.getElapsedRealtime();
+ final boolean crossedMaintenanceTime =
+ mNextLightMaintenanceAlarmTime > 0 && nowElapsed >= mNextLightMaintenanceAlarmTime;
+ final boolean crossedProgressionTime =
+ mNextLightAlarmTime > 0 && nowElapsed >= mNextLightAlarmTime;
+ final boolean enterMaintenance;
+ if (crossedMaintenanceTime) {
+ if (crossedProgressionTime) {
+ enterMaintenance = (mNextLightAlarmTime <= mNextLightMaintenanceAlarmTime);
+ } else {
+ enterMaintenance = true;
+ }
+ } else if (crossedProgressionTime) {
+ enterMaintenance = false;
+ } else if (forceProgression) {
+ // This will happen for adb commands, unit tests,
+ // and when we're in WAITING_FOR_NETWORK and the network connects.
+ enterMaintenance =
+ mLightState == LIGHT_STATE_IDLE
+ || mLightState == LIGHT_STATE_WAITING_FOR_NETWORK;
+ } else {
+ Slog.wtfStack(TAG, "stepLightIdleStateLocked called in invalid state");
+ return;
+ }
+
+ if (enterMaintenance) {
+ if (mNetworkConnected || mLightState == LIGHT_STATE_WAITING_FOR_NETWORK) {
+ // We have been idling long enough, now it is time to do some work.
+ mActiveIdleOpCount = 1;
+ mActiveIdleWakeLock.acquire();
+ mMaintenanceStartTime = SystemClock.elapsedRealtime();
+ if (mCurLightIdleBudget < mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET) {
+ mCurLightIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
+ } else if (mCurLightIdleBudget > mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET) {
+ mCurLightIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET;
}
- // Nothing active, fall through to immediately idle.
- case LIGHT_STATE_PRE_IDLE:
- case LIGHT_STATE_IDLE_MAINTENANCE:
- if (mMaintenanceStartTime != 0) {
- long duration = SystemClock.elapsedRealtime() - mMaintenanceStartTime;
- if (duration < mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET) {
- // We didn't use up all of our minimum budget; add this to the reserve.
- mCurLightIdleBudget +=
- (mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET - duration);
- } else {
- // We used more than our minimum budget; this comes out of the reserve.
- mCurLightIdleBudget -=
- (duration - mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET);
- }
- }
- mMaintenanceStartTime = 0;
- scheduleLightAlarmLocked(mNextLightIdleDelay, mNextLightIdleDelayFlex, false);
mNextLightIdleDelay = Math.min(mConstants.LIGHT_MAX_IDLE_TIMEOUT,
(long) (mNextLightIdleDelay * mConstants.LIGHT_IDLE_FACTOR));
- mNextLightIdleDelayFlex = Math.min(mConstants.LIGHT_MAX_IDLE_TIMEOUT_FLEX,
- (long) (mNextLightIdleDelayFlex * mConstants.LIGHT_IDLE_FACTOR));
- if (DEBUG) Slog.d(TAG, "Moved to LIGHT_STATE_IDLE.");
- mLightState = LIGHT_STATE_IDLE;
- EventLogTags.writeDeviceIdleLight(mLightState, reason);
- addEvent(EVENT_LIGHT_IDLE, null);
- mGoingIdleWakeLock.acquire();
- mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON_LIGHT);
- break;
- case LIGHT_STATE_IDLE:
- case LIGHT_STATE_WAITING_FOR_NETWORK:
- if (mNetworkConnected || mLightState == LIGHT_STATE_WAITING_FOR_NETWORK) {
- // We have been idling long enough, now it is time to do some work.
- mActiveIdleOpCount = 1;
- mActiveIdleWakeLock.acquire();
- mMaintenanceStartTime = SystemClock.elapsedRealtime();
- if (mCurLightIdleBudget < mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET) {
- mCurLightIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
- } else if (mCurLightIdleBudget > mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET) {
- mCurLightIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET;
- }
- scheduleLightAlarmLocked(mCurLightIdleBudget, mConstants.FLEX_TIME_SHORT, true);
- if (DEBUG) Slog.d(TAG,
- "Moved from LIGHT_STATE_IDLE to LIGHT_STATE_IDLE_MAINTENANCE.");
- mLightState = LIGHT_STATE_IDLE_MAINTENANCE;
- EventLogTags.writeDeviceIdleLight(mLightState, reason);
- addEvent(EVENT_LIGHT_MAINTENANCE, null);
- mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
- } else {
- // We'd like to do maintenance, but currently don't have network
- // connectivity... let's try to wait until the network comes back.
- // We'll only wait for another full idle period, however, and then give up.
- scheduleLightAlarmLocked(mNextLightIdleDelay,
- mNextLightIdleDelayFlex / 2, true);
- if (DEBUG) Slog.d(TAG, "Moved to LIGHT_WAITING_FOR_NETWORK.");
- mLightState = LIGHT_STATE_WAITING_FOR_NETWORK;
- EventLogTags.writeDeviceIdleLight(mLightState, reason);
+ // We're entering MAINTENANCE. It should end curLightIdleBudget time from now.
+ // The next maintenance window should be curLightIdleBudget + nextLightIdleDelay
+ // time from now.
+ scheduleLightAlarmLocked(mCurLightIdleBudget, mConstants.FLEX_TIME_SHORT);
+ scheduleLightMaintenanceAlarmLocked(mCurLightIdleBudget + mNextLightIdleDelay);
+ if (DEBUG) {
+ Slog.d(TAG, "Moved from " + lightStateToString(mLightState)
+ + " to LIGHT_STATE_IDLE_MAINTENANCE");
}
- break;
+ mLightState = LIGHT_STATE_IDLE_MAINTENANCE;
+ EventLogTags.writeDeviceIdleLight(mLightState, reason);
+ addEvent(EVENT_LIGHT_MAINTENANCE, null);
+ mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
+ } else {
+ // We'd like to do maintenance, but currently don't have network
+ // connectivity... let's try to wait until the network comes back.
+ // We'll only wait for another full idle period, however, and then give up.
+ scheduleLightMaintenanceAlarmLocked(mNextLightIdleDelay);
+ mNextLightAlarmTime = 0;
+ if (DEBUG) Slog.d(TAG, "Moved to LIGHT_WAITING_FOR_NETWORK.");
+ mLightState = LIGHT_STATE_WAITING_FOR_NETWORK;
+ EventLogTags.writeDeviceIdleLight(mLightState, reason);
+ }
+ } else {
+ if (mMaintenanceStartTime != 0) {
+ // Cap duration at budget since the non-wakeup alarm to exit maintenance may
+ // not fire at the exact intended time, but once the system is up, we will stop
+ // more ongoing work.
+ long duration = Math.min(mCurLightIdleBudget,
+ SystemClock.elapsedRealtime() - mMaintenanceStartTime);
+ if (duration < mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET) {
+ // We didn't use up all of our minimum budget; add this to the reserve.
+ mCurLightIdleBudget +=
+ (mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET - duration);
+ } else {
+ // We used more than our minimum budget; this comes out of the reserve.
+ mCurLightIdleBudget -=
+ (duration - mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET);
+ }
+ }
+ mMaintenanceStartTime = 0;
+ // We're entering IDLE. We may have used less than curLightIdleBudget for the
+ // maintenance window, so reschedule the alarm starting from now.
+ scheduleLightMaintenanceAlarmLocked(mNextLightIdleDelay);
+ mNextLightAlarmTime = 0;
+ if (DEBUG) Slog.d(TAG, "Moved to LIGHT_STATE_IDLE.");
+ mLightState = LIGHT_STATE_IDLE;
+ EventLogTags.writeDeviceIdleLight(mLightState, reason);
+ addEvent(EVENT_LIGHT_IDLE, null);
+ mGoingIdleWakeLock.acquire();
+ mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON_LIGHT);
}
}
@@ -3839,8 +3828,7 @@
@GuardedBy("this")
void exitMaintenanceEarlyIfNeededLocked() {
- if (mState == STATE_IDLE_MAINTENANCE || mLightState == LIGHT_STATE_IDLE_MAINTENANCE
- || mLightState == LIGHT_STATE_PRE_IDLE) {
+ if (mState == STATE_IDLE_MAINTENANCE || mLightState == LIGHT_STATE_IDLE_MAINTENANCE) {
if (isOpsInactiveLocked()) {
final long now = SystemClock.elapsedRealtime();
if (DEBUG) {
@@ -3853,10 +3841,8 @@
}
if (mState == STATE_IDLE_MAINTENANCE) {
stepIdleStateLocked("s:early");
- } else if (mLightState == LIGHT_STATE_PRE_IDLE) {
- stepLightIdleStateLocked("s:predone");
} else {
- stepLightIdleStateLocked("s:early");
+ stepLightIdleStateLocked("s:early", /* forceProgression */ true);
}
}
}
@@ -3969,6 +3955,10 @@
mNextLightAlarmTime = 0;
mAlarmManager.cancel(mLightAlarmListener);
}
+ if (mNextLightMaintenanceAlarmTime != 0) {
+ mNextLightMaintenanceAlarmTime = 0;
+ mAlarmManager.cancel(mLightMaintenanceAlarmListener);
+ }
}
@GuardedBy("this")
@@ -4035,26 +4025,54 @@
}
@GuardedBy("this")
- void scheduleLightAlarmLocked(long delay, long flex, boolean wakeup) {
+ @VisibleForTesting
+ void scheduleLightAlarmLocked(long delay, long flex) {
if (DEBUG) {
Slog.d(TAG, "scheduleLightAlarmLocked(" + delay
+ (mConstants.USE_WINDOW_ALARMS ? "/" + flex : "")
- + ", wakeup=" + wakeup + ")");
+ + ")");
}
- mNextLightAlarmTime = SystemClock.elapsedRealtime() + delay;
+ mNextLightAlarmTime = mInjector.getElapsedRealtime() + delay;
if (mConstants.USE_WINDOW_ALARMS) {
mAlarmManager.setWindow(
- wakeup ? AlarmManager.ELAPSED_REALTIME_WAKEUP : AlarmManager.ELAPSED_REALTIME,
+ AlarmManager.ELAPSED_REALTIME,
mNextLightAlarmTime, flex,
"DeviceIdleController.light", mLightAlarmListener, mHandler);
} else {
mAlarmManager.set(
- wakeup ? AlarmManager.ELAPSED_REALTIME_WAKEUP : AlarmManager.ELAPSED_REALTIME,
+ AlarmManager.ELAPSED_REALTIME,
mNextLightAlarmTime,
"DeviceIdleController.light", mLightAlarmListener, mHandler);
}
}
+ @GuardedBy("this")
+ @VisibleForTesting
+ void scheduleLightMaintenanceAlarmLocked(long delay) {
+ if (DEBUG) {
+ Slog.d(TAG, "scheduleLightMaintenanceAlarmLocked(" + delay + ")");
+ }
+ mNextLightMaintenanceAlarmTime = mInjector.getElapsedRealtime() + delay;
+ mAlarmManager.setWindow(
+ AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ mNextLightMaintenanceAlarmTime, mConstants.FLEX_TIME_SHORT,
+ "DeviceIdleController.light", mLightMaintenanceAlarmListener, mHandler);
+ }
+
+ @VisibleForTesting
+ long getNextLightAlarmTimeForTesting() {
+ synchronized (this) {
+ return mNextLightAlarmTime;
+ }
+ }
+
+ @VisibleForTesting
+ long getNextLightMaintenanceAlarmTimeForTesting() {
+ synchronized (this) {
+ return mNextLightMaintenanceAlarmTime;
+ }
+ }
+
private void scheduleMotionRegistrationAlarmLocked() {
if (DEBUG) Slog.d(TAG, "scheduleMotionRegistrationAlarmLocked");
long nextMotionRegistrationAlarmTime =
@@ -4424,7 +4442,7 @@
pw.print("Stepped to deep: ");
pw.println(stateToString(mState));
} else if ("light".equals(arg)) {
- stepLightIdleStateLocked("s:shell");
+ stepLightIdleStateLocked("s:shell", /* forceProgression */ true);
pw.print("Stepped to light: "); pw.println(lightStateToString(mLightState));
} else {
pw.println("Unknown idle mode: " + arg);
@@ -4464,7 +4482,7 @@
becomeInactiveIfAppropriateLocked();
int curLightState = mLightState;
while (curLightState != LIGHT_STATE_IDLE) {
- stepLightIdleStateLocked("s:shell");
+ stepLightIdleStateLocked("s:shell", /* forceProgression */ true);
if (curLightState == mLightState) {
pw.print("Unable to go light idle; stopped at ");
pw.println(lightStateToString(mLightState));
@@ -5076,19 +5094,19 @@
if (mNextLightIdleDelay != 0) {
pw.print(" mNextLightIdleDelay=");
TimeUtils.formatDuration(mNextLightIdleDelay, pw);
- if (mConstants.USE_WINDOW_ALARMS) {
- pw.print(" (flex=");
- TimeUtils.formatDuration(mNextLightIdleDelayFlex, pw);
- pw.println(")");
- } else {
- pw.println();
- }
+ pw.println();
}
if (mNextLightAlarmTime != 0) {
pw.print(" mNextLightAlarmTime=");
TimeUtils.formatDuration(mNextLightAlarmTime, SystemClock.elapsedRealtime(), pw);
pw.println();
}
+ if (mNextLightMaintenanceAlarmTime != 0) {
+ pw.print(" mNextLightMaintenanceAlarmTime=");
+ TimeUtils.formatDuration(
+ mNextLightMaintenanceAlarmTime, SystemClock.elapsedRealtime(), pw);
+ pw.println();
+ }
if (mCurLightIdleBudget != 0) {
pw.print(" mCurLightIdleBudget=");
TimeUtils.formatDuration(mCurLightIdleBudget, pw);
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index 1620983..a5c2bcc 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -72,6 +72,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.PermissionChecker;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.database.ContentObserver;
@@ -1839,6 +1840,9 @@
if (!isExactAlarmChangeEnabled(a.packageName, UserHandle.getUserId(a.uid))) {
return false;
}
+ if (hasUseExactAlarmPermission(a.packageName, a.uid)) {
+ return false;
+ }
return !isExemptFromExactAlarmPermission(a.uid);
};
removeAlarmsInternalLocked(whichAlarms, REMOVE_REASON_EXACT_PERMISSION_REVOKED);
@@ -1900,6 +1904,9 @@
|| !isExactAlarmChangeEnabled(packageName, userId)) {
return;
}
+ if (hasUseExactAlarmPermission(packageName, uid)) {
+ return;
+ }
final boolean requested = mExactAlarmCandidates.contains(
UserHandle.getAppId(uid));
@@ -2534,6 +2541,8 @@
private static boolean getScheduleExactAlarmState(boolean requested, boolean denyListed,
int appOpMode) {
+ // This does not account for the state of the USE_EXACT_ALARM permission.
+ // The caller should do that separately.
if (!requested) {
return false;
}
@@ -2543,7 +2552,16 @@
return appOpMode == AppOpsManager.MODE_ALLOWED;
}
+ boolean hasUseExactAlarmPermission(String packageName, int uid) {
+ return PermissionChecker.checkPermissionForPreflight(getContext(),
+ Manifest.permission.USE_EXACT_ALARM, PermissionChecker.PID_UNKNOWN, uid,
+ packageName) == PermissionChecker.PERMISSION_GRANTED;
+ }
+
boolean hasScheduleExactAlarmInternal(String packageName, int uid) {
+ if (hasUseExactAlarmPermission(packageName, uid)) {
+ return true;
+ }
// Not using getScheduleExactAlarmState as this can avoid some calls to AppOpsService.
// Not using #mLastOpScheduleExactAlarm as it may contain stale values.
// No locking needed as all internal containers being queried are immutable.
@@ -3759,6 +3777,9 @@
if (!isExactAlarmChangeEnabled(changedPackage, userId)) {
continue;
}
+ if (hasUseExactAlarmPermission(changedPackage, uid)) {
+ continue;
+ }
final int appOpMode;
synchronized (mLock) {
appOpMode = mLastOpScheduleExactAlarm.get(uid,
@@ -3778,7 +3799,8 @@
}
if (added) {
synchronized (mLock) {
- removeExactAlarmsOnPermissionRevokedLocked(uid, changedPackage);
+ removeExactAlarmsOnPermissionRevokedLocked(uid,
+ changedPackage, /*killUid = */ true);
}
} else {
sendScheduleExactAlarmPermissionStateChangedBroadcast(changedPackage, userId);
@@ -3794,7 +3816,7 @@
* This is not expected to get called frequently.
*/
@GuardedBy("mLock")
- void removeExactAlarmsOnPermissionRevokedLocked(int uid, String packageName) {
+ void removeExactAlarmsOnPermissionRevokedLocked(int uid, String packageName, boolean killUid) {
if (isExemptFromExactAlarmPermission(uid)
|| !isExactAlarmChangeEnabled(packageName, UserHandle.getUserId(uid))) {
return;
@@ -3805,7 +3827,7 @@
&& a.windowLength == 0);
removeAlarmsInternalLocked(whichAlarms, REMOVE_REASON_EXACT_PERMISSION_REVOKED);
- if (mConstants.KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED) {
+ if (killUid && mConstants.KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED) {
PermissionManagerService.killUid(UserHandle.getAppId(uid), UserHandle.getUserId(uid),
"schedule_exact_alarm revoked");
}
@@ -4617,6 +4639,7 @@
public static final int EXACT_ALARM_DENY_LIST_PACKAGES_REMOVED = 10;
public static final int REFRESH_EXACT_ALARM_CANDIDATES = 11;
public static final int TARE_AFFORDABILITY_CHANGED = 12;
+ public static final int CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE = 13;
AlarmHandler() {
super(Looper.myLooper());
@@ -4715,10 +4738,11 @@
break;
case REMOVE_EXACT_ALARMS:
- final int uid = msg.arg1;
- final String packageName = (String) msg.obj;
+ int uid = msg.arg1;
+ String packageName = (String) msg.obj;
synchronized (mLock) {
- removeExactAlarmsOnPermissionRevokedLocked(uid, packageName);
+ removeExactAlarmsOnPermissionRevokedLocked(uid, packageName, /*killUid = */
+ true);
}
break;
case EXACT_ALARM_DENY_LIST_PACKAGES_ADDED:
@@ -4730,6 +4754,16 @@
case REFRESH_EXACT_ALARM_CANDIDATES:
refreshExactAlarmCandidates();
break;
+ case CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE:
+ packageName = (String) msg.obj;
+ uid = msg.arg1;
+ if (!hasScheduleExactAlarmInternal(packageName, uid)) {
+ synchronized (mLock) {
+ removeExactAlarmsOnPermissionRevokedLocked(uid,
+ packageName, /*killUid = */false);
+ }
+ }
+ break;
default:
// nope, just ignore it
break;
@@ -4914,6 +4948,12 @@
}
break;
case Intent.ACTION_PACKAGE_ADDED:
+ if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+ final String packageUpdated = intent.getData().getSchemeSpecificPart();
+ mHandler.obtainMessage(
+ AlarmHandler.CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE, uid, -1,
+ packageUpdated).sendToTarget();
+ }
mHandler.sendEmptyMessage(AlarmHandler.REFRESH_EXACT_ALARM_CANDIDATES);
return;
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index cea1945..bdfdd55 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -52,6 +52,7 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
+import android.content.pm.ProviderInfo;
import android.content.pm.ServiceInfo;
import android.net.Uri;
import android.os.BatteryManager;
@@ -70,6 +71,7 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.WorkSource;
+import android.os.storage.StorageManagerInternal;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.text.format.DateUtils;
@@ -86,10 +88,10 @@
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
-import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
+import com.android.internal.os.SomeArgs;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FrameworkStatsLog;
@@ -237,6 +239,7 @@
static final int MSG_UID_ACTIVE = 6;
static final int MSG_UID_IDLE = 7;
static final int MSG_CHECK_CHANGED_JOB_LIST = 8;
+ static final int MSG_CHECK_MEDIA_EXEMPTION = 9;
/**
* Track Services that have currently active or pending jobs. The index is provided by
@@ -271,8 +274,8 @@
@GuardedBy("mLock")
private final BatteryStateTracker mBatteryStateTracker;
- @NonNull
- private final String mSystemGalleryPackage;
+ @GuardedBy("mLock")
+ private final SparseArray<String> mCloudMediaProviderPackages = new SparseArray<>();
private final CountQuotaTracker mQuotaTracker;
private static final String QUOTA_TRACKER_SCHEDULE_PERSISTED_TAG = ".schedulePersisted()";
@@ -417,6 +420,9 @@
break;
case Constants.KEY_CONN_CONGESTION_DELAY_FRAC:
case Constants.KEY_CONN_PREFETCH_RELAX_FRAC:
+ case Constants.KEY_CONN_LOW_SIGNAL_STRENGTH_RELAX_FRAC:
+ case Constants.KEY_CONN_USE_CELL_SIGNAL_STRENGTH:
+ case Constants.KEY_CONN_UPDATE_ALL_JOBS_MIN_INTERVAL_MS:
mConstants.updateConnectivityConstantsLocked();
break;
case Constants.KEY_PREFETCH_FORCE_BATCH_RELAX_THRESHOLD_MS:
@@ -489,6 +495,12 @@
private static final String KEY_MIN_EXP_BACKOFF_TIME_MS = "min_exp_backoff_time_ms";
private static final String KEY_CONN_CONGESTION_DELAY_FRAC = "conn_congestion_delay_frac";
private static final String KEY_CONN_PREFETCH_RELAX_FRAC = "conn_prefetch_relax_frac";
+ private static final String KEY_CONN_USE_CELL_SIGNAL_STRENGTH =
+ "conn_use_cell_signal_strength";
+ private static final String KEY_CONN_UPDATE_ALL_JOBS_MIN_INTERVAL_MS =
+ "conn_update_all_jobs_min_interval_ms";
+ private static final String KEY_CONN_LOW_SIGNAL_STRENGTH_RELAX_FRAC =
+ "conn_low_signal_strength_relax_frac";
private static final String KEY_PREFETCH_FORCE_BATCH_RELAX_THRESHOLD_MS =
"prefetch_force_batch_relax_threshold_ms";
private static final String KEY_ENABLE_API_QUOTAS = "enable_api_quotas";
@@ -514,6 +526,9 @@
private static final long DEFAULT_MIN_EXP_BACKOFF_TIME_MS = JobInfo.MIN_BACKOFF_MILLIS;
private static final float DEFAULT_CONN_CONGESTION_DELAY_FRAC = 0.5f;
private static final float DEFAULT_CONN_PREFETCH_RELAX_FRAC = 0.5f;
+ private static final boolean DEFAULT_CONN_USE_CELL_SIGNAL_STRENGTH = true;
+ private static final long DEFAULT_CONN_UPDATE_ALL_JOBS_MIN_INTERVAL_MS = MINUTE_IN_MILLIS;
+ private static final float DEFAULT_CONN_LOW_SIGNAL_STRENGTH_RELAX_FRAC = 0.5f;
private static final long DEFAULT_PREFETCH_FORCE_BATCH_RELAX_THRESHOLD_MS = HOUR_IN_MILLIS;
private static final boolean DEFAULT_ENABLE_API_QUOTAS = true;
private static final int DEFAULT_API_QUOTA_SCHEDULE_COUNT = 250;
@@ -569,6 +584,23 @@
* we consider matching it against a metered network.
*/
public float CONN_PREFETCH_RELAX_FRAC = DEFAULT_CONN_PREFETCH_RELAX_FRAC;
+ /**
+ * Whether to use the cell signal strength to determine if a particular job is eligible to
+ * run.
+ */
+ public boolean CONN_USE_CELL_SIGNAL_STRENGTH = DEFAULT_CONN_USE_CELL_SIGNAL_STRENGTH;
+ /**
+ * When throttling updating all tracked jobs, make sure not to update them more frequently
+ * than this value.
+ */
+ public long CONN_UPDATE_ALL_JOBS_MIN_INTERVAL_MS =
+ DEFAULT_CONN_UPDATE_ALL_JOBS_MIN_INTERVAL_MS;
+ /**
+ * The fraction of a job's running window that must pass before we consider running it on
+ * low signal strength networks.
+ */
+ public float CONN_LOW_SIGNAL_STRENGTH_RELAX_FRAC =
+ DEFAULT_CONN_LOW_SIGNAL_STRENGTH_RELAX_FRAC;
/**
* The amount of time within which we would consider the app to be launching relatively soon
@@ -661,6 +693,18 @@
CONN_PREFETCH_RELAX_FRAC = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
KEY_CONN_PREFETCH_RELAX_FRAC,
DEFAULT_CONN_PREFETCH_RELAX_FRAC);
+ CONN_USE_CELL_SIGNAL_STRENGTH = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_CONN_USE_CELL_SIGNAL_STRENGTH,
+ DEFAULT_CONN_USE_CELL_SIGNAL_STRENGTH);
+ CONN_UPDATE_ALL_JOBS_MIN_INTERVAL_MS = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_CONN_UPDATE_ALL_JOBS_MIN_INTERVAL_MS,
+ DEFAULT_CONN_UPDATE_ALL_JOBS_MIN_INTERVAL_MS);
+ CONN_LOW_SIGNAL_STRENGTH_RELAX_FRAC = DeviceConfig.getFloat(
+ DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_CONN_LOW_SIGNAL_STRENGTH_RELAX_FRAC,
+ DEFAULT_CONN_LOW_SIGNAL_STRENGTH_RELAX_FRAC);
}
private void updatePrefetchConstantsLocked() {
@@ -739,6 +783,11 @@
pw.print(KEY_MIN_EXP_BACKOFF_TIME_MS, MIN_EXP_BACKOFF_TIME_MS).println();
pw.print(KEY_CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC).println();
pw.print(KEY_CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC).println();
+ pw.print(KEY_CONN_USE_CELL_SIGNAL_STRENGTH, CONN_USE_CELL_SIGNAL_STRENGTH).println();
+ pw.print(KEY_CONN_UPDATE_ALL_JOBS_MIN_INTERVAL_MS, CONN_UPDATE_ALL_JOBS_MIN_INTERVAL_MS)
+ .println();
+ pw.print(KEY_CONN_LOW_SIGNAL_STRENGTH_RELAX_FRAC, CONN_LOW_SIGNAL_STRENGTH_RELAX_FRAC)
+ .println();
pw.print(KEY_PREFETCH_FORCE_BATCH_RELAX_THRESHOLD_MS,
PREFETCH_FORCE_BATCH_RELAX_THRESHOLD_MS).println();
@@ -1737,9 +1786,6 @@
mJobRestrictions = new ArrayList<>();
mJobRestrictions.add(new ThermalStatusRestriction(this));
- mSystemGalleryPackage = Objects.requireNonNull(
- context.getString(R.string.config_systemGallery));
-
// If the job store determined that it can't yet reschedule persisted jobs,
// we need to start watching the clock.
if (!mJobs.jobTimesInflatedValid()) {
@@ -1809,6 +1855,9 @@
mAppStateTracker = (AppStateTrackerImpl) Objects.requireNonNull(
LocalServices.getService(AppStateTracker.class));
+ LocalServices.getService(StorageManagerInternal.class)
+ .registerCloudProviderChangeListener(new CloudProviderChangeListener());
+
// Register br for package removals and user removals.
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
@@ -2307,6 +2356,15 @@
break;
}
+ case MSG_CHECK_MEDIA_EXEMPTION: {
+ final SomeArgs args = (SomeArgs) message.obj;
+ synchronized (mLock) {
+ updateMediaBackupExemptionLocked(
+ args.argi1, (String) args.arg1, (String) args.arg2);
+ }
+ args.recycle();
+ break;
+ }
}
maybeRunPendingJobsLocked();
}
@@ -2603,12 +2661,31 @@
if (DEBUG) {
Slog.d(TAG, "Check changed jobs...");
}
+ if (mChangedJobList.size() == 0) {
+ return;
+ }
mChangedJobList.forEach(mMaybeQueueFunctor);
mMaybeQueueFunctor.postProcessLocked();
mChangedJobList.clear();
}
+ @GuardedBy("mLock")
+ private void updateMediaBackupExemptionLocked(int userId, @Nullable String oldPkg,
+ @Nullable String newPkg) {
+ final Predicate<JobStatus> shouldProcessJob =
+ (job) -> job.getSourceUserId() == userId
+ && (job.getSourcePackageName().equals(oldPkg)
+ || job.getSourcePackageName().equals(newPkg));
+ mJobs.forEachJob(shouldProcessJob,
+ (job) -> {
+ if (job.updateMediaBackupExemptionStatus()) {
+ mChangedJobList.add(job);
+ }
+ });
+ mHandler.sendEmptyMessage(MSG_CHECK_CHANGED_JOB_LIST);
+ }
+
/** Returns true if both the calling and source users for the job are started. */
@GuardedBy("mLock")
public boolean areUsersStartedLocked(final JobStatus job) {
@@ -3004,8 +3081,8 @@
}
@Override
- public String getMediaBackupPackage() {
- return mSystemGalleryPackage;
+ public String getCloudMediaProviderPackage(int userId) {
+ return mCloudMediaProviderPackages.get(userId);
}
@Override
@@ -3113,6 +3190,35 @@
return bucket;
}
+ private class CloudProviderChangeListener implements
+ StorageManagerInternal.CloudProviderChangeListener {
+
+ @Override
+ public void onCloudProviderChanged(int userId, @Nullable String authority) {
+ final PackageManager pm = getContext()
+ .createContextAsUser(UserHandle.of(userId), 0)
+ .getPackageManager();
+ final ProviderInfo pi = pm.resolveContentProvider(
+ authority, PackageManager.ComponentInfoFlags.of(0));
+ final String newPkg = (pi == null) ? null : pi.packageName;
+ synchronized (mLock) {
+ final String oldPkg = mCloudMediaProviderPackages.get(userId);
+ if (!Objects.equals(oldPkg, newPkg)) {
+ if (DEBUG) {
+ Slog.d(TAG, "Cloud provider of user " + userId + " changed from " + oldPkg
+ + " to " + newPkg);
+ }
+ mCloudMediaProviderPackages.put(userId, newPkg);
+ SomeArgs args = SomeArgs.obtain();
+ args.argi1 = userId;
+ args.arg1 = oldPkg;
+ args.arg2 = newPkg;
+ mHandler.obtainMessage(MSG_CHECK_MEDIA_EXEMPTION, args).sendToTarget();
+ }
+ }
+ }
+ }
+
/**
* Binder stub trampoline implementation
*/
@@ -3753,6 +3859,12 @@
pw.println();
pw.println("Started users: " + Arrays.toString(mStartedUsers));
+ pw.println();
+
+ pw.print("Media Cloud Providers: ");
+ pw.println(mCloudMediaProviderPackages);
+ pw.println();
+
pw.print("Registered ");
pw.print(mJobs.size());
pw.println(" jobs:");
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index c678755..892e0c0 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -35,6 +35,10 @@
import android.os.Looper;
import android.os.Message;
import android.os.UserHandle;
+import android.telephony.CellSignalStrength;
+import android.telephony.SignalStrength;
+import android.telephony.TelephonyCallback;
+import android.telephony.TelephonyManager;
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -60,6 +64,7 @@
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
import java.util.function.Predicate;
/**
@@ -213,9 +218,16 @@
* is only done in {@link #maybeAdjustRegisteredCallbacksLocked()} and may sometimes be stale.
*/
private final List<UidStats> mSortedStats = new ArrayList<>();
+ @GuardedBy("mLock")
private long mLastCallbackAdjustmentTimeElapsed;
+ @GuardedBy("mLock")
+ private final SparseArray<CellSignalStrengthCallback> mSignalStrengths = new SparseArray<>();
+
+ @GuardedBy("mLock")
+ private long mLastAllJobUpdateTimeElapsed;
private static final int MSG_ADJUST_CALLBACKS = 0;
+ private static final int MSG_UPDATE_ALL_TRACKED_JOBS = 1;
private final Handler mHandler;
@@ -529,11 +541,7 @@
@GuardedBy("mLock")
public void onBatteryStateChangedLocked() {
// Update job bookkeeping out of band to avoid blocking broadcast progress.
- JobSchedulerBackgroundThread.getHandler().post(() -> {
- synchronized (mLock) {
- updateTrackedJobsLocked(-1, null);
- }
- });
+ mHandler.sendEmptyMessage(MSG_UPDATE_ALL_TRACKED_JOBS);
}
private boolean isUsable(NetworkCapabilities capabilities) {
@@ -650,6 +658,82 @@
}
}
+ @GuardedBy("mLock")
+ private boolean isStrongEnough(JobStatus jobStatus, NetworkCapabilities capabilities,
+ Constants constants) {
+ final int priority = jobStatus.getEffectivePriority();
+ if (priority >= JobInfo.PRIORITY_HIGH) {
+ return true;
+ }
+ if (!constants.CONN_USE_CELL_SIGNAL_STRENGTH) {
+ return true;
+ }
+ if (!capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
+ return true;
+ }
+ if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
+ // Exclude VPNs because it's currently not possible to determine the VPN's underlying
+ // network, and thus the correct signal strength of the VPN's network.
+ // Transmitting data over a VPN is generally more battery-expensive than on the
+ // underlying network, so:
+ // TODO: find a good way to reduce job use of VPN when it'll be very expensive
+ // For now, we just pretend VPNs are always strong enough
+ return true;
+ }
+
+ // VCNs running over WiFi will declare TRANSPORT_CELLULAR. When connected, a VCN will
+ // most likely be the default network. We ideally don't want this to restrict jobs when the
+ // VCN incorrectly declares the CELLULAR transport, but there's currently no way to
+ // determine if a network is a VCN. When there is:
+ // TODO(216127782): exclude VCN running over WiFi from this check
+
+ int signalStrength = CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+ // Use the best strength found.
+ final Set<Integer> subscriptionIds = capabilities.getSubscriptionIds();
+ for (int subId : subscriptionIds) {
+ CellSignalStrengthCallback callback = mSignalStrengths.get(subId);
+ if (callback != null) {
+ signalStrength = Math.max(signalStrength, callback.signalStrength);
+ } else {
+ Slog.wtf(TAG,
+ "Subscription ID " + subId + " doesn't have a registered callback");
+ }
+ }
+ if (DEBUG) {
+ Slog.d(TAG, "Cell signal strength for job=" + signalStrength);
+ }
+ // Treat "NONE_OR_UNKNOWN" as "NONE".
+ if (signalStrength <= CellSignalStrength.SIGNAL_STRENGTH_POOR) {
+ // If signal strength is poor, don't run MIN or LOW priority jobs, and only
+ // run DEFAULT priority jobs if the device is charging or the job has been waiting
+ // long enough.
+ if (priority > JobInfo.PRIORITY_DEFAULT) {
+ return true;
+ }
+ if (priority < JobInfo.PRIORITY_DEFAULT) {
+ return false;
+ }
+ // DEFAULT job.
+ return (mService.isBatteryCharging() && mService.isBatteryNotLow())
+ || jobStatus.getFractionRunTime() > constants.CONN_PREFETCH_RELAX_FRAC;
+ }
+ if (signalStrength <= CellSignalStrength.SIGNAL_STRENGTH_MODERATE) {
+ // If signal strength is moderate, only run MIN priority jobs when the device
+ // is charging, or the job is already running.
+ if (priority >= JobInfo.PRIORITY_LOW) {
+ return true;
+ }
+ // MIN job.
+ if (mService.isBatteryCharging() && mService.isBatteryNotLow()) {
+ return true;
+ }
+ final UidStats uidStats = getUidStats(
+ jobStatus.getSourceUid(), jobStatus.getSourcePackageName(), true);
+ return uidStats.runningJobs.contains(jobStatus);
+ }
+ return true;
+ }
+
private static NetworkCapabilities.Builder copyCapabilities(
@NonNull final NetworkRequest request) {
final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder();
@@ -717,10 +801,12 @@
// Second, is the network congested?
if (isCongestionDelayed(jobStatus, network, capabilities, constants)) return false;
- // Third, is the network a strict match?
+ if (!isStrongEnough(jobStatus, capabilities, constants)) return false;
+
+ // Is the network a strict match?
if (isStrictSatisfied(jobStatus, network, capabilities, constants)) return true;
- // Third, is the network a relaxed match?
+ // Is the network a relaxed match?
if (isRelaxedSatisfied(jobStatus, network, capabilities, constants)) return true;
return false;
@@ -985,6 +1071,24 @@
return changed;
}
+ @GuardedBy("mLock")
+ private void updateAllTrackedJobsLocked(boolean allowThrottle) {
+ if (allowThrottle) {
+ final long throttleTimeLeftMs =
+ (mLastAllJobUpdateTimeElapsed + mConstants.CONN_UPDATE_ALL_JOBS_MIN_INTERVAL_MS)
+ - sElapsedRealtimeClock.millis();
+ if (throttleTimeLeftMs > 0) {
+ Message msg = mHandler.obtainMessage(MSG_UPDATE_ALL_TRACKED_JOBS, 1, 0);
+ mHandler.sendMessageDelayed(msg, throttleTimeLeftMs);
+ return;
+ }
+ }
+
+ mHandler.removeMessages(MSG_UPDATE_ALL_TRACKED_JOBS);
+ updateTrackedJobsLocked(-1, null);
+ mLastAllJobUpdateTimeElapsed = sElapsedRealtimeClock.millis();
+ }
+
/**
* Update any jobs tracked by this controller that match given filters.
*
@@ -1088,7 +1192,11 @@
Slog.v(TAG, "onCapabilitiesChanged: " + network);
}
synchronized (mLock) {
- mAvailableNetworks.put(network, capabilities);
+ final NetworkCapabilities oldCaps = mAvailableNetworks.put(network, capabilities);
+ if (oldCaps != null) {
+ maybeUnregisterSignalStrengthCallbackLocked(oldCaps);
+ }
+ maybeRegisterSignalStrengthCallbackLocked(capabilities);
updateTrackedJobsLocked(-1, network);
postAdjustCallbacks();
}
@@ -1100,7 +1208,10 @@
Slog.v(TAG, "onLost: " + network);
}
synchronized (mLock) {
- mAvailableNetworks.remove(network);
+ final NetworkCapabilities capabilities = mAvailableNetworks.remove(network);
+ if (capabilities != null) {
+ maybeUnregisterSignalStrengthCallbackLocked(capabilities);
+ }
for (int u = 0; u < mCurrentDefaultNetworkCallbacks.size(); ++u) {
UidDefaultNetworkCallback callback = mCurrentDefaultNetworkCallbacks.valueAt(u);
if (Objects.equals(callback.mDefaultNetwork, network)) {
@@ -1111,6 +1222,63 @@
postAdjustCallbacks();
}
}
+
+ @GuardedBy("mLock")
+ private void maybeRegisterSignalStrengthCallbackLocked(
+ @NonNull NetworkCapabilities capabilities) {
+ if (!capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
+ return;
+ }
+ TelephonyManager telephonyManager = mContext.getSystemService(TelephonyManager.class);
+ final Set<Integer> subscriptionIds = capabilities.getSubscriptionIds();
+ for (int subId : subscriptionIds) {
+ if (mSignalStrengths.indexOfKey(subId) >= 0) {
+ continue;
+ }
+ TelephonyManager idTm = telephonyManager.createForSubscriptionId(subId);
+ CellSignalStrengthCallback callback = new CellSignalStrengthCallback();
+ idTm.registerTelephonyCallback(
+ JobSchedulerBackgroundThread.getExecutor(), callback);
+ mSignalStrengths.put(subId, callback);
+
+ final SignalStrength signalStrength = idTm.getSignalStrength();
+ if (signalStrength != null) {
+ callback.signalStrength = signalStrength.getLevel();
+ }
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void maybeUnregisterSignalStrengthCallbackLocked(
+ @NonNull NetworkCapabilities capabilities) {
+ if (!capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
+ return;
+ }
+ ArraySet<Integer> activeIds = new ArraySet<>();
+ for (int i = 0, size = mAvailableNetworks.size(); i < size; ++i) {
+ NetworkCapabilities nc = mAvailableNetworks.valueAt(i);
+ if (nc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
+ activeIds.addAll(nc.getSubscriptionIds());
+ }
+ }
+ if (DEBUG) {
+ Slog.d(TAG, "Active subscription IDs: " + activeIds);
+ }
+ TelephonyManager telephonyManager = mContext.getSystemService(TelephonyManager.class);
+ Set<Integer> subscriptionIds = capabilities.getSubscriptionIds();
+ for (int subId : subscriptionIds) {
+ if (activeIds.contains(subId)) {
+ continue;
+ }
+ TelephonyManager idTm = telephonyManager.createForSubscriptionId(subId);
+ CellSignalStrengthCallback callback = mSignalStrengths.removeReturnOld(subId);
+ if (callback != null) {
+ idTm.unregisterTelephonyCallback(callback);
+ } else {
+ Slog.wtf(TAG, "Callback for sub " + subId + " didn't exist?!?!");
+ }
+ }
+ }
};
private class CcHandler extends Handler {
@@ -1127,6 +1295,13 @@
maybeAdjustRegisteredCallbacksLocked();
}
break;
+
+ case MSG_UPDATE_ALL_TRACKED_JOBS:
+ synchronized (mLock) {
+ final boolean allowThrottle = msg.arg1 == 1;
+ updateAllTrackedJobsLocked(allowThrottle);
+ }
+ break;
}
}
}
@@ -1268,6 +1443,33 @@
}
}
+ private class CellSignalStrengthCallback extends TelephonyCallback
+ implements TelephonyCallback.SignalStrengthsListener {
+ @GuardedBy("mLock")
+ public int signalStrength = CellSignalStrength.SIGNAL_STRENGTH_GREAT;
+
+ @Override
+ public void onSignalStrengthsChanged(@NonNull SignalStrength signalStrength) {
+ synchronized (mLock) {
+ final int newSignalStrength = signalStrength.getLevel();
+ if (DEBUG) {
+ Slog.d(TAG, "Signal strength changing from "
+ + this.signalStrength + " to " + newSignalStrength);
+ for (CellSignalStrength css : signalStrength.getCellSignalStrengths()) {
+ Slog.d(TAG, "CSS: " + css.getLevel() + " " + css);
+ }
+ }
+ if (this.signalStrength == newSignalStrength) {
+ // This happens a lot.
+ return;
+ }
+ this.signalStrength = newSignalStrength;
+ // Update job bookkeeping out of band to avoid blocking callback progress.
+ mHandler.obtainMessage(MSG_UPDATE_ALL_TRACKED_JOBS, 1, 0).sendToTarget();
+ }
+ }
+ }
+
@GuardedBy("mLock")
@Override
public void dumpControllerStateLocked(IndentingPrintWriter pw,
@@ -1299,6 +1501,20 @@
}
pw.println();
+ if (mSignalStrengths.size() > 0) {
+ pw.println("Subscription ID signal strengths:");
+ pw.increaseIndent();
+ for (int i = 0; i < mSignalStrengths.size(); ++i) {
+ pw.print(mSignalStrengths.keyAt(i));
+ pw.print(": ");
+ pw.println(mSignalStrengths.valueAt(i).signalStrength);
+ }
+ pw.decreaseIndent();
+ } else {
+ pw.println("No cached signal strengths");
+ }
+ pw.println();
+
pw.println("Current default network callbacks:");
pw.increaseIndent();
for (int i = 0; i < mCurrentDefaultNetworkCallbacks.size(); i++) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index 0456a9b..649aa39 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -261,11 +261,9 @@
*
* Doesn't exempt jobs with a deadline constraint, as they can be started without any content or
* network changes, in which case this exemption does not make sense.
- *
- * TODO(b/149519887): Use a more explicit signal, maybe an API flag, that the scheduling package
- * needs to provide at the time of scheduling a job.
*/
- private final boolean mHasMediaBackupExemption;
+ private boolean mHasMediaBackupExemption;
+ private final boolean mHasExemptedMediaUrisOnly;
// Set to true if doze constraint was satisfied due to app being whitelisted.
boolean appHasDozeExemption;
@@ -508,11 +506,9 @@
this.mOriginalLatestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
this.numFailures = numFailures;
- boolean requiresNetwork = false;
int requiredConstraints = job.getConstraintFlags();
if (job.getRequiredNetwork() != null) {
requiredConstraints |= CONSTRAINT_CONNECTIVITY;
- requiresNetwork = true;
}
if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME) {
requiredConstraints |= CONSTRAINT_TIMING_DELAY;
@@ -531,6 +527,7 @@
}
}
}
+ mHasExemptedMediaUrisOnly = exemptedMediaUrisOnly;
this.requiredConstraints = requiredConstraints;
mRequiredConstraintsOfInterest = requiredConstraints & CONSTRAINTS_OF_INTEREST;
addDynamicConstraints(dynamicConstraints);
@@ -563,9 +560,7 @@
job = builder.build(false);
}
- final JobSchedulerInternal jsi = LocalServices.getService(JobSchedulerInternal.class);
- mHasMediaBackupExemption = !job.hasLateConstraint() && exemptedMediaUrisOnly
- && requiresNetwork && this.sourcePackageName.equals(jsi.getMediaBackupPackage());
+ updateMediaBackupExemptionStatus();
}
/** Copy constructor: used specifically when cloning JobStatus objects for persistence,
@@ -914,6 +909,25 @@
mFirstForceBatchedTimeElapsed = now;
}
+ /**
+ * Re-evaluates the media backup exemption status.
+ *
+ * @return true if the exemption status changed
+ */
+ public boolean updateMediaBackupExemptionStatus() {
+ final JobSchedulerInternal jsi = LocalServices.getService(JobSchedulerInternal.class);
+ boolean hasMediaExemption = mHasExemptedMediaUrisOnly
+ && !job.hasLateConstraint()
+ && job.getRequiredNetwork() != null
+ && getEffectivePriority() >= JobInfo.PRIORITY_DEFAULT
+ && sourcePackageName.equals(jsi.getCloudMediaProviderPackage(sourceUserId));
+ if (mHasMediaBackupExemption == hasMediaExemption) {
+ return false;
+ }
+ mHasMediaBackupExemption = hasMediaExemption;
+ return true;
+ }
+
public String getSourceTag() {
return sourceTag;
}
@@ -1139,11 +1153,12 @@
*/
public float getFractionRunTime() {
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
- if (earliestRunTimeElapsedMillis == 0 && latestRunTimeElapsedMillis == Long.MAX_VALUE) {
+ if (earliestRunTimeElapsedMillis == NO_EARLIEST_RUNTIME
+ && latestRunTimeElapsedMillis == NO_LATEST_RUNTIME) {
return 1;
- } else if (earliestRunTimeElapsedMillis == 0) {
+ } else if (earliestRunTimeElapsedMillis == NO_EARLIEST_RUNTIME) {
return now >= latestRunTimeElapsedMillis ? 1 : 0;
- } else if (latestRunTimeElapsedMillis == Long.MAX_VALUE) {
+ } else if (latestRunTimeElapsedMillis == NO_LATEST_RUNTIME) {
return now >= earliestRunTimeElapsedMillis ? 1 : 0;
} else {
if (now <= earliestRunTimeElapsedMillis) {
@@ -2026,6 +2041,7 @@
TimeUtils.formatDuration(job.getTriggerContentMaxDelay(), pw);
pw.println();
}
+ pw.print("Has media backup exemption", mHasMediaBackupExemption).println();
}
if (job.getExtras() != null && !job.getExtras().isDefinitelyEmpty()) {
pw.print("Extras: ");
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index 19f2537..b96055f 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -1099,7 +1099,7 @@
final long maxExecutionTimeRemainingMs =
mMaxExecutionTimeMs - stats.executionTimeInMaxPeriodMs;
- if (maxExecutionTimeRemainingMs <= 0) {
+ if (maxExecutionTimeRemainingMs < 0) {
return 0;
}
@@ -1110,7 +1110,7 @@
sessions, startMaxElapsed, maxExecutionTimeRemainingMs);
}
- if (allowedTimeRemainingMs <= 0) {
+ if (allowedTimeRemainingMs < 0) {
return 0;
}
diff --git a/core/api/current.txt b/core/api/current.txt
index 3b41a33..ea3830f 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -111,6 +111,8 @@
field public static final String MANAGE_MEDIA = "android.permission.MANAGE_MEDIA";
field public static final String MANAGE_ONGOING_CALLS = "android.permission.MANAGE_ONGOING_CALLS";
field public static final String MANAGE_OWN_CALLS = "android.permission.MANAGE_OWN_CALLS";
+ field public static final String MANAGE_WIFI_AUTO_JOIN = "android.permission.MANAGE_WIFI_AUTO_JOIN";
+ field public static final String MANAGE_WIFI_INTERFACES = "android.permission.MANAGE_WIFI_INTERFACES";
field public static final String MASTER_CLEAR = "android.permission.MASTER_CLEAR";
field public static final String MEDIA_CONTENT_CONTROL = "android.permission.MEDIA_CONTENT_CONTROL";
field public static final String MODIFY_AUDIO_SETTINGS = "android.permission.MODIFY_AUDIO_SETTINGS";
@@ -121,6 +123,7 @@
field public static final String NFC = "android.permission.NFC";
field public static final String NFC_PREFERRED_PAYMENT_INFO = "android.permission.NFC_PREFERRED_PAYMENT_INFO";
field public static final String NFC_TRANSACTION_EVENT = "android.permission.NFC_TRANSACTION_EVENT";
+ field public static final String OVERRIDE_WIFI_CONFIG = "android.permission.OVERRIDE_WIFI_CONFIG";
field public static final String PACKAGE_USAGE_STATS = "android.permission.PACKAGE_USAGE_STATS";
field @Deprecated public static final String PERSISTENT_ACTIVITY = "android.permission.PERSISTENT_ACTIVITY";
field public static final String POST_NOTIFICATIONS = "android.permission.POST_NOTIFICATIONS";
@@ -192,6 +195,7 @@
field public static final String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS";
field public static final String UPDATE_PACKAGES_WITHOUT_USER_ACTION = "android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION";
field public static final String USE_BIOMETRIC = "android.permission.USE_BIOMETRIC";
+ field public static final String USE_EXACT_ALARM = "android.permission.USE_EXACT_ALARM";
field @Deprecated public static final String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
field public static final String USE_FULL_SCREEN_INTENT = "android.permission.USE_FULL_SCREEN_INTENT";
field public static final String USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER = "android.permission.USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER";
@@ -339,6 +343,7 @@
field public static final int allowSingleTap = 16843353; // 0x1010259
field public static final int allowTaskReparenting = 16843268; // 0x1010204
field public static final int allowUndo = 16843999; // 0x10104df
+ field public static final int allowUntrustedActivityEmbedding;
field public static final int alpha = 16843551; // 0x101031f
field public static final int alphabeticModifiers = 16844110; // 0x101054e
field public static final int alphabeticShortcut = 16843235; // 0x10101e3
@@ -861,6 +866,7 @@
field public static final int installLocation = 16843447; // 0x10102b7
field public static final int interactiveUiTimeout = 16844181; // 0x1010595
field public static final int interpolator = 16843073; // 0x1010141
+ field public static final int intro;
field public static final int isAccessibilityTool = 16844353; // 0x1010641
field public static final int isAlwaysSyncable = 16843571; // 0x1010333
field public static final int isAsciiCapable = 16843753; // 0x10103e9
@@ -903,6 +909,7 @@
field public static final int keyboardNavigationCluster = 16844096; // 0x1010540
field public static final int keycode = 16842949; // 0x10100c5
field public static final int killAfterRestore = 16843420; // 0x101029c
+ field public static final int knownActivityEmbeddingCerts;
field public static final int knownCerts = 16844330; // 0x101062a
field public static final int lStar = 16844359; // 0x1010647
field public static final int label = 16842753; // 0x1010001
@@ -3062,8 +3069,10 @@
method @NonNull public final android.accessibilityservice.AccessibilityButtonController getAccessibilityButtonController();
method @NonNull public final android.accessibilityservice.AccessibilityButtonController getAccessibilityButtonController(int);
method @NonNull @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public final android.accessibilityservice.FingerprintGestureController getFingerprintGestureController();
+ method @Nullable public final android.accessibilityservice.InputMethod getInputMethod();
method @NonNull public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
+ method @Nullable public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow(int);
method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
method @NonNull public final android.accessibilityservice.AccessibilityService.SoftKeyboardController getSoftKeyboardController();
method @NonNull public final java.util.List<android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction> getSystemActions();
@@ -3074,6 +3083,7 @@
method public boolean isNodeInCache(@NonNull android.view.accessibility.AccessibilityNodeInfo);
method public abstract void onAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
method public final android.os.IBinder onBind(android.content.Intent);
+ method @NonNull public android.accessibilityservice.InputMethod onCreateInputMethod();
method @Deprecated protected boolean onGesture(int);
method public boolean onGesture(@NonNull android.accessibilityservice.AccessibilityGestureEvent);
method public abstract void onInterrupt();
@@ -3238,6 +3248,7 @@
method @Nullable public String getTileServiceClassName();
method public boolean isAccessibilityTool();
method public String loadDescription(android.content.pm.PackageManager);
+ method @Nullable public CharSequence loadIntro(@NonNull android.content.pm.PackageManager);
method public CharSequence loadSummary(android.content.pm.PackageManager);
method public void setInteractiveUiTimeoutMillis(@IntRange(from=0) int);
method public void setNonInteractiveUiTimeoutMillis(@IntRange(from=0) int);
@@ -3261,6 +3272,7 @@
field public static final int FEEDBACK_VISUAL = 8; // 0x8
field public static final int FLAG_ENABLE_ACCESSIBILITY_VOLUME = 128; // 0x80
field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
+ field public static final int FLAG_INPUT_METHOD_EDITOR = 32768; // 0x8000
field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
field public static final int FLAG_REQUEST_2_FINGER_PASSTHROUGH = 8192; // 0x2000
field public static final int FLAG_REQUEST_ACCESSIBILITY_BUTTON = 256; // 0x100
@@ -3321,6 +3333,28 @@
method public boolean willContinue();
}
+ public class InputMethod {
+ ctor protected InputMethod(@NonNull android.accessibilityservice.AccessibilityService);
+ method @Nullable public final android.accessibilityservice.InputMethod.AccessibilityInputConnection getCurrentInputConnection();
+ method @Nullable public final android.view.inputmethod.EditorInfo getCurrentInputEditorInfo();
+ method public final boolean getCurrentInputStarted();
+ method public void onFinishInput();
+ method public void onStartInput(@NonNull android.view.inputmethod.EditorInfo, boolean);
+ method public void onUpdateSelection(int, int, int, int, int, int);
+ }
+
+ public final class InputMethod.AccessibilityInputConnection {
+ method public void clearMetaKeyStates(int);
+ method public void commitText(@NonNull CharSequence, int, @Nullable android.view.inputmethod.TextAttribute);
+ method public void deleteSurroundingText(int, int);
+ method public int getCursorCapsMode(int);
+ method @Nullable public android.view.inputmethod.SurroundingText getSurroundingText(@IntRange(from=0) int, @IntRange(from=0) int, int);
+ method public void performContextMenuAction(int);
+ method public void performEditorAction(int);
+ method public void sendKeyEvent(@NonNull android.view.KeyEvent);
+ method public void setSelection(int, int);
+ }
+
public final class MagnificationConfig implements android.os.Parcelable {
method public int describeContents();
method public float getCenterX();
@@ -4244,6 +4278,7 @@
method @Deprecated public final void setProgressBarIndeterminate(boolean);
method @Deprecated public final void setProgressBarIndeterminateVisibility(boolean);
method @Deprecated public final void setProgressBarVisibility(boolean);
+ method public void setRecentsScreenshotEnabled(boolean);
method public void setRequestedOrientation(int);
method public final void setResult(int);
method public final void setResult(int, android.content.Intent);
@@ -4506,6 +4541,7 @@
method @Nullable public android.graphics.Rect getLaunchBounds();
method public int getLaunchDisplayId();
method public boolean getLockTaskMode();
+ method public int getSplashScreenStyle();
method public boolean isPendingIntentBackgroundActivityLaunchAllowed();
method public static android.app.ActivityOptions makeBasic();
method public static android.app.ActivityOptions makeClipRevealAnimation(android.view.View, int, int, int, int);
@@ -6600,6 +6636,7 @@
method public android.app.PictureInPictureParams.Builder setActions(java.util.List<android.app.RemoteAction>);
method public android.app.PictureInPictureParams.Builder setAspectRatio(android.util.Rational);
method @NonNull public android.app.PictureInPictureParams.Builder setAutoEnterEnabled(boolean);
+ method @NonNull public android.app.PictureInPictureParams.Builder setExpandedAspectRatio(@Nullable android.util.Rational);
method @NonNull public android.app.PictureInPictureParams.Builder setSeamlessResizeEnabled(boolean);
method public android.app.PictureInPictureParams.Builder setSourceRectHint(android.graphics.Rect);
}
@@ -7012,6 +7049,7 @@
public final class VoiceInteractor {
method public android.app.VoiceInteractor.Request getActiveRequest(String);
method public android.app.VoiceInteractor.Request[] getActiveRequests();
+ method @NonNull public String getPackageName();
method public boolean isDestroyed();
method public void notifyDirectActionsChanged();
method public boolean registerOnDestroyedCallback(@NonNull java.util.concurrent.Executor, @NonNull Runnable);
@@ -7335,6 +7373,7 @@
method public int getCurrentFailedPasswordAttempts();
method @Nullable public java.util.List<java.lang.String> getDelegatePackages(@NonNull android.content.ComponentName, @NonNull String);
method @NonNull public java.util.List<java.lang.String> getDelegatedScopes(@Nullable android.content.ComponentName, @NonNull String);
+ method @Nullable public String getDeviceManagerRoleHolderPackageName();
method public CharSequence getDeviceOwnerLockScreenInfo();
method @Nullable public android.graphics.drawable.Drawable getDrawable(@NonNull String, @NonNull String, @NonNull java.util.concurrent.Callable<android.graphics.drawable.Drawable>);
method @Nullable public android.graphics.drawable.Drawable getDrawable(@NonNull String, @NonNull String, @NonNull String, @NonNull java.util.concurrent.Callable<android.graphics.drawable.Drawable>);
@@ -7630,6 +7669,7 @@
field public static final String EXTRA_PROVISIONING_MODE = "android.app.extra.PROVISIONING_MODE";
field public static final String EXTRA_PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT = "android.app.extra.PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT";
field public static final String EXTRA_PROVISIONING_SERIAL_NUMBER = "android.app.extra.PROVISIONING_SERIAL_NUMBER";
+ field public static final String EXTRA_PROVISIONING_SHOULD_LAUNCH_RESULT_INTENT = "android.app.extra.PROVISIONING_SHOULD_LAUNCH_RESULT_INTENT";
field public static final String EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS = "android.app.extra.PROVISIONING_SKIP_EDUCATION_SCREENS";
field public static final String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
field @Deprecated public static final String EXTRA_PROVISIONING_SKIP_USER_CONSENT = "android.app.extra.PROVISIONING_SKIP_USER_CONSENT";
@@ -7652,6 +7692,7 @@
field public static final String EXTRA_RESOURCE_ID = "android.app.extra.RESOURCE_ID";
field public static final String EXTRA_RESOURCE_TYPE_DRAWABLE = "android.app.extra.RESOURCE_TYPE_DRAWABLE";
field public static final String EXTRA_RESOURCE_TYPE_STRING = "android.app.extra.RESOURCE_TYPE_STRING";
+ field public static final String EXTRA_RESULT_LAUNCH_INTENT = "android.app.extra.RESULT_LAUNCH_INTENT";
field public static final int FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY = 1; // 0x1
field public static final int FLAG_MANAGED_CAN_ACCESS_PARENT = 2; // 0x2
field public static final int FLAG_PARENT_CAN_ACCESS_MANAGED = 1; // 0x1
@@ -7850,6 +7891,8 @@
field public static final int TAG_ADB_SHELL_CMD = 210002; // 0x33452
field public static final int TAG_ADB_SHELL_INTERACTIVE = 210001; // 0x33451
field public static final int TAG_APP_PROCESS_START = 210005; // 0x33455
+ field public static final int TAG_BLUETOOTH_CONNECTION = 210039; // 0x33477
+ field public static final int TAG_BLUETOOTH_DISCONNECTION = 210040; // 0x33478
field public static final int TAG_CAMERA_POLICY_SET = 210034; // 0x33472
field public static final int TAG_CERT_AUTHORITY_INSTALLED = 210029; // 0x3346d
field public static final int TAG_CERT_AUTHORITY_REMOVED = 210030; // 0x3346e
@@ -7872,6 +7915,7 @@
field public static final int TAG_MEDIA_UNMOUNT = 210014; // 0x3345e
field public static final int TAG_OS_SHUTDOWN = 210010; // 0x3345a
field public static final int TAG_OS_STARTUP = 210009; // 0x33459
+ field public static final int TAG_PASSWORD_CHANGED = 210036; // 0x33474
field public static final int TAG_PASSWORD_COMPLEXITY_REQUIRED = 210035; // 0x33473
field public static final int TAG_PASSWORD_COMPLEXITY_SET = 210017; // 0x33461
field public static final int TAG_PASSWORD_EXPIRATION_SET = 210016; // 0x33460
@@ -7881,6 +7925,8 @@
field public static final int TAG_SYNC_SEND_FILE = 210004; // 0x33454
field public static final int TAG_USER_RESTRICTION_ADDED = 210027; // 0x3346b
field public static final int TAG_USER_RESTRICTION_REMOVED = 210028; // 0x3346c
+ field public static final int TAG_WIFI_CONNECTION = 210037; // 0x33475
+ field public static final int TAG_WIFI_DISCONNECTION = 210038; // 0x33476
field public static final int TAG_WIPE_FAILURE = 210023; // 0x33467
}
@@ -10934,6 +10980,7 @@
ctor public ActivityInfo(android.content.pm.ActivityInfo);
method public int describeContents();
method public void dump(android.util.Printer, String);
+ method @NonNull public java.util.Set<java.lang.String> getKnownActivityEmbeddingCerts();
method public final int getThemeResource();
field public static final int COLOR_MODE_DEFAULT = 0; // 0x0
field public static final int COLOR_MODE_HDR = 2; // 0x2
@@ -10961,6 +11008,7 @@
field public static final int DOCUMENT_LAUNCH_NEVER = 3; // 0x3
field public static final int DOCUMENT_LAUNCH_NONE = 0; // 0x0
field public static final int FLAG_ALLOW_TASK_REPARENTING = 64; // 0x40
+ field public static final int FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING = 268435456; // 0x10000000
field public static final int FLAG_ALWAYS_RETAIN_TASK_STATE = 8; // 0x8
field public static final int FLAG_AUTO_REMOVE_FROM_RECENTS = 8192; // 0x2000
field public static final int FLAG_CLEAR_TASK_ON_LAUNCH = 4; // 0x4
@@ -11050,6 +11098,7 @@
method public void dump(android.util.Printer, String);
method public static CharSequence getCategoryTitle(android.content.Context, int);
method public int getGwpAsanMode();
+ method @NonNull public java.util.Set<java.lang.String> getKnownActivityEmbeddingCerts();
method public int getMemtagMode();
method public int getNativeHeapZeroInitialized();
method public int getRequestRawExternalStorageAccess();
@@ -11819,6 +11868,7 @@
field public static final String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
field public static final String FEATURE_EMBEDDED = "android.hardware.type.embedded";
field public static final String FEATURE_ETHERNET = "android.hardware.ethernet";
+ field public static final String FEATURE_EXPANDED_PICTURE_IN_PICTURE = "android.software.expanded_picture_in_picture";
field public static final String FEATURE_FACE = "android.hardware.biometrics.face";
field public static final String FEATURE_FAKETOUCH = "android.hardware.faketouch";
field public static final String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
@@ -17330,6 +17380,7 @@
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Size> SCALER_DEFAULT_SECURE_IMAGE_SIZE;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_MAXIMUM_RESOLUTION_STREAM_COMBINATIONS;
+ field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_PREVIEW_STABILIZATION_OUTPUT_STREAM_COMBINATIONS;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_STREAM_COMBINATIONS;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_TEN_BIT_OUTPUT_STREAM_COMBINATIONS;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_USE_CASE_STREAM_COMBINATIONS;
@@ -18165,6 +18216,7 @@
method public void enableSurfaceSharing();
method public int getDynamicRangeProfile();
method public int getMaxSharedSurfaceCount();
+ method public int getMirrorMode();
method public int getStreamUseCase();
method @Nullable public android.view.Surface getSurface();
method public int getSurfaceGroupId();
@@ -18173,11 +18225,16 @@
method public void removeSensorPixelModeUsed(int);
method public void removeSurface(@NonNull android.view.Surface);
method public void setDynamicRangeProfile(int);
+ method public void setMirrorMode(int);
method public void setPhysicalCameraId(@Nullable String);
method public void setStreamUseCase(int);
method public void setTimestampBase(int);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.camera2.params.OutputConfiguration> CREATOR;
+ field public static final int MIRROR_MODE_AUTO = 0; // 0x0
+ field public static final int MIRROR_MODE_H = 2; // 0x2
+ field public static final int MIRROR_MODE_NONE = 1; // 0x1
+ field public static final int MIRROR_MODE_V = 3; // 0x3
field public static final int SURFACE_GROUP_ID_NONE = -1; // 0xffffffff
field public static final int TIMESTAMP_BASE_CHOREOGRAPHER_SYNCED = 4; // 0x4
field public static final int TIMESTAMP_BASE_DEFAULT = 0; // 0x0
@@ -18304,8 +18361,8 @@
}
public final class DisplayManager {
- method public android.hardware.display.VirtualDisplay createVirtualDisplay(@NonNull String, int, int, int, @Nullable android.view.Surface, int);
- method public android.hardware.display.VirtualDisplay createVirtualDisplay(@NonNull String, int, int, int, @Nullable android.view.Surface, int, @Nullable android.hardware.display.VirtualDisplay.Callback, @Nullable android.os.Handler);
+ method public android.hardware.display.VirtualDisplay createVirtualDisplay(@NonNull String, @IntRange(from=1) int, @IntRange(from=1) int, @IntRange(from=1) int, @Nullable android.view.Surface, int);
+ method public android.hardware.display.VirtualDisplay createVirtualDisplay(@NonNull String, @IntRange(from=1) int, @IntRange(from=1) int, @IntRange(from=1) int, @Nullable android.view.Surface, int, @Nullable android.hardware.display.VirtualDisplay.Callback, @Nullable android.os.Handler);
method public android.view.Display getDisplay(int);
method public android.view.Display[] getDisplays();
method public android.view.Display[] getDisplays(String);
@@ -23352,7 +23409,6 @@
method @NonNull public java.util.List<java.lang.String> getAllowedPackages();
method @NonNull public java.util.List<java.lang.String> getDeduplicationPackageOrder();
method @NonNull public java.util.List<java.lang.String> getPreferredFeatures();
- method @NonNull public java.util.List<java.lang.String> getRequiredFeatures();
method public boolean shouldPerformActiveScan();
method public boolean shouldRemoveDuplicates();
method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -23366,7 +23422,6 @@
method @NonNull public android.media.RouteDiscoveryPreference.Builder setAllowedPackages(@NonNull java.util.List<java.lang.String>);
method @NonNull public android.media.RouteDiscoveryPreference.Builder setDeduplicationPackageOrder(@NonNull java.util.List<java.lang.String>);
method @NonNull public android.media.RouteDiscoveryPreference.Builder setPreferredFeatures(@NonNull java.util.List<java.lang.String>);
- method @NonNull public android.media.RouteDiscoveryPreference.Builder setRequiredFeatures(@NonNull java.util.List<java.lang.String>);
method @NonNull public android.media.RouteDiscoveryPreference.Builder setShouldPerformActiveScan(boolean);
}
@@ -24324,6 +24379,17 @@
package android.media.metrics {
+ public final class BundleSession implements java.lang.AutoCloseable {
+ method public void close();
+ method @NonNull public android.media.metrics.LogSessionId getSessionId();
+ method public void reportBundleMetrics(@NonNull android.os.PersistableBundle);
+ }
+
+ public final class EditingSession implements java.lang.AutoCloseable {
+ method public void close();
+ method @NonNull public android.media.metrics.LogSessionId getSessionId();
+ }
+
public abstract class Event {
method @NonNull public android.os.Bundle getMetricsBundle();
method @IntRange(from=0xffffffff) public long getTimeSinceCreatedMillis();
@@ -24335,8 +24401,11 @@
}
public final class MediaMetricsManager {
+ method @NonNull public android.media.metrics.BundleSession createBundleSession();
+ method @NonNull public android.media.metrics.EditingSession createEditingSession();
method @NonNull public android.media.metrics.PlaybackSession createPlaybackSession();
method @NonNull public android.media.metrics.RecordingSession createRecordingSession();
+ method @NonNull public android.media.metrics.TranscodingSession createTranscodingSession();
field public static final long INVALID_TIMESTAMP = -1L; // 0xffffffffffffffffL
}
@@ -24584,6 +24653,11 @@
method @NonNull public android.media.metrics.TrackChangeEvent.Builder setWidth(@IntRange(from=0xffffffff, to=java.lang.Integer.MAX_VALUE) int);
}
+ public final class TranscodingSession implements java.lang.AutoCloseable {
+ method public void close();
+ method @NonNull public android.media.metrics.LogSessionId getSessionId();
+ }
+
}
package android.media.midi {
@@ -26408,6 +26482,14 @@
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();
@@ -26433,10 +26515,11 @@
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);
+ method @NonNull public android.net.Ikev2VpnProfile.Builder setRequiresInternetValidation(boolean);
}
public class LocalServerSocket implements java.io.Closeable {
@@ -26510,7 +26593,8 @@
}
public abstract class PlatformVpnProfile {
- method public final boolean getExcludeLocalRoutes();
+ method public final boolean areLocalRoutesExcluded();
+ method public final boolean getRequiresInternetValidation();
method public final int getType();
method @NonNull public final String getTypeString();
field public static final int TYPE_IKEV2_IPSEC_PSK = 7; // 0x7
@@ -26706,6 +26790,23 @@
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 = "android.net.extra.TIMESTAMP";
+ 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 {
@@ -31996,6 +32097,7 @@
method public boolean isDemoUser();
method public static boolean isHeadlessSystemUserMode();
method public boolean isManagedProfile();
+ method public boolean isProfile();
method public boolean isQuietModeEnabled(android.os.UserHandle);
method public boolean isSystemUser();
method public boolean isUserAGoat();
@@ -38831,6 +38933,7 @@
field public static final int NOTIFICATION_CHANNEL_OR_GROUP_UPDATED = 2; // 0x2
field public static final int REASON_APP_CANCEL = 8; // 0x8
field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
+ field public static final int REASON_ASSISTANT_CANCEL = 22; // 0x16
field public static final int REASON_CANCEL = 2; // 0x2
field public static final int REASON_CANCEL_ALL = 3; // 0x3
field public static final int REASON_CHANNEL_BANNED = 17; // 0x11
@@ -39427,9 +39530,9 @@
public static final class RecognitionSupport.Builder {
ctor public RecognitionSupport.Builder();
- method @NonNull public android.speech.RecognitionSupport.Builder addInstalledLanguages(@NonNull String);
- method @NonNull public android.speech.RecognitionSupport.Builder addPendingLanguages(@NonNull String);
- method @NonNull public android.speech.RecognitionSupport.Builder addSupportedLanguages(@NonNull String);
+ method @NonNull public android.speech.RecognitionSupport.Builder addInstalledLanguage(@NonNull String);
+ method @NonNull public android.speech.RecognitionSupport.Builder addPendingLanguage(@NonNull String);
+ method @NonNull public android.speech.RecognitionSupport.Builder addSupportedLanguage(@NonNull String);
method @NonNull public android.speech.RecognitionSupport build();
method @NonNull public android.speech.RecognitionSupport.Builder setInstalledLanguages(@NonNull java.util.List<java.lang.String>);
method @NonNull public android.speech.RecognitionSupport.Builder setPendingLanguages(@NonNull java.util.List<java.lang.String>);
@@ -41298,13 +41401,13 @@
field public static final int IPSEC_ENCRYPTION_ALGORITHM_AES_CBC = 2; // 0x2
field public static final int IPSEC_ENCRYPTION_ALGORITHM_DES_EDE3_CBC = 1; // 0x1
field public static final int IPSEC_ENCRYPTION_ALGORITHM_NULL = 0; // 0x0
- field public static final String KEY_CAPABILITY_CALL_COMPOSER_INT_ARRAY = "ims.key_capability_type_call_composer_int_array";
- field public static final String KEY_CAPABILITY_TYPE_OPTIONS_UCE_INT_ARRAY = "ims.key_capability_type_options_uce_int_array";
- field public static final String KEY_CAPABILITY_TYPE_PRESENCE_UCE_INT_ARRAY = "ims.key_capability_type_presence_uce_int_array";
- field public static final String KEY_CAPABILITY_TYPE_SMS_INT_ARRAY = "ims.key_capability_type_sms_int_array";
- field public static final String KEY_CAPABILITY_TYPE_UT_INT_ARRAY = "ims.key_capability_type_ut_int_array";
- field public static final String KEY_CAPABILITY_TYPE_VIDEO_INT_ARRAY = "ims.key_capability_type_video_int_array";
- field public static final String KEY_CAPABILITY_TYPE_VOICE_INT_ARRAY = "ims.key_capability_type_voice_int_array";
+ 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";
@@ -41345,6 +41448,7 @@
field public static final String KEY_SIP_TIMER_T2_MILLIS_INT = "ims.sip_timer_t2_millis_int";
field public static final String KEY_SIP_TIMER_T4_MILLIS_INT = "ims.sip_timer_t4_millis_int";
field public static final String KEY_SUPPORTED_RATS_INT_ARRAY = "ims.supported_rats_int_array";
+ 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";
field public static final int NETWORK_TYPE_HOME = 0; // 0x0
field public static final int NETWORK_TYPE_ROAMING = 1; // 0x1
@@ -43275,6 +43379,7 @@
method public boolean isVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle);
method public boolean isWorldPhone();
method @Deprecated public void listen(android.telephony.PhoneStateListener, int);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void rebootModem();
method public void registerTelephonyCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyCallback);
method public void registerTelephonyCallback(boolean, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyCallback);
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void requestCellInfoUpdate(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
@@ -46804,6 +46909,7 @@
public interface DumpableContainer {
method public boolean addDumpable(@NonNull android.util.Dumpable);
+ method public boolean removeDumpable(@NonNull android.util.Dumpable);
}
public class EventLog {
@@ -51557,6 +51663,7 @@
method @Deprecated public void getBoundsInParent(android.graphics.Rect);
method public void getBoundsInScreen(android.graphics.Rect);
method public android.view.accessibility.AccessibilityNodeInfo getChild(int);
+ method @Nullable public android.view.accessibility.AccessibilityNodeInfo getChild(int, int);
method public int getChildCount();
method public CharSequence getClassName();
method public android.view.accessibility.AccessibilityNodeInfo.CollectionInfo getCollectionInfo();
@@ -51576,6 +51683,7 @@
method public CharSequence getPackageName();
method @Nullable public CharSequence getPaneTitle();
method public android.view.accessibility.AccessibilityNodeInfo getParent();
+ method @Nullable public android.view.accessibility.AccessibilityNodeInfo getParent(int);
method public android.view.accessibility.AccessibilityNodeInfo.RangeInfo getRangeInfo();
method @Nullable public CharSequence getStateDescription();
method public CharSequence getText();
@@ -51726,8 +51834,15 @@
field public static final int EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_MAX_LENGTH = 20000; // 0x4e20
field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX";
field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_KEY";
+ field public static final int FLAG_PREFETCH_ANCESTORS = 1; // 0x1
+ field public static final int FLAG_PREFETCH_DESCENDANTS_BREADTH_FIRST = 16; // 0x10
+ field public static final int FLAG_PREFETCH_DESCENDANTS_DEPTH_FIRST = 8; // 0x8
+ field public static final int FLAG_PREFETCH_DESCENDANTS_HYBRID = 4; // 0x4
+ field public static final int FLAG_PREFETCH_SIBLINGS = 2; // 0x2
+ field public static final int FLAG_PREFETCH_UNINTERRUPTIBLE = 32; // 0x20
field public static final int FOCUS_ACCESSIBILITY = 2; // 0x2
field public static final int FOCUS_INPUT = 1; // 0x1
+ field public static final int MAX_NUMBER_OF_PREFETCHED_NODES = 50; // 0x32
field public static final int MOVEMENT_GRANULARITY_CHARACTER = 1; // 0x1
field public static final int MOVEMENT_GRANULARITY_LINE = 4; // 0x4
field public static final int MOVEMENT_GRANULARITY_PAGE = 16; // 0x10
@@ -51892,6 +52007,7 @@
method public int getScrollX();
method public int getScrollY();
method @Nullable public android.view.accessibility.AccessibilityNodeInfo getSource();
+ method @Nullable public android.view.accessibility.AccessibilityNodeInfo getSource(int);
method @NonNull public java.util.List<java.lang.CharSequence> getText();
method public int getToIndex();
method public int getWindowId();
@@ -51949,6 +52065,7 @@
method public android.view.accessibility.AccessibilityWindowInfo getParent();
method public void getRegionInScreen(@NonNull android.graphics.Region);
method public android.view.accessibility.AccessibilityNodeInfo getRoot();
+ method @Nullable public android.view.accessibility.AccessibilityNodeInfo getRoot(int);
method @Nullable public CharSequence getTitle();
method public int getType();
method public boolean isAccessibilityFocused();
@@ -51975,8 +52092,8 @@
method @NonNull public android.view.accessibility.CaptioningManager.CaptionStyle getUserStyle();
method public boolean isCallCaptioningEnabled();
method public final boolean isEnabled();
- method public final boolean isSystemAudioCaptioningRequested();
- method public final boolean isSystemAudioCaptioningUiRequested();
+ method public final boolean isSystemAudioCaptioningEnabled();
+ method public final boolean isSystemAudioCaptioningUiEnabled();
method public void removeCaptioningChangeListener(@NonNull android.view.accessibility.CaptioningManager.CaptioningChangeListener);
}
@@ -52333,6 +52450,8 @@
method public void requestAutofill(@NonNull android.view.View, int, @NonNull android.graphics.Rect);
method public void setAutofillRequestCallback(@NonNull java.util.concurrent.Executor, @NonNull android.view.autofill.AutofillRequestCallback);
method public void setUserData(@Nullable android.service.autofill.UserData);
+ method public boolean showAutofillDialog(@NonNull android.view.View);
+ method public boolean showAutofillDialog(@NonNull android.view.View, int);
method public void unregisterCallback(@Nullable android.view.autofill.AutofillManager.AutofillCallback);
field public static final String EXTRA_ASSIST_STRUCTURE = "android.view.autofill.extra.ASSIST_STRUCTURE";
field public static final String EXTRA_AUTHENTICATION_RESULT = "android.view.autofill.extra.AUTHENTICATION_RESULT";
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 36d54f5..594f46b 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -250,12 +250,20 @@
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 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 interface EthernetManager.InterfaceStateListener {
+ method public void onInterfaceStateChanged(@NonNull String, int, int, @Nullable android.net.IpConfiguration);
}
public class LocalSocket implements java.io.Closeable {
@@ -407,6 +415,7 @@
method public long computeStorageCacheBytes(@NonNull java.io.File);
method public void notifyAppIoBlocked(@NonNull java.util.UUID, int, int, int);
method public void notifyAppIoResumed(@NonNull java.util.UUID, int, int, int);
+ method public void setCloudMediaProvider(@Nullable String);
field public static final int APP_IO_BLOCKED_REASON_TRANSCODING = 1; // 0x1
field public static final int APP_IO_BLOCKED_REASON_UNKNOWN = 0; // 0x0
}
@@ -474,6 +483,25 @@
method public static int logToRadioBuffer(int, @Nullable String, @Nullable String);
}
+ public final class Slog {
+ method public static int d(@Nullable String, @NonNull String);
+ method public static int d(@Nullable String, @NonNull String, @Nullable Throwable);
+ method public static int e(@Nullable String, @NonNull String);
+ method public static int e(@Nullable String, @NonNull String, @Nullable Throwable);
+ method public static int i(@Nullable String, @NonNull String);
+ method public static int i(@Nullable String, @NonNull String, @Nullable Throwable);
+ method public static int v(@Nullable String, @NonNull String);
+ method public static int v(@Nullable String, @NonNull String, @Nullable Throwable);
+ method public static int w(@Nullable String, @NonNull String);
+ method public static int w(@Nullable String, @NonNull String, @Nullable Throwable);
+ method public static int w(@Nullable String, @Nullable Throwable);
+ method public static int wtf(@Nullable String, @NonNull String);
+ method public static int wtf(@Nullable String, @Nullable Throwable);
+ method public static int wtf(@Nullable String, @NonNull String, @Nullable Throwable);
+ method public static void wtfQuiet(@Nullable String, @NonNull String);
+ method public static int wtfStack(@Nullable String, @NonNull String);
+ }
+
public class SystemConfigFileCommitEventLogger {
ctor public SystemConfigFileCommitEventLogger(@NonNull String);
method public void setStartTime(long);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 01e2414..297239a 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -195,7 +195,6 @@
field public static final String MANAGE_USER_OEM_UNLOCK_STATE = "android.permission.MANAGE_USER_OEM_UNLOCK_STATE";
field public static final String MANAGE_WALLPAPER_EFFECTS_GENERATION = "android.permission.MANAGE_WALLPAPER_EFFECTS_GENERATION";
field public static final String MANAGE_WEAK_ESCROW_TOKEN = "android.permission.MANAGE_WEAK_ESCROW_TOKEN";
- field public static final String MANAGE_WIFI_AUTO_JOIN = "android.permission.MANAGE_WIFI_AUTO_JOIN";
field public static final String MANAGE_WIFI_COUNTRY_CODE = "android.permission.MANAGE_WIFI_COUNTRY_CODE";
field public static final String MARK_DEVICE_ORGANIZATION_OWNED = "android.permission.MARK_DEVICE_ORGANIZATION_OWNED";
field public static final String MODIFY_APPWIDGET_BIND_PERMISSIONS = "android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS";
@@ -227,7 +226,6 @@
field public static final String OBSERVE_SENSOR_PRIVACY = "android.permission.OBSERVE_SENSOR_PRIVACY";
field public static final String OPEN_ACCESSIBILITY_DETAILS_SETTINGS = "android.permission.OPEN_ACCESSIBILITY_DETAILS_SETTINGS";
field public static final String OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD = "android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD";
- field public static final String OVERRIDE_WIFI_CONFIG = "android.permission.OVERRIDE_WIFI_CONFIG";
field public static final String PACKAGE_VERIFICATION_AGENT = "android.permission.PACKAGE_VERIFICATION_AGENT";
field public static final String PACKET_KEEPALIVE_OFFLOAD = "android.permission.PACKET_KEEPALIVE_OFFLOAD";
field public static final String PEERS_MAC_ADDRESS = "android.permission.PEERS_MAC_ADDRESS";
@@ -357,6 +355,7 @@
field public static final String WRITE_EMBEDDED_SUBSCRIPTIONS = "android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS";
field @Deprecated public static final String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE";
field public static final String WRITE_OBB = "android.permission.WRITE_OBB";
+ field public static final String WRITE_SECURITY_LOG = "android.permission.WRITE_SECURITY_LOG";
field public static final String WRITE_SMS = "android.permission.WRITE_SMS";
}
@@ -470,6 +469,10 @@
method public boolean convertToTranslucent(android.app.Activity.TranslucentConversionListener, android.app.ActivityOptions);
method @Deprecated public boolean isBackgroundVisibleBehind();
method @Deprecated public void onBackgroundVisibleBehindChanged(boolean);
+ method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void startActivityAsUser(@NonNull android.content.Intent, @Nullable android.os.Bundle, @NonNull android.os.UserHandle);
+ method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void startActivityForResultAsUser(@NonNull android.content.Intent, int, @NonNull android.os.UserHandle);
+ method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void startActivityForResultAsUser(@NonNull android.content.Intent, int, @Nullable android.os.Bundle, @NonNull android.os.UserHandle);
+ method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void startActivityForResultAsUser(@NonNull android.content.Intent, @NonNull String, int, @Nullable android.os.Bundle, @NonNull android.os.UserHandle);
}
public static interface Activity.TranslucentConversionListener {
@@ -849,6 +852,10 @@
field public static final int SEMANTIC_ACTION_MARK_CONVERSATION_AS_PRIORITY = 11; // 0xb
}
+ public static class Notification.MediaStyle extends android.app.Notification.Style {
+ method @NonNull @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public android.app.Notification.MediaStyle setRemotePlaybackInfo(@NonNull CharSequence, @DrawableRes int, @Nullable android.app.PendingIntent);
+ }
+
public static final class Notification.TvExtender implements android.app.Notification.Extender {
ctor public Notification.TvExtender();
ctor public Notification.TvExtender(android.app.Notification);
@@ -912,7 +919,7 @@
method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public int getNavBarModeOverride();
method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSetup(boolean);
method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setNavBarModeOverride(int);
- method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void updateMediaTapToTransferReceiverDisplay(int, @NonNull android.media.MediaRoute2Info);
+ method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void updateMediaTapToTransferReceiverDisplay(int, @NonNull android.media.MediaRoute2Info, @Nullable android.graphics.drawable.Icon, @Nullable CharSequence);
method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void updateMediaTapToTransferSenderDisplay(int, @NonNull android.media.MediaRoute2Info, @Nullable java.util.concurrent.Executor, @Nullable Runnable);
field public static final int MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER = 0; // 0x0
field public static final int MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER = 1; // 0x1
@@ -1143,11 +1150,16 @@
field public static final String EXTRA_PROVISIONING_ORGANIZATION_NAME = "android.app.extra.PROVISIONING_ORGANIZATION_NAME";
field public static final String EXTRA_PROVISIONING_RETURN_BEFORE_POLICY_COMPLIANCE = "android.app.extra.PROVISIONING_RETURN_BEFORE_POLICY_COMPLIANCE";
field public static final String EXTRA_PROVISIONING_ROLE_HOLDER_CUSTOM_USER_CONSENT_INTENT = "android.app.extra.PROVISIONING_ROLE_HOLDER_CUSTOM_USER_CONSENT_INTENT";
+ field public static final String EXTRA_PROVISIONING_ROLE_HOLDER_EXTRAS_BUNDLE = "android.app.extra.PROVISIONING_ROLE_HOLDER_EXTRAS_BUNDLE";
+ field public static final String EXTRA_PROVISIONING_ROLE_HOLDER_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_ROLE_HOLDER_PACKAGE_DOWNLOAD_COOKIE_HEADER";
+ field public static final String EXTRA_PROVISIONING_ROLE_HOLDER_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_ROLE_HOLDER_PACKAGE_DOWNLOAD_LOCATION";
+ field public static final String EXTRA_PROVISIONING_ROLE_HOLDER_SIGNATURE_CHECKSUM = "android.app.extra.PROVISIONING_ROLE_HOLDER_SIGNATURE_CHECKSUM";
field public static final String EXTRA_PROVISIONING_SKIP_OWNERSHIP_DISCLAIMER = "android.app.extra.PROVISIONING_SKIP_OWNERSHIP_DISCLAIMER";
field public static final String EXTRA_PROVISIONING_SUPPORTED_MODES = "android.app.extra.PROVISIONING_SUPPORTED_MODES";
field public static final String EXTRA_PROVISIONING_SUPPORT_URL = "android.app.extra.PROVISIONING_SUPPORT_URL";
field public static final String EXTRA_PROVISIONING_TRIGGER = "android.app.extra.PROVISIONING_TRIGGER";
field public static final String EXTRA_RESTRICTION = "android.app.extra.RESTRICTION";
+ field public static final String EXTRA_ROLE_HOLDER_PROVISIONING_INITIATOR_PACKAGE = "android.app.extra.ROLE_HOLDER_PROVISIONING_INITIATOR_PACKAGE";
field public static final String EXTRA_ROLE_HOLDER_STATE = "android.app.extra.ROLE_HOLDER_STATE";
field public static final int FLAG_SUPPORTED_MODES_DEVICE_OWNER = 4; // 0x4
field public static final int FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED = 1; // 0x1
@@ -1296,6 +1308,10 @@
field public static final int ERROR_UNKNOWN = 0; // 0x0
}
+ public class SecurityLog {
+ method @RequiresPermission(android.Manifest.permission.WRITE_SECURITY_LOG) public static int writeEvent(int, @NonNull java.lang.Object...);
+ }
+
public final class SystemUpdatePolicy implements android.os.Parcelable {
method public android.app.admin.SystemUpdatePolicy.InstallationOption getInstallationOptionAt(long);
field public static final int TYPE_PAUSE = 4; // 0x4
@@ -1355,14 +1371,13 @@
method @NonNull public android.app.ambientcontext.AmbientContextEventRequest.Builder setOptions(@NonNull android.os.PersistableBundle);
}
- public final class AmbientContextEventResponse implements android.os.Parcelable {
- method public int describeContents();
- method @Nullable public android.app.PendingIntent getActionPendingIntent();
- method @NonNull public java.util.List<android.app.ambientcontext.AmbientContextEvent> getEvents();
- method @NonNull public String getPackageName();
- method public int getStatusCode();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.ambientcontext.AmbientContextEventResponse> CREATOR;
+ public final class AmbientContextManager {
+ method @NonNull public static java.util.List<android.app.ambientcontext.AmbientContextEvent> getEventsFromIntent(@NonNull android.content.Intent);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT) public void queryAmbientContextServiceStatus(@NonNull java.util.Set<java.lang.Integer>, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT) public void registerObserver(@NonNull android.app.ambientcontext.AmbientContextEventRequest, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT) public void startConsentActivity(@NonNull java.util.Set<java.lang.Integer>);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT) public void unregisterObserver();
+ field public static final String EXTRA_AMBIENT_CONTEXT_EVENTS = "android.app.ambientcontext.extra.AMBIENT_CONTEXT_EVENTS";
field public static final int STATUS_ACCESS_DENIED = 5; // 0x5
field public static final int STATUS_MICROPHONE_DISABLED = 4; // 0x4
field public static final int STATUS_NOT_SUPPORTED = 2; // 0x2
@@ -1371,27 +1386,14 @@
field public static final int STATUS_UNKNOWN = 0; // 0x0
}
- public static final class AmbientContextEventResponse.Builder {
- ctor public AmbientContextEventResponse.Builder();
- method @NonNull public android.app.ambientcontext.AmbientContextEventResponse.Builder addEvent(@NonNull android.app.ambientcontext.AmbientContextEvent);
- method @NonNull public android.app.ambientcontext.AmbientContextEventResponse build();
- method @NonNull public android.app.ambientcontext.AmbientContextEventResponse.Builder setActionPendingIntent(@NonNull android.app.PendingIntent);
- method @NonNull public android.app.ambientcontext.AmbientContextEventResponse.Builder setPackageName(@NonNull String);
- method @NonNull public android.app.ambientcontext.AmbientContextEventResponse.Builder setStatusCode(int);
- }
-
- public final class AmbientContextManager {
- method @Nullable public static android.app.ambientcontext.AmbientContextEventResponse getResponseFromIntent(@NonNull android.content.Intent);
- method @RequiresPermission(android.Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT) public void registerObserver(@NonNull android.app.ambientcontext.AmbientContextEventRequest, @NonNull android.app.PendingIntent);
- method @RequiresPermission(android.Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT) public void unregisterObserver();
- field public static final String EXTRA_AMBIENT_CONTEXT_EVENT_RESPONSE = "android.app.ambientcontext.extra.AMBIENT_CONTEXT_EVENT_RESPONSE";
- }
-
}
package android.app.assist {
- public class ActivityId {
+ public final class ActivityId implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.assist.ActivityId> CREATOR;
}
public static class AssistStructure.ViewNode {
@@ -1650,6 +1652,7 @@
method public int getResultNumber();
method public int getResultOffset();
method @NonNull public android.os.Bundle getSearchConstraints();
+ method @NonNull public String getSource();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field public static final String CONSTRAINT_IS_PRESUBMIT_SUGGESTION = "IS_PRESUBMIT_SUGGESTION";
field public static final String CONSTRAINT_SEARCH_PROVIDER_FILTER = "SEARCH_PROVIDER_FILTER";
@@ -2756,8 +2759,9 @@
public static class VirtualDeviceManager.VirtualDevice implements java.lang.AutoCloseable {
method public void addActivityListener(@NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener);
method public void addActivityListener(@NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener, @NonNull java.util.concurrent.Executor);
- method public void close();
- method @Nullable public android.hardware.display.VirtualDisplay createVirtualDisplay(int, int, int, @Nullable android.view.Surface, int, @Nullable android.os.Handler, @Nullable android.hardware.display.VirtualDisplay.Callback);
+ method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close();
+ method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.companion.virtual.audio.VirtualAudioDevice createVirtualAudioDevice(@NonNull android.hardware.display.VirtualDisplay, @Nullable java.util.concurrent.Executor, @Nullable android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChangeCallback);
+ method @Nullable public android.hardware.display.VirtualDisplay createVirtualDisplay(@IntRange(from=1) int, @IntRange(from=1) int, @IntRange(from=1) int, @Nullable android.view.Surface, int, @NonNull java.util.concurrent.Executor, @Nullable android.hardware.display.VirtualDisplay.Callback);
method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualKeyboard createVirtualKeyboard(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualMouse createVirtualMouse(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualTouchscreen createVirtualTouchscreen(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
@@ -2774,8 +2778,8 @@
method @NonNull public java.util.Set<android.os.UserHandle> getUsersWithMatchingAccounts();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.companion.virtual.VirtualDeviceParams> CREATOR;
- field public static final int LOCK_STATE_ALWAYS_LOCKED = 0; // 0x0
field public static final int LOCK_STATE_ALWAYS_UNLOCKED = 1; // 0x1
+ field public static final int LOCK_STATE_DEFAULT = 0; // 0x0
}
public static final class VirtualDeviceParams.Builder {
@@ -2789,6 +2793,39 @@
}
+package android.companion.virtual.audio {
+
+ public final class AudioCapture {
+ ctor public AudioCapture();
+ method public int getRecordingState();
+ method public int read(@NonNull java.nio.ByteBuffer, int);
+ method public void startRecording();
+ method public void stop();
+ }
+
+ public final class AudioInjection {
+ ctor public AudioInjection();
+ method public int getPlayState();
+ method public void play();
+ method public void stop();
+ method public int write(@NonNull java.nio.ByteBuffer, int, int);
+ }
+
+ public final class VirtualAudioDevice implements java.io.Closeable {
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void close();
+ method @Nullable public android.companion.virtual.audio.AudioCapture getAudioCapture();
+ method @Nullable public android.companion.virtual.audio.AudioInjection getAudioInjection();
+ method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.companion.virtual.audio.AudioCapture startAudioCapture(@NonNull android.media.AudioFormat);
+ method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.companion.virtual.audio.AudioInjection startAudioInjection(@NonNull android.media.AudioFormat);
+ }
+
+ public static interface VirtualAudioDevice.AudioConfigurationChangeCallback {
+ method public void onPlaybackConfigChanged(@NonNull java.util.List<android.media.AudioPlaybackConfiguration>);
+ method public void onRecordingConfigChanged(@NonNull java.util.List<android.media.AudioRecordingConfiguration>);
+ }
+
+}
+
package android.content {
public class ApexEnvironment {
@@ -3000,6 +3037,7 @@
}
public static final class IntegrityFormula.Application {
+ method @NonNull public static android.content.integrity.IntegrityFormula certificateLineageContains(@NonNull String);
method @NonNull public static android.content.integrity.IntegrityFormula certificatesContain(@NonNull String);
method @NonNull public static android.content.integrity.IntegrityFormula isPreInstalled();
method @NonNull public static android.content.integrity.IntegrityFormula packageNameEquals(@NonNull String);
@@ -3294,6 +3332,7 @@
method @Deprecated @RequiresPermission(android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT) public abstract void verifyIntentFilter(int, int, @NonNull java.util.List<java.lang.String>);
field public static final String ACTION_REQUEST_PERMISSIONS = "android.content.pm.action.REQUEST_PERMISSIONS";
field public static final String ACTION_REQUEST_PERMISSIONS_FOR_OTHER = "android.content.pm.action.REQUEST_PERMISSIONS_FOR_OTHER";
+ field public static final String EXTRA_REQUEST_PERMISSIONS_LEGACY_ACCESS_PERMISSION_NAMES = "android.content.pm.extra.REQUEST_PERMISSIONS_LEGACY_ACCESS_PERMISSION_NAMES";
field public static final String EXTRA_REQUEST_PERMISSIONS_NAMES = "android.content.pm.extra.REQUEST_PERMISSIONS_NAMES";
field public static final String EXTRA_REQUEST_PERMISSIONS_RESULTS = "android.content.pm.extra.REQUEST_PERMISSIONS_RESULTS";
field public static final String FEATURE_BROADCAST_RADIO = "android.hardware.broadcastradio";
@@ -5143,6 +5182,15 @@
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.soundtrigger.SoundTrigger.Keyphrase> CREATOR;
}
+ public static final class SoundTrigger.KeyphraseRecognitionExtra implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getCoarseConfidenceLevel();
+ method public int getKeyphraseId();
+ method public int getRecognitionModes();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra> CREATOR;
+ }
+
public static final class SoundTrigger.KeyphraseSoundModel extends android.hardware.soundtrigger.SoundTrigger.SoundModel implements android.os.Parcelable {
ctor public SoundTrigger.KeyphraseSoundModel(@NonNull java.util.UUID, @NonNull java.util.UUID, @Nullable byte[], @Nullable android.hardware.soundtrigger.SoundTrigger.Keyphrase[], int);
ctor public SoundTrigger.KeyphraseSoundModel(@NonNull java.util.UUID, @NonNull java.util.UUID, @Nullable byte[], @Nullable android.hardware.soundtrigger.SoundTrigger.Keyphrase[]);
@@ -5993,6 +6041,7 @@
public class AudioManager {
method @Deprecated public int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addAssistantServicesUids(@NonNull java.util.List<java.lang.Integer>);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDeviceForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener) throws java.lang.SecurityException;
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDevicesForCapturePresetChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDevicesForCapturePresetChangedListener) throws java.lang.SecurityException;
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDevicesForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDevicesForStrategyChangedListener) throws java.lang.SecurityException;
@@ -6000,7 +6049,9 @@
method public void clearAudioServerStateCallback();
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean clearPreferredDevicesForCapturePreset(int);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int dispatchAudioFocusChange(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
+ method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<java.lang.Integer> getActiveAssistantServicesUids();
method @IntRange(from=0) public long getAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo);
+ method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<java.lang.Integer> getAssistantServicesUids();
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioProductStrategy> getAudioProductStrategies();
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioVolumeGroup> getAudioVolumeGroups();
method @NonNull @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION) public android.media.AudioRecord getCallDownlinkExtractionAudioRecord(@NonNull android.media.AudioFormat);
@@ -6025,6 +6076,7 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int registerAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void registerMuteAwaitConnectionCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.MuteAwaitConnectionCallback);
method public void registerVolumeGroupCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.VolumeGroupCallback);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeAssistantServicesUids(@NonNull java.util.List<java.lang.Integer>);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDeviceForStrategyChangedListener(@NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDevicesForCapturePresetChangedListener(@NonNull android.media.AudioManager.OnPreferredDevicesForCapturePresetChangedListener);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDevicesForStrategyChangedListener(@NonNull android.media.AudioManager.OnPreferredDevicesForStrategyChangedListener);
@@ -6032,6 +6084,7 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int) throws java.lang.IllegalArgumentException;
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.MODIFY_AUDIO_ROUTING}) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int, android.media.audiopolicy.AudioPolicy) throws java.lang.IllegalArgumentException;
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int requestAudioFocus(@NonNull android.media.AudioFocusRequest, @Nullable android.media.audiopolicy.AudioPolicy);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setActiveAssistantServiceUids(@NonNull java.util.List<java.lang.Integer>);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo, @IntRange(from=0) long);
method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes, int);
@@ -6167,6 +6220,10 @@
method @NonNull public android.media.HwAudioSource.Builder setAudioDeviceInfo(@NonNull android.media.AudioDeviceInfo);
}
+ public final class MediaCodec {
+ method @NonNull @RequiresPermission("android.permission.MEDIA_RESOURCE_OVERRIDE_PID") public static android.media.MediaCodec createByCodecNameForClient(@NonNull String, int, int) throws java.io.IOException;
+ }
+
public class MediaPlayer implements android.media.AudioRouting android.media.VolumeAutomation {
method @RequiresPermission(android.Manifest.permission.BIND_IMS_SERVICE) public void setOnRtpRxNoticeListener(@NonNull android.content.Context, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaPlayer.OnRtpRxNoticeListener);
}
@@ -6228,6 +6285,9 @@
method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public int getHeadTrackingMode();
method @IntRange(from=0) @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public int getOutput();
method @NonNull @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public java.util.List<java.lang.Integer> getSupportedHeadTrackingModes();
+ method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public boolean hasHeadTracker(@NonNull android.media.AudioDeviceAttributes);
+ method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public boolean isAvailableForDevice(@NonNull android.media.AudioDeviceAttributes);
+ method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public boolean isHeadTrackerEnabled(@NonNull android.media.AudioDeviceAttributes);
method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public void recenterHeadTracker();
method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public void removeCompatibleAudioDevice(@NonNull android.media.AudioDeviceAttributes);
method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public void removeOnHeadTrackingModeChangedListener(@NonNull android.media.Spatializer.OnHeadTrackingModeChangedListener);
@@ -6235,6 +6295,7 @@
method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public void setEffectParameter(int, @NonNull byte[]);
method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public void setEnabled(boolean);
method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public void setGlobalTransform(@NonNull float[]);
+ method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public void setHeadTrackerEnabled(boolean, @NonNull android.media.AudioDeviceAttributes);
method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public void setOnHeadToSoundstagePoseUpdatedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.Spatializer.OnHeadToSoundstagePoseUpdatedListener);
method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public void setOnSpatializerOutputChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.Spatializer.OnSpatializerOutputChangedListener);
field @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public static final int HEAD_TRACKING_MODE_DISABLED = -1; // 0xffffffff
@@ -6663,7 +6724,7 @@
method @NonNull @RequiresPermission(android.Manifest.permission.TIS_EXTENSION_INTERFACE) public java.util.List<java.lang.String> getAvailableExtensionInterfaceNames(@NonNull String);
method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public java.util.List<android.media.tv.TvStreamConfig> getAvailableTvStreamConfigList(String);
method @RequiresPermission("android.permission.TUNER_RESOURCE_ACCESS") public int getClientPid(@NonNull String);
- method public int getClientPriority(int, @Nullable String);
+ method @RequiresPermission("android.permission.TUNER_RESOURCE_ACCESS") public int getClientPriority(int, @Nullable String);
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TUNED_INFO) public java.util.List<android.media.tv.TunedInfo> getCurrentTunedInfos();
method @NonNull @RequiresPermission("android.permission.DVB_DEVICE") public java.util.List<android.media.tv.DvbDeviceInfo> getDvbDeviceList();
method @Nullable @RequiresPermission(android.Manifest.permission.TIS_EXTENSION_INTERFACE) public android.os.IBinder getExtensionInterface(@NonNull String, @NonNull String);
@@ -8863,7 +8924,7 @@
method @Nullable public android.net.wifi.nl80211.DeviceWiphyCapabilities getDeviceWiphyCapabilities(@NonNull String);
method @NonNull public java.util.List<android.net.wifi.nl80211.NativeScanResult> getScanResults(@NonNull String, int);
method @Nullable public android.net.wifi.nl80211.WifiNl80211Manager.TxPacketCounters getTxPacketCounters(@NonNull String);
- method public boolean notifyCountryCodeChanged();
+ method public void notifyCountryCodeChanged(@Nullable String);
method @Nullable public static android.net.wifi.nl80211.WifiNl80211Manager.OemSecurityType parseOemSecurityTypeElement(int, int, @NonNull byte[]);
method @Deprecated public boolean registerApCallback(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.nl80211.WifiNl80211Manager.SoftApCallback);
method public boolean registerCountryCodeChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.nl80211.WifiNl80211Manager.CountryCodeChangedListener);
@@ -9649,13 +9710,12 @@
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean hasRestrictedProfiles();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean hasUserRestrictionForUser(@NonNull String, @NonNull android.os.UserHandle);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isAdminUser();
- method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isCloneProfile();
+ method public boolean isCloneProfile();
method public boolean isCredentialSharedWithParent();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isGuestUser();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isManagedProfile(int);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isMediaSharedWithParent();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isPrimaryUser();
- method public boolean isProfile();
method public boolean isRestrictedProfile();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public boolean isRestrictedProfile(@NonNull android.os.UserHandle);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isSameProfileGroup(@NonNull android.os.UserHandle, @NonNull android.os.UserHandle);
@@ -10697,14 +10757,45 @@
package android.service.ambientcontext {
+ public final class AmbientContextDetectionResult implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public java.util.List<android.app.ambientcontext.AmbientContextEvent> getEvents();
+ method @NonNull public String getPackageName();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.service.ambientcontext.AmbientContextDetectionResult> CREATOR;
+ }
+
+ public static final class AmbientContextDetectionResult.Builder {
+ ctor public AmbientContextDetectionResult.Builder();
+ method @NonNull public android.service.ambientcontext.AmbientContextDetectionResult.Builder addEvent(@NonNull android.app.ambientcontext.AmbientContextEvent);
+ method @NonNull public android.service.ambientcontext.AmbientContextDetectionResult build();
+ method @NonNull public android.service.ambientcontext.AmbientContextDetectionResult.Builder setPackageName(@NonNull String);
+ }
+
public abstract class AmbientContextDetectionService extends android.app.Service {
ctor public AmbientContextDetectionService();
method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
- method public abstract void onStartDetection(@NonNull android.app.ambientcontext.AmbientContextEventRequest, @NonNull String, @NonNull java.util.function.Consumer<android.app.ambientcontext.AmbientContextEventResponse>);
+ method @BinderThread public abstract void onQueryServiceStatus(@NonNull int[], @NonNull String, @NonNull java.util.function.Consumer<android.service.ambientcontext.AmbientContextDetectionServiceStatus>);
+ method @BinderThread public abstract void onStartDetection(@NonNull android.app.ambientcontext.AmbientContextEventRequest, @NonNull String, @NonNull java.util.function.Consumer<android.service.ambientcontext.AmbientContextDetectionResult>, @NonNull java.util.function.Consumer<android.service.ambientcontext.AmbientContextDetectionServiceStatus>);
method public abstract void onStopDetection(@NonNull String);
field public static final String SERVICE_INTERFACE = "android.service.ambientcontext.AmbientContextDetectionService";
}
+ public final class AmbientContextDetectionServiceStatus implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public String getPackageName();
+ method public int getStatusCode();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.service.ambientcontext.AmbientContextDetectionServiceStatus> CREATOR;
+ }
+
+ public static final class AmbientContextDetectionServiceStatus.Builder {
+ ctor public AmbientContextDetectionServiceStatus.Builder();
+ method @NonNull public android.service.ambientcontext.AmbientContextDetectionServiceStatus build();
+ method @NonNull public android.service.ambientcontext.AmbientContextDetectionServiceStatus.Builder setPackageName(@NonNull String);
+ method @NonNull public android.service.ambientcontext.AmbientContextDetectionServiceStatus.Builder setStatusCode(int);
+ }
+
}
package android.service.appprediction {
@@ -11068,7 +11159,8 @@
method public int encodeSmdxSubjectAndReasonCode(@Nullable String, @Nullable String);
method @CallSuper public android.os.IBinder onBind(android.content.Intent);
method public abstract int onDeleteSubscription(int, String);
- method public android.service.euicc.DownloadSubscriptionResult onDownloadSubscription(int, @NonNull android.telephony.euicc.DownloadableSubscription, boolean, boolean, @Nullable android.os.Bundle);
+ method @Deprecated public android.service.euicc.DownloadSubscriptionResult onDownloadSubscription(int, @NonNull android.telephony.euicc.DownloadableSubscription, boolean, boolean, @Nullable android.os.Bundle);
+ method @NonNull public android.service.euicc.DownloadSubscriptionResult onDownloadSubscription(int, int, @NonNull android.telephony.euicc.DownloadableSubscription, boolean, boolean, @NonNull android.os.Bundle);
method @Deprecated public int onDownloadSubscription(int, @NonNull android.telephony.euicc.DownloadableSubscription, boolean, boolean);
method @Deprecated public abstract int onEraseSubscriptions(int);
method public int onEraseSubscriptions(int, @android.telephony.euicc.EuiccCardManager.ResetOption int);
@@ -11687,8 +11779,13 @@
public static class AlwaysOnHotwordDetector.EventPayload {
method @Nullable public android.os.ParcelFileDescriptor getAudioStream();
method @Nullable public android.media.AudioFormat getCaptureAudioFormat();
+ method @Nullable public byte[] getData();
+ method public int getDataFormat();
method @Nullable public android.service.voice.HotwordDetectedResult getHotwordDetectedResult();
- method @Nullable public byte[] getTriggerAudio();
+ method @NonNull public java.util.List<android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra> getKeyphraseRecognitionExtras();
+ method @Deprecated @Nullable public byte[] getTriggerAudio();
+ field public static final int DATA_FORMAT_RAW = 0; // 0x0
+ field public static final int DATA_FORMAT_TRIGGER_AUDIO = 1; // 0x1
}
public static final class AlwaysOnHotwordDetector.ModelParamRange {
@@ -11759,6 +11856,7 @@
}
public interface HotwordDetector {
+ method public default void destroy();
method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public boolean startRecognition();
method public boolean startRecognition(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, @Nullable android.os.PersistableBundle);
method public boolean stopRecognition();
@@ -12304,7 +12402,7 @@
method public int getNumRtpPacketsReceived();
method public int getNumRtpPacketsTransmitted();
method public int getNumRtpPacketsTransmittedLost();
- method public int getNumRtpSidPacketsRx();
+ method public int getNumRtpSidPacketsReceived();
method public int getNumVoiceFrames();
method public int getUplinkCallQualityLevel();
method public boolean isIncomingSilenceDetectedAtCallSetup();
@@ -12324,8 +12422,8 @@
ctor public CallQuality.Builder();
method @NonNull public android.telephony.CallQuality build();
method @NonNull public android.telephony.CallQuality.Builder setAverageRelativeJitter(int);
- method @NonNull public android.telephony.CallQuality.Builder setAverageRoundTripTime(int);
- method @NonNull public android.telephony.CallQuality.Builder setCallDuration(int);
+ method @NonNull public android.telephony.CallQuality.Builder setAverageRoundTripTimeMillis(int);
+ method @NonNull public android.telephony.CallQuality.Builder setCallDurationMillis(int);
method @NonNull public android.telephony.CallQuality.Builder setCodecType(int);
method @NonNull public android.telephony.CallQuality.Builder setDownlinkCallQualityLevel(int);
method @NonNull public android.telephony.CallQuality.Builder setIncomingSilenceDetectedAtCallSetup(boolean);
@@ -12339,7 +12437,7 @@
method @NonNull public android.telephony.CallQuality.Builder setNumRtpPacketsReceived(int);
method @NonNull public android.telephony.CallQuality.Builder setNumRtpPacketsTransmitted(int);
method @NonNull public android.telephony.CallQuality.Builder setNumRtpPacketsTransmittedLost(int);
- method @NonNull public android.telephony.CallQuality.Builder setNumRtpSidPacketsRx(int);
+ method @NonNull public android.telephony.CallQuality.Builder setNumRtpSidPacketsReceived(int);
method @NonNull public android.telephony.CallQuality.Builder setNumVoiceFrames(int);
method @NonNull public android.telephony.CallQuality.Builder setOutgoingSilenceDetectedAtCallSetup(boolean);
method @NonNull public android.telephony.CallQuality.Builder setRtpInactivityDetected(boolean);
@@ -13252,7 +13350,7 @@
method public boolean needsOtaServiceProvisioning();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyOtaEmergencyNumberDbInstalled();
method @RequiresPermission(android.Manifest.permission.REBOOT) public int prepareForUnattendedReboot();
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio();
+ method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void removeCarrierPrivilegesListener(@NonNull android.telephony.TelephonyManager.CarrierPrivilegesListener);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void reportDefaultNetworkStatus(boolean);
method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
@@ -13808,7 +13906,7 @@
field public static final int RESULT_CALLER_NOT_ALLOWED = -3; // 0xfffffffd
field public static final int RESULT_EUICC_NOT_FOUND = -2; // 0xfffffffe
field public static final int RESULT_OK = 0; // 0x0
- field public static final int RESULT_PROFILE_NOT_FOUND = -4; // 0xfffffffc
+ field public static final int RESULT_PROFILE_NOT_FOUND = 1; // 0x1
field public static final int RESULT_UNKNOWN_ERROR = -1; // 0xffffffff
}
@@ -14751,6 +14849,7 @@
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();
@@ -14779,6 +14878,7 @@
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 {
@@ -15525,8 +15625,8 @@
}
public class CaptioningManager {
- method @RequiresPermission(android.Manifest.permission.SET_SYSTEM_AUDIO_CAPTION) public final void setSystemAudioCaptioningRequested(boolean);
- method @RequiresPermission(android.Manifest.permission.SET_SYSTEM_AUDIO_CAPTION) public final void setSystemAudioCaptioningUiRequested(boolean);
+ method @RequiresPermission(android.Manifest.permission.SET_SYSTEM_AUDIO_CAPTION) public final void setSystemAudioCaptioningEnabled(boolean);
+ method @RequiresPermission(android.Manifest.permission.SET_SYSTEM_AUDIO_CAPTION) public final void setSystemAudioCaptioningUiEnabled(boolean);
}
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 5bd6ca8..84b393a 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -278,6 +278,7 @@
}
public final class GameManager {
+ method @RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE) public int getGameMode(@NonNull String);
method @RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE) public boolean isAngleEnabled(@NonNull String);
method public void setGameServiceProvider(@Nullable String);
}
@@ -299,6 +300,9 @@
public class Notification implements android.os.Parcelable {
method public boolean shouldShowForegroundImmediately();
+ field public static final String EXTRA_MEDIA_REMOTE_DEVICE = "android.mediaRemoteDevice";
+ field public static final String EXTRA_MEDIA_REMOTE_ICON = "android.mediaRemoteIcon";
+ field public static final String EXTRA_MEDIA_REMOTE_INTENT = "android.mediaRemoteIntent";
}
public final class NotificationChannel implements android.os.Parcelable {
@@ -348,6 +352,7 @@
public final class PictureInPictureParams implements android.os.Parcelable {
method public java.util.List<android.app.RemoteAction> getActions();
method public float getAspectRatio();
+ method public float getExpandedAspectRatio();
method public android.graphics.Rect getSourceRectHint();
method public boolean isSeamlessResizeEnabled();
}
@@ -482,6 +487,7 @@
package android.app.admin {
public class DevicePolicyManager {
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public void acknowledgeNewUserDisclaimer();
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void clearOrganizationId();
method @RequiresPermission(android.Manifest.permission.CLEAR_FREEZE_PERIOD) public void clearSystemUpdatePolicyFreezePeriodRecord();
method @RequiresPermission(android.Manifest.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS) public long forceNetworkLogs();
@@ -569,9 +575,13 @@
package android.app.assist {
- public class ActivityId {
+ public final class ActivityId implements android.os.Parcelable {
+ ctor public ActivityId(int, @Nullable android.os.IBinder);
+ method public int describeContents();
method public int getTaskId();
method @Nullable public android.os.IBinder getToken();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.assist.ActivityId> CREATOR;
}
}
@@ -596,6 +606,14 @@
}
+package android.app.cloudsearch {
+
+ public static final class SearchRequest.Builder {
+ method @NonNull public android.app.cloudsearch.SearchRequest.Builder setSource(@NonNull String);
+ }
+
+}
+
package android.app.contentsuggestions {
public final class ContentSuggestionsManager {
@@ -1271,6 +1289,10 @@
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.soundtrigger.KeyphraseMetadata> CREATOR;
}
+ public static final class SoundTrigger.KeyphraseRecognitionExtra implements android.os.Parcelable {
+ ctor public SoundTrigger.KeyphraseRecognitionExtra(int, int, int);
+ }
+
public static final class SoundTrigger.ModelParamRange implements android.os.Parcelable {
ctor public SoundTrigger.ModelParamRange(int, int);
}
@@ -1602,10 +1624,6 @@
package android.net {
- public class EthernetManager {
- method public void setIncludeTestInterfaces(boolean);
- }
-
public class NetworkPolicyManager {
method public boolean getRestrictBackground();
method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidNetworkingBlocked(int, boolean);
@@ -1748,6 +1766,7 @@
public class Process {
method public static final int getThreadScheduler(int) throws java.lang.IllegalArgumentException;
+ method public static final int toSupplementalUid(int);
field public static final int FIRST_APP_ZYGOTE_ISOLATED_UID = 90000; // 0x15f90
field public static final int FIRST_ISOLATED_UID = 99000; // 0x182b8
field public static final int LAST_APP_ZYGOTE_ISOLATED_UID = 98999; // 0x182b7
@@ -1949,6 +1968,7 @@
method public long computeStorageCacheBytes(@NonNull java.io.File);
method @NonNull public static java.util.UUID convert(@NonNull String);
method @NonNull public static String convert(@NonNull java.util.UUID);
+ method @Nullable public String getCloudMediaProvider();
method public boolean isAppIoBlocked(@NonNull java.util.UUID, int, int, int);
method public static boolean isUserKeyUnlocked(int);
field public static final String CACHE_RESERVE_PERCENT_HIGH_KEY = "cache_reserve_percent_high";
@@ -2059,7 +2079,7 @@
method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.permission.PermGroupUsage> getIndicatorAppOpUsageData();
method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.permission.PermGroupUsage> getIndicatorAppOpUsageData(boolean);
method @NonNull public android.content.AttributionSource registerAttributionSource(@NonNull android.content.AttributionSource);
- method public void revokePostNotificationPermissionWithoutKillForTest(@NonNull String, int);
+ method @RequiresPermission(android.Manifest.permission.REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL) public void revokePostNotificationPermissionWithoutKillForTest(@NonNull String, int);
}
}
@@ -2396,6 +2416,19 @@
method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public void triggerHardwareRecognitionEventForTest(int, int, boolean, int, int, int, boolean, @NonNull android.media.AudioFormat, @Nullable byte[]);
}
+ public static final class AlwaysOnHotwordDetector.EventPayload.Builder {
+ ctor public AlwaysOnHotwordDetector.EventPayload.Builder();
+ method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload build();
+ method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setAudioStream(@NonNull android.os.ParcelFileDescriptor);
+ method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setCaptureAudioFormat(@NonNull android.media.AudioFormat);
+ method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setCaptureAvailable(boolean);
+ method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setCaptureSession(int);
+ method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setData(@NonNull byte[]);
+ method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setDataFormat(int);
+ method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setHotwordDetectedResult(@NonNull android.service.voice.HotwordDetectedResult);
+ method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setKeyphraseRecognitionExtras(@NonNull java.util.List<android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra>);
+ }
+
public final class VisibleActivityInfo implements android.os.Parcelable {
ctor public VisibleActivityInfo(int, @NonNull android.os.IBinder);
}
@@ -2862,6 +2895,7 @@
method public default void setShouldShowSystemDecors(int, boolean);
method public default void setShouldShowWithInsecureKeyguard(int, boolean);
method public default boolean shouldShowSystemDecors(int);
+ method @Nullable public default android.graphics.Bitmap snapshotTaskForRecents(@IntRange(from=0) int);
field public static final int DISPLAY_IME_POLICY_FALLBACK_DISPLAY = 1; // 0x1
field public static final int DISPLAY_IME_POLICY_HIDE = 2; // 0x2
field public static final int DISPLAY_IME_POLICY_LOCAL = 0; // 0x0
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 50473f1..c82f5f6 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -40,6 +40,8 @@
import android.graphics.Region;
import android.hardware.HardwareBuffer;
import android.hardware.display.DisplayManager;
+import android.inputmethodservice.IInputMethodSessionWrapper;
+import android.inputmethodservice.RemoteInputConnection;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -65,14 +67,23 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.accessibility.AccessibilityWindowInfo;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputBinding;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputMethodSession;
+import com.android.internal.inputmethod.CancellationGroup;
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.Preconditions;
import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.internal.view.IInputContext;
+import com.android.internal.view.IInputMethodSession;
+import com.android.internal.view.IInputSessionWithIdCallback;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executor;
@@ -627,6 +638,21 @@
void onAccessibilityButtonAvailabilityChanged(boolean available);
/** This is called when the system action list is changed. */
void onSystemActionsChanged();
+ /** This is called when an app requests ime sessions or when the service is enabled. */
+ void createImeSession(IInputSessionWithIdCallback callback);
+ /**
+ * This is called when InputMethodManagerService requests to set the session enabled or
+ * disabled
+ */
+ void setImeSessionEnabled(InputMethodSession session, boolean enabled);
+ /** This is called when an app binds input or when the service is enabled. */
+ void bindInput(InputBinding binding);
+ /** This is called when an app unbinds input or when the service is disabled. */
+ void unbindInput();
+ /** This is called when an app starts input or when the service is enabled. */
+ void startInput(@Nullable InputConnection inputConnection,
+ @NonNull EditorInfo editorInfo, boolean restarting,
+ @NonNull IBinder startInputToken);
}
/**
@@ -763,6 +789,8 @@
new SparseArray<>(0);
private SoftKeyboardController mSoftKeyboardController;
+ private InputMethod mInputMethod;
+ private boolean mInputMethodInitialized = false;
private final SparseArray<AccessibilityButtonController> mAccessibilityButtonControllers =
new SparseArray<>(0);
@@ -797,6 +825,17 @@
for (int i = 0; i < mMagnificationControllers.size(); i++) {
mMagnificationControllers.valueAt(i).onServiceConnectedLocked();
}
+ AccessibilityServiceInfo info = getServiceInfo();
+ if (info != null) {
+ boolean requestIme = (info.flags
+ & AccessibilityServiceInfo.FLAG_INPUT_METHOD_EDITOR) != 0;
+ if (requestIme && !mInputMethodInitialized) {
+ mInputMethod = onCreateInputMethod();
+ mInputMethodInitialized = true;
+ }
+ } else {
+ Log.e(LOG_TAG, "AccessibilityServiceInfo is null in dispatchServiceConnected");
+ }
}
if (mSoftKeyboardController != null) {
mSoftKeyboardController.onServiceConnected();
@@ -969,14 +1008,6 @@
* is currently touching or the window with input focus, if the user is not
* touching any window. It could be from any logical display.
* <p>
- * The currently active window is defined as the window that most recently fired one
- * of the following events:
- * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED},
- * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER},
- * {@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT}.
- * In other words, the last window shown that also has input focus.
- * </p>
- * <p>
* <strong>Note:</strong> In order to access the root node your service has
* to declare the capability to retrieve window content by setting the
* {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
@@ -984,10 +1015,29 @@
* </p>
*
* @return The root node if this service can retrieve window content.
+ * @see AccessibilityWindowInfo#isActive() for more explanation about the active window.
*/
public AccessibilityNodeInfo getRootInActiveWindow() {
+ return getRootInActiveWindow(AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS_HYBRID);
+ }
+
+ /**
+ * Gets the root node in the currently active window if this service
+ * can retrieve window content. The active window is the one that the user
+ * is currently touching or the window with input focus, if the user is not
+ * touching any window. It could be from any logical display.
+ *
+ * @param prefetchingStrategy the prefetching strategy.
+ * @return The root node if this service can retrieve window content.
+ *
+ * @see #getRootInActiveWindow()
+ * @see AccessibilityNodeInfo#getParent(int) for a description of prefetching.
+ */
+ @Nullable
+ public AccessibilityNodeInfo getRootInActiveWindow(
+ @AccessibilityNodeInfo.PrefetchingStrategy int prefetchingStrategy) {
return AccessibilityInteractionClient.getInstance(this).getRootInActiveWindow(
- mConnectionId);
+ mConnectionId, prefetchingStrategy);
}
/**
@@ -1849,6 +1899,32 @@
}
}
+ /**
+ * The default implementation returns our default {@link InputMethod}. Subclasses can override
+ * it to provide their own customized version. Accessibility services need to set the
+ * {@link AccessibilityServiceInfo#FLAG_INPUT_METHOD_EDITOR} flag to use input method APIs.
+ *
+ * @return the InputMethod.
+ */
+ @NonNull
+ public InputMethod onCreateInputMethod() {
+ return new InputMethod(this);
+ }
+
+ /**
+ * Returns the InputMethod instance after the system calls {@link #onCreateInputMethod()},
+ * which may be used to input text or get editable text selection change notifications. It will
+ * return null if the accessibility service doesn't set the
+ * {@link AccessibilityServiceInfo#FLAG_INPUT_METHOD_EDITOR} flag or the system doesn't call
+ * {@link #onCreateInputMethod()}.
+ *
+ * @return the InputMethod instance
+ */
+ @Nullable
+ public final InputMethod getInputMethod() {
+ return mInputMethod;
+ }
+
private void onSoftKeyboardShowModeChanged(int showMode) {
if (mSoftKeyboardController != null) {
mSoftKeyboardController.dispatchSoftKeyboardShowModeChanged(showMode);
@@ -2657,6 +2733,47 @@
public void onSystemActionsChanged() {
AccessibilityService.this.onSystemActionsChanged();
}
+
+ @Override
+ public void createImeSession(IInputSessionWithIdCallback callback) {
+ if (mInputMethod != null) {
+ mInputMethod.createImeSession(callback);
+ }
+ }
+
+ @Override
+ public void setImeSessionEnabled(InputMethodSession session, boolean enabled) {
+ if (mInputMethod != null) {
+ mInputMethod.setImeSessionEnabled(session, enabled);
+ }
+ }
+
+ @Override
+ public void bindInput(InputBinding binding) {
+ if (mInputMethod != null) {
+ mInputMethod.bindInput(binding);
+ }
+ }
+
+ @Override
+ public void unbindInput() {
+ if (mInputMethod != null) {
+ mInputMethod.unbindInput();
+ }
+ }
+
+ @Override
+ public void startInput(@Nullable InputConnection inputConnection,
+ @NonNull EditorInfo editorInfo, boolean restarting,
+ @NonNull IBinder startInputToken) {
+ if (mInputMethod != null) {
+ if (restarting) {
+ mInputMethod.restartInput(inputConnection, editorInfo);
+ } else {
+ mInputMethod.startInput(inputConnection, editorInfo);
+ }
+ }
+ }
});
}
@@ -2682,6 +2799,11 @@
private static final int DO_ACCESSIBILITY_BUTTON_CLICKED = 12;
private static final int DO_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED = 13;
private static final int DO_ON_SYSTEM_ACTIONS_CHANGED = 14;
+ private static final int DO_CREATE_IME_SESSION = 15;
+ private static final int DO_SET_IME_SESSION_ENABLED = 16;
+ private static final int DO_BIND_INPUT = 17;
+ private static final int DO_UNBIND_INPUT = 18;
+ private static final int DO_START_INPUT = 19;
private final HandlerCaller mCaller;
@@ -2690,6 +2812,22 @@
private int mConnectionId = AccessibilityInteractionClient.NO_ID;
+ /**
+ * This is not {@null} only between {@link #bindInput(InputBinding)} and
+ * {@link #unbindInput()} so that {@link RemoteInputConnection} can query if
+ * {@link #unbindInput()} has already been called or not, mainly to avoid unnecessary
+ * blocking operations.
+ *
+ * <p>This field must be set and cleared only from the binder thread(s), where the system
+ * guarantees that {@link #bindInput(InputBinding)},
+ * {@link #startInput(IBinder, IInputContext, EditorInfo, boolean)}, and
+ * {@link #unbindInput()} are called with the same order as the original calls
+ * in {@link com.android.server.inputmethod.InputMethodManagerService}.
+ * See {@link IBinder#FLAG_ONEWAY} for detailed semantics.</p>
+ */
+ @Nullable
+ CancellationGroup mCancellationGroup = null;
+
public IAccessibilityServiceClientWrapper(Context context, Looper looper,
Callbacks callback) {
mCallback = callback;
@@ -2783,6 +2921,70 @@
mCaller.sendMessage(mCaller.obtainMessage(DO_ON_SYSTEM_ACTIONS_CHANGED));
}
+ /** This is called when an app requests ime sessions or when the service is enabled. */
+ public void createImeSession(IInputSessionWithIdCallback callback) {
+ final Message message = mCaller.obtainMessageO(DO_CREATE_IME_SESSION, callback);
+ mCaller.sendMessage(message);
+ }
+
+ /**
+ * This is called when InputMethodManagerService requests to set the session enabled or
+ * disabled
+ */
+ public void setImeSessionEnabled(IInputMethodSession session, boolean enabled) {
+ try {
+ InputMethodSession ls = ((IInputMethodSessionWrapper)
+ session).getInternalInputMethodSession();
+ if (ls == null) {
+ Log.w(LOG_TAG, "Session is already finished: " + session);
+ return;
+ }
+ mCaller.sendMessage(mCaller.obtainMessageIO(
+ DO_SET_IME_SESSION_ENABLED, enabled ? 1 : 0, ls));
+ } catch (ClassCastException e) {
+ Log.w(LOG_TAG, "Incoming session not of correct type: " + session, e);
+ }
+ }
+
+ /** This is called when an app binds input or when the service is enabled. */
+ public void bindInput(InputBinding binding) {
+ if (mCancellationGroup != null) {
+ Log.e(LOG_TAG, "bindInput must be paired with unbindInput.");
+ }
+ mCancellationGroup = new CancellationGroup();
+ InputConnection ic = new RemoteInputConnection(new WeakReference<>(() -> mContext),
+ IInputContext.Stub.asInterface(binding.getConnectionToken()),
+ mCancellationGroup);
+ InputBinding nu = new InputBinding(ic, binding);
+ final Message message = mCaller.obtainMessageO(DO_BIND_INPUT, nu);
+ mCaller.sendMessage(message);
+ }
+
+ /** This is called when an app unbinds input or when the service is disabled. */
+ public void unbindInput() {
+ if (mCancellationGroup != null) {
+ // Signal the flag then forget it.
+ mCancellationGroup.cancelAll();
+ mCancellationGroup = null;
+ } else {
+ Log.e(LOG_TAG, "unbindInput must be paired with bindInput.");
+ }
+ mCaller.sendMessage(mCaller.obtainMessage(DO_UNBIND_INPUT));
+ }
+
+ /** This is called when an app starts input or when the service is enabled. */
+ public void startInput(IBinder startInputToken, IInputContext inputContext,
+ EditorInfo editorInfo, boolean restarting) {
+ if (mCancellationGroup == null) {
+ Log.e(LOG_TAG, "startInput must be called after bindInput.");
+ mCancellationGroup = new CancellationGroup();
+ }
+ final Message message = mCaller.obtainMessageOOOOII(DO_START_INPUT, startInputToken,
+ inputContext, editorInfo, mCancellationGroup, restarting ? 1 : 0,
+ 0 /* unused */);
+ mCaller.sendMessage(message);
+ }
+
@Override
public void onMotionEvent(MotionEvent event) {
final Message message = PooledLambda.obtainMessage(
@@ -2948,6 +3150,50 @@
}
return;
}
+ case DO_CREATE_IME_SESSION: {
+ if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
+ IInputSessionWithIdCallback callback =
+ (IInputSessionWithIdCallback) message.obj;
+ mCallback.createImeSession(callback);
+ }
+ return;
+ }
+ case DO_SET_IME_SESSION_ENABLED: {
+ if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
+ mCallback.setImeSessionEnabled((InputMethodSession) message.obj,
+ message.arg1 != 0);
+ }
+ return;
+ }
+ case DO_BIND_INPUT: {
+ if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
+ mCallback.bindInput((InputBinding) message.obj);
+ }
+ return;
+ }
+ case DO_UNBIND_INPUT: {
+ if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
+ mCallback.unbindInput();
+ }
+ return;
+ }
+ case DO_START_INPUT: {
+ if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
+ final SomeArgs args = (SomeArgs) message.obj;
+ final IBinder startInputToken = (IBinder) args.arg1;
+ final IInputContext inputContext = (IInputContext) args.arg2;
+ final EditorInfo info = (EditorInfo) args.arg3;
+ final CancellationGroup cancellationGroup = (CancellationGroup) args.arg4;
+ final boolean restarting = args.argi5 == 1;
+ final InputConnection ic = inputContext != null
+ ? new RemoteInputConnection(new WeakReference<>(() -> mContext),
+ inputContext, cancellationGroup) : null;
+ info.makeCompatible(mContext.getApplicationInfo().targetSdkVersion);
+ mCallback.startInput(ic, info, restarting, startInputToken);
+ args.recycle();
+ }
+ return;
+ }
default:
Log.w(LOG_TAG, "Unknown message type " + message.what);
}
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 6988048..8af68d7 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -390,6 +390,15 @@
*/
public static final int FLAG_SEND_MOTION_EVENTS = 0x0004000;
+ /**
+ * This flag makes the AccessibilityService an input method editor with a subset of input
+ * method editor capabilities: get the {@link android.view.inputmethod.InputConnection} and get
+ * text selection change notifications.
+ *
+ * @see AccessibilityService#getInputMethod()
+ */
+ public static final int FLAG_INPUT_METHOD_EDITOR = 0x0008000;
+
/** {@hide} */
public static final int FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000;
@@ -497,6 +506,7 @@
* @see #FLAG_ENABLE_ACCESSIBILITY_VOLUME
* @see #FLAG_REQUEST_ACCESSIBILITY_BUTTON
* @see #FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK
+ * @see #FLAG_INPUT_METHOD_EDITOR
*/
public int flags;
@@ -559,6 +569,11 @@
private String mNonLocalizedSummary;
/**
+ * Resource id of the intro of the accessibility service.
+ */
+ private int mIntroResId;
+
+ /**
* Resource id of the description of the accessibility service.
*/
private int mDescriptionResId;
@@ -727,6 +742,11 @@
R.styleable.AccessibilityService_isAccessibilityTool, false);
mTileServiceClassName = asAttributes.getString(
com.android.internal.R.styleable.AccessibilityService_tileService);
+ peekedValue = asAttributes.peekValue(
+ com.android.internal.R.styleable.AccessibilityService_intro);
+ if (peekedValue != null) {
+ mIntroResId = peekedValue.resourceId;
+ }
asAttributes.recycle();
} catch (NameNotFoundException e) {
throw new XmlPullParserException( "Unable to create context for: "
@@ -947,6 +967,29 @@
}
/**
+ * The localized intro of the accessibility service.
+ * <p>
+ * <strong>Statically set from
+ * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
+ * </p>
+ * @return The localized intro if available, and {@code null} if a intro
+ * has not been provided.
+ */
+ @Nullable
+ public CharSequence loadIntro(@NonNull PackageManager packageManager) {
+ if (mIntroResId == /* invalid */ 0) {
+ return null;
+ }
+ ServiceInfo serviceInfo = mResolveInfo.serviceInfo;
+ CharSequence intro = packageManager.getText(serviceInfo.packageName,
+ mIntroResId, serviceInfo.applicationInfo);
+ if (intro != null) {
+ return intro.toString().trim();
+ }
+ return null;
+ }
+
+ /**
* Gets the non-localized description of the accessibility service.
* <p>
* <strong>Statically set from
@@ -1104,6 +1147,7 @@
parcel.writeString(mNonLocalizedDescription);
parcel.writeBoolean(mIsAccessibilityTool);
parcel.writeString(mTileServiceClassName);
+ parcel.writeInt(mIntroResId);
}
private void initFromParcel(Parcel parcel) {
@@ -1127,6 +1171,7 @@
mNonLocalizedDescription = parcel.readString();
mIsAccessibilityTool = parcel.readBoolean();
mTileServiceClassName = parcel.readString();
+ mIntroResId = parcel.readInt();
}
@Override
@@ -1356,6 +1401,8 @@
return "FLAG_REQUEST_FINGERPRINT_GESTURES";
case FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK:
return "FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK";
+ case FLAG_INPUT_METHOD_EDITOR:
+ return "FLAG_INPUT_METHOD_EDITOR";
default:
return null;
}
diff --git a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
index 52a1cad..9a73219 100644
--- a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
@@ -70,6 +70,11 @@
private final ActivityInfo mActivityInfo;
/**
+ * Resource id of the intro of the accessibility shortcut target.
+ */
+ private final int mIntroResId;
+
+ /**
* Resource id of the summary of the accessibility shortcut target.
*/
private final int mSummaryResId;
@@ -160,6 +165,9 @@
// Get tile service class name
mTileServiceClassName = asAttributes.getString(
com.android.internal.R.styleable.AccessibilityShortcutTarget_tileService);
+ // Gets intro
+ mIntroResId = asAttributes.getResourceId(
+ com.android.internal.R.styleable.AccessibilityShortcutTarget_intro, 0);
asAttributes.recycle();
if ((mDescriptionResId == 0 && mHtmlDescriptionRes == 0) || mSummaryResId == 0) {
@@ -203,6 +211,16 @@
}
/**
+ * The localized intro of the accessibility shortcut target.
+ *
+ * @return The localized intro.
+ */
+ @Nullable
+ public String loadIntro(@NonNull PackageManager packageManager) {
+ return loadResourceString(packageManager, mActivityInfo, mIntroResId);
+ }
+
+ /**
* The localized description of the accessibility shortcut target.
*
* @return The localized description.
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
index 375383d..94da61f 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
@@ -24,6 +24,11 @@
import android.accessibilityservice.MagnificationConfig;
import android.view.KeyEvent;
import android.view.MotionEvent;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputBinding;
+import com.android.internal.view.IInputContext;
+import com.android.internal.view.IInputMethodSession;
+import com.android.internal.view.IInputSessionWithIdCallback;
/**
* Top-level interface to an accessibility service component.
@@ -63,4 +68,15 @@
void onAccessibilityButtonAvailabilityChanged(boolean available);
void onSystemActionsChanged();
+
+ void createImeSession(IInputSessionWithIdCallback callback);
+
+ void setImeSessionEnabled(IInputMethodSession session, boolean enabled);
+
+ void bindInput(in InputBinding binding);
+
+ void unbindInput();
+
+ void startInput(in IBinder startInputToken, in IInputContext inputContext,
+ in EditorInfo editorInfo, boolean restarting);
}
diff --git a/core/java/android/accessibilityservice/InputMethod.java b/core/java/android/accessibilityservice/InputMethod.java
new file mode 100644
index 0000000..001d804
--- /dev/null
+++ b/core/java/android/accessibilityservice/InputMethod.java
@@ -0,0 +1,637 @@
+/*
+ * 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.accessibilityservice;
+
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.graphics.Rect;
+import android.inputmethodservice.IInputMethodSessionWrapper;
+import android.inputmethodservice.RemoteInputConnection;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.Trace;
+import android.util.Log;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.CursorAnchorInfo;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.ExtractedText;
+import android.view.inputmethod.InputBinding;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.InputMethodSession;
+import android.view.inputmethod.SurroundingText;
+import android.view.inputmethod.TextAttribute;
+
+import com.android.internal.view.IInputContext;
+import com.android.internal.view.IInputSessionWithIdCallback;
+
+import java.util.concurrent.Executor;
+
+/**
+ * This class provides input method APIs. Some public methods such as
+ * @link #onUpdateSelection(int, int, int, int, int, int)} do nothing by default and service
+ * developers should override them as needed. Developers should also override
+ * {@link AccessibilityService#onCreateInputMethod()} to return
+ * their custom InputMethod implementation. Accessibility services also need to set the
+ * {@link AccessibilityServiceInfo#FLAG_INPUT_METHOD_EDITOR} flag to use input method APIs.
+ */
+public class InputMethod {
+ private static final String LOG_TAG = "A11yInputMethod";
+
+ private final AccessibilityService mService;
+ private InputBinding mInputBinding;
+ private InputConnection mInputConnection;
+ private boolean mInputStarted;
+ private InputConnection mStartedInputConnection;
+ private EditorInfo mInputEditorInfo;
+
+ protected InputMethod(@NonNull AccessibilityService service) {
+ mService = service;
+ }
+
+ /**
+ * Retrieve the currently active InputConnection that is bound to
+ * the input method, or null if there is none.
+ */
+ @Nullable
+ public final AccessibilityInputConnection getCurrentInputConnection() {
+ InputConnection ic = mStartedInputConnection;
+ if (ic != null) {
+ return new AccessibilityInputConnection(ic);
+ }
+ if (mInputConnection != null) {
+ return new AccessibilityInputConnection(mInputConnection);
+ }
+ return null;
+ }
+
+ /**
+ * Whether the input has started.
+ */
+ public final boolean getCurrentInputStarted() {
+ return mInputStarted;
+ }
+
+ /**
+ * Get the EditorInfo which describes several attributes of a text editing object
+ * that an accessibility service is communicating with (typically an EditText).
+ */
+ @Nullable
+ public final EditorInfo getCurrentInputEditorInfo() {
+ return mInputEditorInfo;
+ }
+
+ /**
+ * Called to inform the accessibility service that text input has started in an
+ * editor. You should use this callback to initialize the state of your
+ * input to match the state of the editor given to it.
+ *
+ * @param attribute The attributes of the editor that input is starting
+ * in.
+ * @param restarting Set to true if input is restarting in the same
+ * editor such as because the application has changed the text in
+ * the editor. Otherwise will be false, indicating this is a new
+ * session with the editor.
+ */
+ public void onStartInput(@NonNull EditorInfo attribute, boolean restarting) {
+ // Intentionally empty
+ }
+
+ /**
+ * Called to inform the accessibility service that text input has finished in
+ * the last editor. At this point there may be a call to
+ * {@link #onStartInput(EditorInfo, boolean)} to perform input in a
+ * new editor, or the accessibility service may be left idle. This method is
+ * <em>not</em> called when input restarts in the same editor.
+ *
+ * <p>The default
+ * implementation uses the InputConnection to clear any active composing
+ * text; you can override this (not calling the base class implementation)
+ * to perform whatever behavior you would like.
+ */
+ public void onFinishInput() {
+ InputConnection ic = mStartedInputConnection != null ? mStartedInputConnection
+ : mInputConnection;
+ if (ic != null) {
+ ic.finishComposingText();
+ }
+ }
+
+ /**
+ * Called when the application has reported a new selection region of
+ * the text. This is called whether or not the accessibility service has requested
+ * extracted text updates, although if so it will not receive this call
+ * if the extracted text has changed as well.
+ *
+ * <p>Be careful about changing the text in reaction to this call with
+ * methods such as setComposingText, commitText or
+ * deleteSurroundingText. If the cursor moves as a result, this method
+ * will be called again, which may result in an infinite loop.
+ */
+ public void onUpdateSelection(int oldSelStart, int oldSelEnd, int newSelStart,
+ int newSelEnd, int candidatesStart, int candidatesEnd) {
+ // Intentionally empty
+ }
+
+ final void createImeSession(IInputSessionWithIdCallback callback) {
+ InputMethodSession session = onCreateInputMethodSessionInterface();
+ try {
+ IInputMethodSessionWrapper wrap =
+ new IInputMethodSessionWrapper(mService, session, null);
+ callback.sessionCreated(wrap, mService.getConnectionId());
+ } catch (RemoteException ignored) {
+ }
+ }
+
+ final void setImeSessionEnabled(@NonNull InputMethodSession session, boolean enabled) {
+ ((InputMethodSessionForAccessibility) session).setEnabled(enabled);
+ }
+
+ final void bindInput(@NonNull InputBinding binding) {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AccessibilityService.bindInput");
+ mInputBinding = binding;
+ mInputConnection = binding.getConnection();
+ Log.v(LOG_TAG, "bindInput(): binding=" + binding
+ + " ic=" + mInputConnection);
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ }
+
+ final void unbindInput() {
+ Log.v(LOG_TAG, "unbindInput(): binding=" + mInputBinding
+ + " ic=" + mInputConnection);
+ // Unbind input is per process per display.
+ mInputBinding = null;
+ mInputConnection = null;
+ }
+
+ final void startInput(@Nullable InputConnection ic, @NonNull EditorInfo attribute) {
+ Log.v(LOG_TAG, "startInput(): editor=" + attribute);
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.startInput");
+ doStartInput(ic, attribute, false /* restarting */);
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ }
+
+ final void restartInput(@Nullable InputConnection ic, @NonNull EditorInfo attribute) {
+ Log.v(LOG_TAG, "restartInput(): editor=" + attribute);
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.restartInput");
+ doStartInput(ic, attribute, true /* restarting */);
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ }
+
+
+ final void doStartInput(InputConnection ic, EditorInfo attribute, boolean restarting) {
+ if (!restarting && mInputStarted) {
+ doFinishInput();
+ }
+ mInputStarted = true;
+ mStartedInputConnection = ic;
+ mInputEditorInfo = attribute;
+ Log.v(LOG_TAG, "CALL: onStartInput");
+ onStartInput(attribute, restarting);
+ }
+
+ final void doFinishInput() {
+ Log.v(LOG_TAG, "CALL: doFinishInput");
+ if (mInputStarted) {
+ Log.v(LOG_TAG, "CALL: onFinishInput");
+ onFinishInput();
+ }
+ mInputStarted = false;
+ mStartedInputConnection = null;
+ }
+
+ private InputMethodSession onCreateInputMethodSessionInterface() {
+ return new InputMethodSessionForAccessibility();
+ }
+
+ /**
+ * This class provides the allowed list of {@link InputConnection} APIs for
+ * accessibility services.
+ */
+ public final class AccessibilityInputConnection {
+ private InputConnection mIc;
+ AccessibilityInputConnection(InputConnection ic) {
+ this.mIc = ic;
+ }
+
+ /**
+ * Commit text to the text box and set the new cursor position. This method is
+ * used to allow the IME to provide extra information while setting up text.
+ *
+ * <p>This method commits the contents of the currently composing text, and then
+ * moves the cursor according to {@code newCursorPosition}. If there
+ * is no composing text when this method is called, the new text is
+ * inserted at the cursor position, removing text inside the selection
+ * if any.
+ *
+ * <p>Calling this method will cause the editor to call
+ * {@link #onUpdateSelection(int, int, int, int,
+ * int, int)} on the current accessibility service after the batch input is over.
+ * <strong>Editor authors</strong>, for this to happen you need to
+ * make the changes known to the accessibility service by calling
+ * {@link InputMethodManager#updateSelection(View, int, int, int, int)},
+ * but be careful to wait until the batch edit is over if one is
+ * in progress.</p>
+ *
+ * @param text The text to commit. This may include styles.
+ * @param newCursorPosition The new cursor position around the text,
+ * in Java characters. If > 0, this is relative to the end
+ * of the text - 1; if <= 0, this is relative to the start
+ * of the text. So a value of 1 will always advance the cursor
+ * to the position after the full text being inserted. Note that
+ * this means you can't position the cursor within the text,
+ * because the editor can make modifications to the text
+ * you are providing so it is not possible to correctly specify
+ * locations there.
+ * @param textAttribute The extra information about the text.
+ */
+ public void commitText(@NonNull CharSequence text, int newCursorPosition,
+ @Nullable TextAttribute textAttribute) {
+ if (mIc != null) {
+ mIc.commitText(text, newCursorPosition, textAttribute);
+ }
+ }
+
+ /**
+ * Set the selection of the text editor. To set the cursor
+ * position, start and end should have the same value.
+ *
+ * <p>Since this moves the cursor, calling this method will cause
+ * the editor to call
+ * {@link android.inputmethodservice.InputMethodService#onUpdateSelection(int, int, int,
+ * int,int, int)} on the current IME after the batch input is over.
+ * <strong>Editor authors</strong>, for this to happen you need to
+ * make the changes known to the input method by calling
+ * {@link InputMethodManager#updateSelection(View, int, int, int, int)},
+ * but be careful to wait until the batch edit is over if one is
+ * in progress.</p>
+ *
+ * <p>This has no effect on the composing region which must stay
+ * unchanged. The order of start and end is not important. In
+ * effect, the region from start to end and the region from end to
+ * start is the same. Editor authors, be ready to accept a start
+ * that is greater than end.</p>
+ *
+ * @param start the character index where the selection should start.
+ * @param end the character index where the selection should end.
+ */
+ public void setSelection(int start, int end) {
+ if (mIc != null) {
+ mIc.setSelection(start, end);
+ }
+ }
+
+ /**
+ * Gets the surrounding text around the current cursor, with <var>beforeLength</var>
+ * characters of text before the cursor (start of the selection), <var>afterLength</var>
+ * characters of text after the cursor (end of the selection), and all of the selected
+ * text. The range are for java characters, not glyphs that can be multiple characters.
+ *
+ * <p>This method may fail either if the input connection has become invalid (such as its
+ * process crashing), or the client is taking too long to respond with the text (it is
+ * given a couple seconds to return), or the protocol is not supported. In any of these
+ * cases, null is returned.
+ *
+ * <p>This method does not affect the text in the editor in any way, nor does it affect the
+ * selection or composing spans.</p>
+ *
+ * <p>If {@link InputConnection#GET_TEXT_WITH_STYLES} is supplied as flags, the editor
+ * should return a {@link android.text.Spanned} with all the spans set on the text.</p>
+ *
+ * <p><strong>Accessibility service authors:</strong> please consider this will trigger an
+ * IPC round-trip that will take some time. Assume this method consumes a lot of time.
+ *
+ * @param beforeLength The expected length of the text before the cursor.
+ * @param afterLength The expected length of the text after the cursor.
+ * @param flags Supplies additional options controlling how the text is returned. May be
+ * either {@code 0} or {@link InputConnection#GET_TEXT_WITH_STYLES}.
+ * @return an {@link android.view.inputmethod.SurroundingText} object describing the
+ * surrounding text and state of selection, or null if the input connection is no longer
+ * valid, or the editor can't comply with the request for some reason, or the application
+ * does not implement this method. The length of the returned text might be less than the
+ * sum of <var>beforeLength</var> and <var>afterLength</var> .
+ * @throws IllegalArgumentException if {@code beforeLength} or {@code afterLength} is
+ * negative.
+ */
+ @Nullable
+ public SurroundingText getSurroundingText(
+ @IntRange(from = 0) int beforeLength, @IntRange(from = 0) int afterLength,
+ @InputConnection.GetTextType int flags) {
+ if (mIc != null) {
+ return mIc.getSurroundingText(beforeLength, afterLength, flags);
+ }
+ return null;
+ }
+
+ /**
+ * Delete <var>beforeLength</var> characters of text before the
+ * current cursor position, and delete <var>afterLength</var>
+ * characters of text after the current cursor position, excluding
+ * the selection. Before and after refer to the order of the
+ * characters in the string, not to their visual representation:
+ * this means you don't have to figure out the direction of the
+ * text and can just use the indices as-is.
+ *
+ * <p>The lengths are supplied in Java chars, not in code points
+ * or in glyphs.</p>
+ *
+ * <p>Since this method only operates on text before and after the
+ * selection, it can't affect the contents of the selection. This
+ * may affect the composing span if the span includes characters
+ * that are to be deleted, but otherwise will not change it. If
+ * some characters in the composing span are deleted, the
+ * composing span will persist but get shortened by however many
+ * chars inside it have been removed.</p>
+ *
+ * <p><strong>Accessibility service authors:</strong> please be careful not to
+ * delete only half of a surrogate pair. Also take care not to
+ * delete more characters than are in the editor, as that may have
+ * ill effects on the application. Calling this method will cause
+ * the editor to call
+ * {@link android.inputmethodservice.InputMethodService#onUpdateSelection(int, int, int, int,
+ * int, int)} on your service after the batch input is over.</p>
+ *
+ * <p><strong>Editor authors:</strong> please be careful of race
+ * conditions in implementing this call. An IME can make a change
+ * to the text or change the selection position and use this
+ * method right away; you need to make sure the effects are
+ * consistent with the results of the latest edits. Also, although
+ * the IME should not send lengths bigger than the contents of the
+ * string, you should check the values for overflows and trim the
+ * indices to the size of the contents to avoid crashes. Since
+ * this changes the contents of the editor, you need to make the
+ * changes known to the input method by calling
+ * {@link InputMethodManager#updateSelection(View, int, int, int, int)},
+ * but be careful to wait until the batch edit is over if one is
+ * in progress.</p>
+ *
+ * @param beforeLength The number of characters before the cursor to be deleted, in code
+ * unit. If this is greater than the number of existing characters between the
+ * beginning of the text and the cursor, then this method does not fail but deletes
+ * all the characters in that range.
+ * @param afterLength The number of characters after the cursor to be deleted, in code unit.
+ * If this is greater than the number of existing characters between the cursor and
+ * the end of the text, then this method does not fail but deletes all the characters
+ * in that range.
+ */
+ public void deleteSurroundingText(int beforeLength, int afterLength) {
+ if (mIc != null) {
+ mIc.deleteSurroundingText(beforeLength, afterLength);
+ }
+ }
+
+ /**
+ * Send a key event to the process that is currently attached
+ * through this input connection. The event will be dispatched
+ * like a normal key event, to the currently focused view; this
+ * generally is the view that is providing this InputConnection,
+ * but due to the asynchronous nature of this protocol that can
+ * not be guaranteed and the focus may have changed by the time
+ * the event is received.
+ *
+ * <p>This method can be used to send key events to the
+ * application. For example, an on-screen keyboard may use this
+ * method to simulate a hardware keyboard. There are three types
+ * of standard keyboards, numeric (12-key), predictive (20-key)
+ * and ALPHA (QWERTY). You can specify the keyboard type by
+ * specify the device id of the key event.</p>
+ *
+ * <p>You will usually want to set the flag
+ * {@link KeyEvent#FLAG_SOFT_KEYBOARD KeyEvent.FLAG_SOFT_KEYBOARD}
+ * on all key event objects you give to this API; the flag will
+ * not be set for you.</p>
+ *
+ * <p>Note that it's discouraged to send such key events in normal
+ * operation; this is mainly for use with
+ * {@link android.text.InputType#TYPE_NULL} type text fields. Use
+ * the {@link #commitText} family of methods to send text to the
+ * application instead.</p>
+ *
+ * @param event The key event.
+ *
+ * @see KeyEvent
+ * @see KeyCharacterMap#NUMERIC
+ * @see KeyCharacterMap#PREDICTIVE
+ * @see KeyCharacterMap#ALPHA
+ */
+ public void sendKeyEvent(@NonNull KeyEvent event) {
+ if (mIc != null) {
+ mIc.sendKeyEvent(event);
+ }
+ }
+
+ /**
+ * Have the editor perform an action it has said it can do.
+ *
+ * @param editorAction This must be one of the action constants for
+ * {@link EditorInfo#imeOptions EditorInfo.imeOptions}, such as
+ * {@link EditorInfo#IME_ACTION_GO EditorInfo.EDITOR_ACTION_GO}, or the value of
+ * {@link EditorInfo#actionId EditorInfo.actionId} if a custom action is available.
+ */
+ public void performEditorAction(int editorAction) {
+ if (mIc != null) {
+ mIc.performEditorAction(editorAction);
+ }
+ }
+
+ /**
+ * Perform a context menu action on the field. The given id may be one of:
+ * {@link android.R.id#selectAll},
+ * {@link android.R.id#startSelectingText}, {@link android.R.id#stopSelectingText},
+ * {@link android.R.id#cut}, {@link android.R.id#copy},
+ * {@link android.R.id#paste}, {@link android.R.id#copyUrl},
+ * or {@link android.R.id#switchInputMethod}
+ */
+ public void performContextMenuAction(int id) {
+ if (mIc != null) {
+ mIc.performContextMenuAction(id);
+ }
+ }
+
+ /**
+ * Retrieve the current capitalization mode in effect at the
+ * current cursor position in the text. See
+ * {@link android.text.TextUtils#getCapsMode TextUtils.getCapsMode}
+ * for more information.
+ *
+ * <p>This method may fail either if the input connection has
+ * become invalid (such as its process crashing) or the client is
+ * taking too long to respond with the text (it is given a couple
+ * seconds to return). In either case, 0 is returned.</p>
+ *
+ * <p>This method does not affect the text in the editor in any
+ * way, nor does it affect the selection or composing spans.</p>
+ *
+ * <p><strong>Editor authors:</strong> please be careful of race
+ * conditions in implementing this call. An IME can change the
+ * cursor position and use this method right away; you need to make
+ * sure the returned value is consistent with the results of the
+ * latest edits and changes to the cursor position.</p>
+ *
+ * @param reqModes The desired modes to retrieve, as defined by
+ * {@link android.text.TextUtils#getCapsMode TextUtils.getCapsMode}. These
+ * constants are defined so that you can simply pass the current
+ * {@link EditorInfo#inputType TextBoxAttribute.contentType} value
+ * directly in to here.
+ * @return the caps mode flags that are in effect at the current
+ * cursor position. See TYPE_TEXT_FLAG_CAPS_* in {@link android.text.InputType}.
+ */
+ public int getCursorCapsMode(int reqModes) {
+ if (mIc != null) {
+ return mIc.getCursorCapsMode(reqModes);
+ }
+ return 0;
+ }
+
+ /**
+ * Clear the given meta key pressed states in the given input
+ * connection.
+ *
+ * <p>This can be used by the accessibility service to clear the meta key states set
+ * by a hardware keyboard with latched meta keys, if the editor
+ * keeps track of these.</p>
+ *
+ * @param states The states to be cleared, may be one or more bits as
+ * per {@link KeyEvent#getMetaState() KeyEvent.getMetaState()}.
+ */
+ public void clearMetaKeyStates(int states) {
+ if (mIc != null) {
+ mIc.clearMetaKeyStates(states);
+ }
+ }
+ }
+
+ /**
+ * Concrete implementation of InputMethodSession that provides all of the standard behavior
+ * for an input method session.
+ */
+ private final class InputMethodSessionForAccessibility implements InputMethodSession {
+ boolean mEnabled = true;
+
+ public void setEnabled(boolean enabled) {
+ mEnabled = enabled;
+ }
+
+ @Override
+ public void finishInput() {
+ if (mEnabled) {
+ doFinishInput();
+ }
+ }
+
+ @Override
+ public void updateSelection(int oldSelStart, int oldSelEnd, int newSelStart,
+ int newSelEnd, int candidatesStart, int candidatesEnd) {
+ if (mEnabled) {
+ InputMethod.this.onUpdateSelection(oldSelEnd, oldSelEnd, newSelStart,
+ newSelEnd, candidatesStart, candidatesEnd);
+ }
+ }
+
+ @Override
+ public void viewClicked(boolean focusChanged) {
+ }
+
+ @Override
+ public void updateCursor(@NonNull Rect newCursor) {
+ }
+
+ @Override
+ public void displayCompletions(
+ @SuppressLint("ArrayReturn") @NonNull CompletionInfo[] completions) {
+ }
+
+ @Override
+ public void updateExtractedText(int token, @NonNull ExtractedText text) {
+ }
+
+ public void dispatchKeyEvent(int seq, @NonNull KeyEvent event,
+ @NonNull @CallbackExecutor Executor executor, @NonNull EventCallback callback) {
+ }
+
+ @Override
+ public void dispatchKeyEvent(int seq, @NonNull KeyEvent event,
+ @NonNull EventCallback callback) {
+ }
+
+ public void dispatchTrackballEvent(int seq, @NonNull MotionEvent event,
+ @NonNull @CallbackExecutor Executor executor, @NonNull EventCallback callback) {
+ }
+
+ @Override
+ public void dispatchTrackballEvent(int seq, @NonNull MotionEvent event,
+ @NonNull EventCallback callback) {
+ }
+
+ public void dispatchGenericMotionEvent(int seq, @NonNull MotionEvent event,
+ @NonNull @CallbackExecutor Executor executor, @NonNull EventCallback callback) {
+ }
+
+ @Override
+ public void dispatchGenericMotionEvent(int seq, @NonNull MotionEvent event,
+ @NonNull EventCallback callback) {
+ }
+
+ @Override
+ public void appPrivateCommand(@NonNull String action, @NonNull Bundle data) {
+ }
+
+ @Override
+ public void toggleSoftInput(int showFlags, int hideFlags) {
+ }
+
+ @Override
+ public void updateCursorAnchorInfo(@NonNull CursorAnchorInfo cursorAnchorInfo) {
+ }
+
+ @Override
+ public void notifyImeHidden() {
+ }
+
+ @Override
+ public void removeImeSurface() {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void invalidateInputInternal(EditorInfo editorInfo, IInputContext inputContext,
+ int sessionId) {
+ // TODO(b/217788708): Add automated test.
+ if (mStartedInputConnection instanceof RemoteInputConnection) {
+ final RemoteInputConnection ric =
+ (RemoteInputConnection) mStartedInputConnection;
+ if (!ric.isSameConnection(inputContext)) {
+ // This is not an error, and can be safely ignored.
+ return;
+ }
+ editorInfo.makeCompatible(
+ mService.getApplicationInfo().targetSdkVersion);
+ restartInput(new RemoteInputConnection(ric, sessionId), editorInfo);
+ }
+ }
+ }
+}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index e022700..983dde3 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -17,6 +17,8 @@
package android.app;
import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.inMultiWindowMode;
import static android.os.Process.myUid;
@@ -44,7 +46,10 @@
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.ActivityNotFoundException;
+import android.content.ComponentCallbacks;
import android.content.ComponentCallbacks2;
+import android.content.ComponentCallbacksController;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -979,6 +984,8 @@
@Nullable
private DumpableContainerImpl mDumpableContainer;
+ private ComponentCallbacksController mCallbacksController;
+
private final WindowControllerCallback mWindowControllerCallback =
new WindowControllerCallback() {
/**
@@ -1320,6 +1327,28 @@
}
}
+ @Override
+ public void registerComponentCallbacks(ComponentCallbacks callback) {
+ if (CompatChanges.isChangeEnabled(OVERRIDABLE_COMPONENT_CALLBACKS)
+ && mCallbacksController == null) {
+ mCallbacksController = new ComponentCallbacksController();
+ }
+ if (mCallbacksController != null) {
+ mCallbacksController.registerCallbacks(callback);
+ } else {
+ super.registerComponentCallbacks(callback);
+ }
+ }
+
+ @Override
+ public void unregisterComponentCallbacks(ComponentCallbacks callback) {
+ if (mCallbacksController != null) {
+ mCallbacksController.unregisterCallbacks(callback);
+ } else {
+ super.unregisterComponentCallbacks(callback);
+ }
+ }
+
private void dispatchActivityPreCreated(@Nullable Bundle savedInstanceState) {
getApplication().dispatchActivityPreCreated(this, savedInstanceState);
Object[] callbacks = collectActivityLifecycleCallbacks();
@@ -2665,9 +2694,12 @@
if (mUiTranslationController != null) {
mUiTranslationController.onActivityDestroyed();
}
-
if (mDefaultBackCallback != null) {
getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(mDefaultBackCallback);
+ mDefaultBackCallback = null;
+ }
+ if (mCallbacksController != null) {
+ mCallbacksController.clearCallbacks();
}
}
@@ -2988,6 +3020,9 @@
}
dispatchActivityConfigurationChanged();
+ if (mCallbacksController != null) {
+ mCallbacksController.dispatchConfigurationChanged(newConfig);
+ }
}
/**
@@ -3159,12 +3194,18 @@
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onLowMemory " + this);
mCalled = true;
mFragments.dispatchLowMemory();
+ if (mCallbacksController != null) {
+ mCallbacksController.dispatchLowMemory();
+ }
}
public void onTrimMemory(int level) {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onTrimMemory " + this + ": " + level);
mCalled = true;
mFragments.dispatchTrimMemory(level);
+ if (mCallbacksController != null) {
+ mCallbacksController.dispatchTrimMemory(level);
+ }
}
/**
@@ -5435,26 +5476,115 @@
}
/**
+ * Launch an activity for which you would like a result when it finished.
+ * When this activity exits, your
+ * onActivityResult() method will be called with the given requestCode.
+ * Using a negative requestCode is the same as calling
+ * {@link #startActivity} (the activity is not launched as a sub-activity).
+ *
+ * <p>Note that this method should only be used with Intent protocols
+ * that are defined to return a result. In other protocols (such as
+ * {@link Intent#ACTION_MAIN} or {@link Intent#ACTION_VIEW}), you may
+ * not get the result when you expect. For example, if the activity you
+ * are launching uses {@link Intent#FLAG_ACTIVITY_NEW_TASK}, it will not
+ * run in your task and thus you will immediately receive a cancel result.
+ *
+ * <p>As a special case, if you call startActivityForResult() with a requestCode
+ * >= 0 during the initial onCreate(Bundle savedInstanceState)/onResume() of your
+ * activity, then your window will not be displayed until a result is
+ * returned back from the started activity. This is to avoid visible
+ * flickering when redirecting to another activity.
+ *
+ * <p>This method throws {@link android.content.ActivityNotFoundException}
+ * if there was no Activity found to run the given Intent.
+ *
+ * @param intent The intent to start.
+ * @param requestCode If >= 0, this code will be returned in
+ * onActivityResult() when the activity exits.
+ * @param user The user to start the intent as.
* @hide Implement to provide correct calling token.
*/
- @UnsupportedAppUsage
- public void startActivityForResultAsUser(Intent intent, int requestCode, UserHandle user) {
+ @SystemApi
+ @RequiresPermission(anyOf = {INTERACT_ACROSS_USERS, INTERACT_ACROSS_USERS_FULL})
+ public void startActivityForResultAsUser(@NonNull Intent intent, int requestCode,
+ @NonNull UserHandle user) {
startActivityForResultAsUser(intent, requestCode, null, user);
}
/**
+ * Launch an activity for which you would like a result when it finished.
+ * When this activity exits, your
+ * onActivityResult() method will be called with the given requestCode.
+ * Using a negative requestCode is the same as calling
+ * {@link #startActivity} (the activity is not launched as a sub-activity).
+ *
+ * <p>Note that this method should only be used with Intent protocols
+ * that are defined to return a result. In other protocols (such as
+ * {@link Intent#ACTION_MAIN} or {@link Intent#ACTION_VIEW}), you may
+ * not get the result when you expect. For example, if the activity you
+ * are launching uses {@link Intent#FLAG_ACTIVITY_NEW_TASK}, it will not
+ * run in your task and thus you will immediately receive a cancel result.
+ *
+ * <p>As a special case, if you call startActivityForResult() with a requestCode
+ * >= 0 during the initial onCreate(Bundle savedInstanceState)/onResume() of your
+ * activity, then your window will not be displayed until a result is
+ * returned back from the started activity. This is to avoid visible
+ * flickering when redirecting to another activity.
+ *
+ * <p>This method throws {@link android.content.ActivityNotFoundException}
+ * if there was no Activity found to run the given Intent.
+ *
+ * @param intent The intent to start.
+ * @param requestCode If >= 0, this code will be returned in
+ * onActivityResult() when the activity exits.
+ * @param options Additional options for how the Activity should be started. See {@link
+ * android.content.Context#startActivity(Intent, Bundle)} for more details.
+ * @param user The user to start the intent as.
* @hide Implement to provide correct calling token.
*/
- public void startActivityForResultAsUser(Intent intent, int requestCode,
- @Nullable Bundle options, UserHandle user) {
+ @SystemApi
+ @RequiresPermission(anyOf = {INTERACT_ACROSS_USERS, INTERACT_ACROSS_USERS_FULL})
+ public void startActivityForResultAsUser(@NonNull Intent intent, int requestCode,
+ @Nullable Bundle options, @NonNull UserHandle user) {
startActivityForResultAsUser(intent, mEmbeddedID, requestCode, options, user);
}
/**
+ * Launch an activity for which you would like a result when it finished.
+ * When this activity exits, your
+ * onActivityResult() method will be called with the given requestCode.
+ * Using a negative requestCode is the same as calling
+ * {@link #startActivity} (the activity is not launched as a sub-activity).
+ *
+ * <p>Note that this method should only be used with Intent protocols
+ * that are defined to return a result. In other protocols (such as
+ * {@link Intent#ACTION_MAIN} or {@link Intent#ACTION_VIEW}), you may
+ * not get the result when you expect. For example, if the activity you
+ * are launching uses {@link Intent#FLAG_ACTIVITY_NEW_TASK}, it will not
+ * run in your task and thus you will immediately receive a cancel result.
+ *
+ * <p>As a special case, if you call startActivityForResult() with a requestCode
+ * >= 0 during the initial onCreate(Bundle savedInstanceState)/onResume() of your
+ * activity, then your window will not be displayed until a result is
+ * returned back from the started activity. This is to avoid visible
+ * flickering when redirecting to another activity.
+ *
+ * <p>This method throws {@link android.content.ActivityNotFoundException}
+ * if there was no Activity found to run the given Intent.
+ *
+ * @param intent The intent to start.
+ * @param requestCode If >= 0, this code will be returned in
+ * onActivityResult() when the activity exits.
+ * @param options Additional options for how the Activity should be started. See {@link
+ * android.content.Context#startActivity(Intent, Bundle)} for more details.
+ * @param user The user to start the intent as.
* @hide Implement to provide correct calling token.
*/
- public void startActivityForResultAsUser(Intent intent, String resultWho, int requestCode,
- @Nullable Bundle options, UserHandle user) {
+ @SystemApi
+ @RequiresPermission(anyOf = {INTERACT_ACROSS_USERS, INTERACT_ACROSS_USERS_FULL})
+ public void startActivityForResultAsUser(@NonNull Intent intent, @NonNull String resultWho,
+ int requestCode,
+ @Nullable Bundle options, @NonNull UserHandle user) {
if (mParent != null) {
throw new RuntimeException("Can't be called from a child");
}
@@ -5464,7 +5594,7 @@
options, user);
if (ar != null) {
mMainThread.sendActivityResult(
- mToken, mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData());
+ mToken, mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData());
}
if (requestCode >= 0) {
// If this start is requesting a result, we can avoid making
@@ -5489,9 +5619,23 @@
}
/**
- * @hide Implement to provide correct calling token.
+ * Version of {@link #startActivity(Intent, Bundle)} that allows you to specify the
+ * user the activity will be started for. This is not available to applications
+ * that are not pre-installed on the system image.
+ * @param intent The description of the activity to start.
+ *
+ * @param user The UserHandle of the user to start this activity for.
+ * @param options Additional options for how the Activity should be started.
+ * May be null if there are no options. See {@link android.app.ActivityOptions}
+ * for how to build the Bundle supplied here; there are no supported definitions
+ * for building it manually.
+ * @throws ActivityNotFoundException
+ * @hide
*/
- public void startActivityAsUser(Intent intent, Bundle options, UserHandle user) {
+ @SystemApi
+ @RequiresPermission(anyOf = {INTERACT_ACROSS_USERS, INTERACT_ACROSS_USERS_FULL})
+ public void startActivityAsUser(@NonNull Intent intent,
+ @Nullable Bundle options, @NonNull UserHandle user) {
if (mParent != null) {
throw new RuntimeException("Can't be called from a child");
}
@@ -8556,8 +8700,18 @@
}
/**
- * If set to true, this indicates to the system that it should never take a
- * screenshot of the activity to be used as a representation while it is not in a started state.
+ * @hide
+ */
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.S,
+ publicAlternatives = "Use {@link #setRecentsScreenshotEnabled(boolean)} instead.")
+ public void setDisablePreviewScreenshots(boolean disable) {
+ setRecentsScreenshotEnabled(!disable);
+ }
+
+ /**
+ * If set to false, this indicates to the system that it should never take a
+ * screenshot of the activity to be used as a representation in recents screen. By default, this
+ * value is {@code true}.
* <p>
* Note that the system may use the window background of the theme instead to represent
* the window when it is not running.
@@ -8570,12 +8724,10 @@
* {@link android.service.voice.VoiceInteractionService} requests a screenshot via
* {@link android.service.voice.VoiceInteractionSession#SHOW_WITH_SCREENSHOT}.
*
- * @param disable {@code true} to disable preview screenshots; {@code false} otherwise.
- * @hide
+ * @param enabled {@code true} to enable recents screenshots; {@code false} otherwise.
*/
- @UnsupportedAppUsage
- public void setDisablePreviewScreenshots(boolean disable) {
- ActivityClient.getInstance().setDisablePreviewScreenshots(mToken, disable);
+ public void setRecentsScreenshotEnabled(boolean enabled) {
+ ActivityClient.getInstance().setRecentsScreenshotEnabled(mToken, enabled);
}
/**
diff --git a/core/java/android/app/ActivityClient.java b/core/java/android/app/ActivityClient.java
index 605a1fa..4715e0f 100644
--- a/core/java/android/app/ActivityClient.java
+++ b/core/java/android/app/ActivityClient.java
@@ -438,9 +438,9 @@
}
}
- void setDisablePreviewScreenshots(IBinder token, boolean disable) {
+ void setRecentsScreenshotEnabled(IBinder token, boolean enabled) {
try {
- getActivityClientController().setDisablePreviewScreenshots(token, disable);
+ getActivityClientController().setRecentsScreenshotEnabled(token, enabled);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index a58ceaa..294621e 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -779,6 +779,16 @@
* @param started {@code true} if the process transits from non-FGS state to FGS state.
*/
void onForegroundServiceStateChanged(String packageName, int uid, int pid, boolean started);
+
+ /**
+ * Call when the notification of the foreground service is updated.
+ *
+ * @param packageName The package name of the process.
+ * @param uid The UID of the process.
+ * @param foregroundId The current foreground service notification ID, a negative value
+ * means this notification is being removed.
+ */
+ void onForegroundServiceNotificationUpdated(String packageName, int uid, int foregroundId);
}
/**
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index e405b60..5012121 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -1121,7 +1121,7 @@
mPackageName = opts.getString(KEY_PACKAGE_NAME);
try {
- mUsageTimeReport = opts.getParcelable(KEY_USAGE_TIME_REPORT);
+ mUsageTimeReport = opts.getParcelable(KEY_USAGE_TIME_REPORT, PendingIntent.class);
} catch (RuntimeException e) {
Slog.w(TAG, e);
}
@@ -1429,7 +1429,6 @@
/**
* Gets the style can be used for cold-launching an activity.
* @see #setSplashScreenStyle(int)
- * @hide
*/
public @SplashScreen.SplashScreenStyle int getSplashScreenStyle() {
return mSplashScreenStyle;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 5b8969e..61d1865 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2132,7 +2132,16 @@
Looper.myLooper().quit();
break;
case RECEIVER:
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveComp");
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+ ReceiverData rec = (ReceiverData) msg.obj;
+ if (rec.intent != null) {
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+ "broadcastReceiveComp: " + rec.intent.getAction());
+ } else {
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+ "broadcastReceiveComp");
+ }
+ }
handleReceiver((ReceiverData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 8181a74..a3dd705a 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1998,7 +1998,7 @@
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
String instanceName, Handler handler, Executor executor, UserHandle user) {
// Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser and
- // ActivityManagerService.LocalService.startAndBindSupplementalProcessService
+ // ActivityManagerLocal.bindSupplementalProcessService
IServiceConnection sd;
if (conn == null) {
throw new IllegalArgumentException("connection is null");
@@ -2900,6 +2900,14 @@
}
}
+ /**
+ * @hide
+ */
+ @Override
+ public int getAssociatedDisplayId() {
+ return isAssociatedWithDisplay() ? getDisplayId() : Display.INVALID_DISPLAY;
+ }
+
@Override
public Display getDisplayNoVerify() {
if (mDisplay == null) {
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 2084775..aa6c184 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -465,6 +465,7 @@
}
};
getOnBackInvokedDispatcher().registerSystemOnBackInvokedCallback(mDefaultBackCallback);
+ mDefaultBackCallback = null;
}
}
diff --git a/core/java/android/app/DialogFragment.java b/core/java/android/app/DialogFragment.java
index 9fea3f7..cadbf23 100644
--- a/core/java/android/app/DialogFragment.java
+++ b/core/java/android/app/DialogFragment.java
@@ -140,7 +140,7 @@
* embed}
*
* @deprecated Use the <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>
- * {@link android.support.v4.app.DialogFragment} for consistent behavior across all devices
+ * {@link androidx.fragment.app.DialogFragment} for consistent behavior across all devices
* and access to <a href="{@docRoot}topic/libraries/architecture/lifecycle.html">Lifecycle</a>.
*/
@Deprecated
diff --git a/core/java/android/app/FragmentContainer.java b/core/java/android/app/FragmentContainer.java
index 536c866..ff9dbcb 100644
--- a/core/java/android/app/FragmentContainer.java
+++ b/core/java/android/app/FragmentContainer.java
@@ -26,7 +26,7 @@
* Callbacks to a {@link Fragment}'s container.
*
* @deprecated Use the <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>
- * {@link android.support.v4.app.FragmentContainer}.
+ * {@link androidx.fragment.app.FragmentContainer}.
*/
@Deprecated
public abstract class FragmentContainer {
diff --git a/core/java/android/app/FragmentController.java b/core/java/android/app/FragmentController.java
index 150b7a5..3c8d760 100644
--- a/core/java/android/app/FragmentController.java
+++ b/core/java/android/app/FragmentController.java
@@ -41,7 +41,7 @@
* The methods provided by {@link FragmentController} are for that purpose.
*
* @deprecated Use the <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>
- * {@link android.support.v4.app.FragmentController}
+ * {@link androidx.fragment.app.FragmentController}
*/
@Deprecated
public class FragmentController {
diff --git a/core/java/android/app/FragmentHostCallback.java b/core/java/android/app/FragmentHostCallback.java
index 9e887b8..6cfdc53 100644
--- a/core/java/android/app/FragmentHostCallback.java
+++ b/core/java/android/app/FragmentHostCallback.java
@@ -40,7 +40,7 @@
* applicable to the host.
*
* @deprecated Use the <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>
- * {@link android.support.v4.app.FragmentHostCallback}
+ * {@link androidx.fragment.app.FragmentHostCallback}
*/
@Deprecated
public abstract class FragmentHostCallback<E> extends FragmentContainer {
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 5435558..f8f846d 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -72,12 +72,12 @@
* While the FragmentManager API was introduced in
* {@link android.os.Build.VERSION_CODES#HONEYCOMB}, a version of the API
* at is also available for use on older platforms through
- * {@link android.support.v4.app.FragmentActivity}. See the blog post
+ * {@link androidx.fragment.app.FragmentActivity}. See the blog post
* <a href="http://android-developers.blogspot.com/2011/03/fragments-for-all.html">
* Fragments For All</a> for more details.
*
* @deprecated Use the <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>
- * {@link android.support.v4.app.FragmentManager} for consistent behavior across all devices
+ * {@link androidx.fragment.app.FragmentManager} for consistent behavior across all devices
* and access to <a href="{@docRoot}topic/libraries/architecture/lifecycle.html">Lifecycle</a>.
*/
@Deprecated
@@ -94,7 +94,7 @@
* will be persisted across activity instances.
*
* @deprecated Use the <a href="{@docRoot}tools/extras/support-library.html">
- * Support Library</a> {@link android.support.v4.app.FragmentManager.BackStackEntry}
+ * Support Library</a> {@link androidx.fragment.app.FragmentManager.BackStackEntry}
*/
@Deprecated
public interface BackStackEntry {
@@ -142,7 +142,7 @@
*
* @deprecated Use the <a href="{@docRoot}tools/extras/support-library.html">
* Support Library</a>
- * {@link android.support.v4.app.FragmentManager.OnBackStackChangedListener}
+ * {@link androidx.fragment.app.FragmentManager.OnBackStackChangedListener}
*/
@Deprecated
public interface OnBackStackChangedListener {
@@ -446,7 +446,7 @@
*
* @deprecated Use the <a href="{@docRoot}tools/extras/support-library.html">
* Support Library</a>
- * {@link android.support.v4.app.FragmentManager.FragmentLifecycleCallbacks}
+ * {@link androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks}
*/
@Deprecated
public abstract static class FragmentLifecycleCallbacks {
diff --git a/core/java/android/app/FragmentManagerNonConfig.java b/core/java/android/app/FragmentManagerNonConfig.java
index 326438a..ae7fd64 100644
--- a/core/java/android/app/FragmentManagerNonConfig.java
+++ b/core/java/android/app/FragmentManagerNonConfig.java
@@ -29,7 +29,7 @@
* {@link FragmentController#restoreAllState(Parcelable, FragmentManagerNonConfig)}.</p>
*
* @deprecated Use the <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>
- * {@link android.support.v4.app.FragmentManagerNonConfig}
+ * {@link androidx.fragment.app.FragmentManagerNonConfig}
*/
@Deprecated
public class FragmentManagerNonConfig {
diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java
index 713a559..34c4928 100644
--- a/core/java/android/app/FragmentTransaction.java
+++ b/core/java/android/app/FragmentTransaction.java
@@ -23,7 +23,7 @@
* </div>
*
* @deprecated Use the <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>
- * {@link android.support.v4.app.FragmentTransaction}
+ * {@link androidx.fragment.app.FragmentTransaction}
*/
@Deprecated
public abstract class FragmentTransaction {
diff --git a/core/java/android/app/GameManager.java b/core/java/android/app/GameManager.java
index 040399e..6f49c9e 100644
--- a/core/java/android/app/GameManager.java
+++ b/core/java/android/app/GameManager.java
@@ -109,6 +109,7 @@
*
* @hide
*/
+ @TestApi
@UserHandleAware
@RequiresPermission(Manifest.permission.MANAGE_GAME_MODE)
public @GameMode int getGameMode(@NonNull String packageName) {
diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl
index 396e552..f9439cb 100644
--- a/core/java/android/app/IActivityClientController.aidl
+++ b/core/java/android/app/IActivityClientController.aidl
@@ -115,8 +115,8 @@
int enterAnim, int exitAnim, int backgroundColor);
int setVrMode(in IBinder token, boolean enabled, in ComponentName packageName);
- /** See {@link android.app.Activity#setDisablePreviewScreenshots}. */
- oneway void setDisablePreviewScreenshots(in IBinder token, boolean disable);
+ /** See {@link android.app.Activity#setRecentsScreenshotEnabled}. */
+ oneway void setRecentsScreenshotEnabled(in IBinder token, boolean enabled);
/**
* It should only be called from home activity to remove its outdated snapshot. The home
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index c5add66..490afc1 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -128,8 +128,10 @@
int callingUid, in Intent intent, in String resolvedType,
in IVoiceInteractionSession session, in IVoiceInteractor interactor, int flags,
in ProfilerInfo profilerInfo, in Bundle options, int userId);
+ String getVoiceInteractorPackageName(in IBinder callingVoiceInteractor);
int startAssistantActivity(in String callingPackage, in String callingFeatureId, int callingPid,
int callingUid, in Intent intent, in String resolvedType, in Bundle options, int userId);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_ACTIVITY)")
int startActivityFromGameSession(IApplicationThread caller, in String callingPackage,
in String callingFeatureId, int callingPid, int callingUid, in Intent intent,
int taskId, int userId);
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index a74438a..e0c69df 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -381,10 +381,6 @@
* Force the global system in or out of touch mode. This can be used if your
* instrumentation relies on the UI being in one more or the other when it starts.
*
- * <p><b>Note:</b> Starting from Android {@link Build.VERSION_CODES#TIRAMISU}, this method
- * will only have an effect if the calling process is also the focused window owner or has
- * {@link android.permission#MODIFY_TOUCH_MODE_STATE} permission granted.
- *
* @param inTouch Set to true to be in touch mode, false to be in focus mode.
*/
public void setInTouchMode(boolean inTouch) {
diff --git a/core/java/android/app/IntentService.java b/core/java/android/app/IntentService.java
index 5de0d69..2e83308 100644
--- a/core/java/android/app/IntentService.java
+++ b/core/java/android/app/IntentService.java
@@ -52,7 +52,7 @@
* guide.</p>
* </div>
*
- * @see android.support.v4.app.JobIntentService
+ * @see androidx.core.app.JobIntentService
*
* @deprecated IntentService is subject to all the
* <a href="{@docRoot}about/versions/oreo/background.html">background execution limits</a>
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 5d1f4df..9910000 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -591,7 +591,7 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public boolean isDeviceLocked(int userId) {
try {
- return mTrustManager.isDeviceLocked(userId);
+ return mTrustManager.isDeviceLocked(userId, mContext.getAssociatedDisplayId());
} catch (RemoteException e) {
return false;
}
@@ -617,7 +617,7 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean isDeviceSecure(int userId) {
try {
- return mTrustManager.isDeviceSecure(userId);
+ return mTrustManager.isDeviceSecure(userId, mContext.getAssociatedDisplayId());
} catch (RemoteException e) {
return false;
}
diff --git a/core/java/android/app/ListFragment.java b/core/java/android/app/ListFragment.java
index 7790f70..b6d80ca 100644
--- a/core/java/android/app/ListFragment.java
+++ b/core/java/android/app/ListFragment.java
@@ -146,7 +146,7 @@
* @see android.widget.ListView
*
* @deprecated Use the <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>
- * {@link android.support.v4.app.ListFragment} for consistent behavior across all devices
+ * {@link androidx.fragment.app.ListFragment} for consistent behavior across all devices
* and access to <a href="{@docRoot}topic/libraries/architecture/lifecycle.html">Lifecycle</a>.
*/
@Deprecated
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 38e344e..77c7c6f 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -1734,7 +1734,11 @@
return;
}
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg");
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+ "broadcastReceiveReg: " + intent.getAction());
+ }
+
try {
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java
index 86d0fd6..e2de716 100644
--- a/core/java/android/app/LoaderManager.java
+++ b/core/java/android/app/LoaderManager.java
@@ -37,7 +37,7 @@
* While the LoaderManager API was introduced in
* {@link android.os.Build.VERSION_CODES#HONEYCOMB}, a version of the API
* at is also available for use on older platforms through
- * {@link android.support.v4.app.FragmentActivity}. See the blog post
+ * {@link androidx.fragment.app.FragmentActivity}. See the blog post
* <a href="http://android-developers.blogspot.com/2011/03/fragments-for-all.html">
* Fragments For All</a> for more details.
*
@@ -56,7 +56,7 @@
* </div>
*
* @deprecated Use the <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>
- * {@link android.support.v4.app.LoaderManager}
+ * {@link androidx.loader.app.LoaderManager}
*/
@Deprecated
public abstract class LoaderManager {
@@ -64,7 +64,7 @@
* Callback interface for a client to interact with the manager.
*
* @deprecated Use the <a href="{@docRoot}tools/extras/support-library.html">
- * Support Library</a> {@link android.support.v4.app.LoaderManager.LoaderCallbacks}
+ * Support Library</a> {@link androidx.loader.app.LoaderManager.LoaderCallbacks}
*/
@Deprecated
public interface LoaderCallbacks<D> {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 6a14772..9dd206e 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1330,6 +1330,32 @@
public static final String EXTRA_MEDIA_SESSION = "android.mediaSession";
/**
+ * {@link #extras} key: A {@code CharSequence} name of a remote device used for a media session
+ * associated with a {@link Notification.MediaStyle} notification. This will show in the media
+ * controls output switcher instead of the local device name.
+ * @hide
+ */
+ @TestApi
+ public static final String EXTRA_MEDIA_REMOTE_DEVICE = "android.mediaRemoteDevice";
+
+ /**
+ * {@link #extras} key: A {@code int} resource ID for an icon that should show in the output
+ * switcher of the media controls for a {@link Notification.MediaStyle} notification.
+ * @hide
+ */
+ @TestApi
+ public static final String EXTRA_MEDIA_REMOTE_ICON = "android.mediaRemoteIcon";
+
+ /**
+ * {@link #extras} key: A {@code PendingIntent} that will replace the default action for the
+ * media controls output switcher chip, associated with a {@link Notification.MediaStyle}
+ * notification. This should launch an activity.
+ * @hide
+ */
+ @TestApi
+ public static final String EXTRA_MEDIA_REMOTE_INTENT = "android.mediaRemoteIntent";
+
+ /**
* {@link #extras} key: the indices of actions to be shown in the compact view,
* as supplied to (e.g.) {@link MediaStyle#setShowActionsInCompactView(int...)}.
*/
@@ -3719,7 +3745,7 @@
* Provides a convenient way to set the various fields of a {@link Notification} and generate
* content views using the platform's notification layout template. If your app supports
* versions of Android as old as API level 4, you can instead use
- * {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder},
+ * {@link androidx.core.app.NotificationCompat.Builder NotificationCompat.Builder},
* available in the <a href="{@docRoot}tools/extras/support-library.html">Android Support
* library</a>.
*
@@ -8943,6 +8969,9 @@
private int[] mActionsToShowInCompact = null;
private MediaSession.Token mToken;
+ private CharSequence mDeviceName;
+ private int mDeviceIcon;
+ private PendingIntent mDeviceIntent;
public MediaStyle() {
}
@@ -8976,6 +9005,32 @@
}
/**
+ * For media notifications associated with playback on a remote device, provide device
+ * information that will replace the default values for the output switcher chip on the
+ * media control, as well as an intent to use when the output switcher chip is tapped,
+ * on devices where this is supported.
+ *
+ * @param deviceName The name of the remote device to display
+ * @param iconResource Icon resource representing the device
+ * @param chipIntent PendingIntent to send when the output switcher is tapped. May be
+ * {@code null}, in which case the output switcher will be disabled.
+ * This intent should open an Activity or it will be ignored.
+ * @return MediaStyle
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL)
+ @NonNull
+ public MediaStyle setRemotePlaybackInfo(@NonNull CharSequence deviceName,
+ @DrawableRes int iconResource, @Nullable PendingIntent chipIntent) {
+ mDeviceName = deviceName;
+ mDeviceIcon = iconResource;
+ mDeviceIntent = chipIntent;
+ return this;
+ }
+
+ /**
* @hide
*/
@Override
@@ -9023,6 +9078,15 @@
if (mActionsToShowInCompact != null) {
extras.putIntArray(EXTRA_COMPACT_ACTIONS, mActionsToShowInCompact);
}
+ if (mDeviceName != null) {
+ extras.putCharSequence(EXTRA_MEDIA_REMOTE_DEVICE, mDeviceName);
+ }
+ if (mDeviceIcon > 0) {
+ extras.putInt(EXTRA_MEDIA_REMOTE_ICON, mDeviceIcon);
+ }
+ if (mDeviceIntent != null) {
+ extras.putParcelable(EXTRA_MEDIA_REMOTE_INTENT, mDeviceIntent);
+ }
}
/**
@@ -9038,6 +9102,15 @@
if (extras.containsKey(EXTRA_COMPACT_ACTIONS)) {
mActionsToShowInCompact = extras.getIntArray(EXTRA_COMPACT_ACTIONS);
}
+ if (extras.containsKey(EXTRA_MEDIA_REMOTE_DEVICE)) {
+ mDeviceName = extras.getCharSequence(EXTRA_MEDIA_REMOTE_DEVICE);
+ }
+ if (extras.containsKey(EXTRA_MEDIA_REMOTE_ICON)) {
+ mDeviceIcon = extras.getInt(EXTRA_MEDIA_REMOTE_ICON);
+ }
+ if (extras.containsKey(EXTRA_MEDIA_REMOTE_INTENT)) {
+ mDeviceIntent = extras.getParcelable(EXTRA_MEDIA_REMOTE_INTENT);
+ }
}
/**
diff --git a/core/java/android/app/NotificationHistory.java b/core/java/android/app/NotificationHistory.java
index b40fbee..eadb7e3 100644
--- a/core/java/android/app/NotificationHistory.java
+++ b/core/java/android/app/NotificationHistory.java
@@ -610,6 +610,7 @@
// Data can be too large for a transact. Write the data as a Blob, which will be written to
// ashmem if too large.
dest.writeBlob(data.marshall());
+ data.recycle();
}
public static final @NonNull Creator<NotificationHistory> CREATOR
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 4aa2d2e..392f52a 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -2573,11 +2573,18 @@
* method will return false regardless of input.
* </p>
* <p>
- * The provided URI must meet the requirements for a URI associated with a
- * {@link Person}: it may be the {@code String} representation of a
- * {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}, or a
- * <code>mailto:</code> or <code>tel:</code> schema URI matching an entry in the
- * Contacts database. See also {@link Person.Builder#setUri} and
+ * The provided URI should be a <code>tel:</code> or <code>mailto:</code> schema URI indicating
+ * the source of the call. For an accurate answer regarding whether the caller matches the
+ * user's permitted contacts, the path part of the URI must match an entry the Contacts database
+ * in the appropriate column.
+ * </p>
+ * <p>
+ * Passing in a {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI} is also
+ * permissible, but should only be used for priority contact interruptions and may not provide
+ * accurate results in the case of repeat callers.
+ * </p>
+ * <p>
+ * See also {@link Person.Builder#setUri} and
* {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}
* for more information.
* </p>
diff --git a/core/java/android/app/PictureInPictureParams.java b/core/java/android/app/PictureInPictureParams.java
index 358ce6a..18343fd 100644
--- a/core/java/android/app/PictureInPictureParams.java
+++ b/core/java/android/app/PictureInPictureParams.java
@@ -18,7 +18,9 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
import android.annotation.TestApi;
+import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
@@ -43,6 +45,9 @@
private Rational mAspectRatio;
@Nullable
+ private Rational mExpandedAspectRatio;
+
+ @Nullable
private List<RemoteAction> mUserActions;
@Nullable
@@ -67,6 +72,24 @@
}
/**
+ * Sets the aspect ratio for the expanded picture-in-picture mode. The aspect ratio is
+ * defined as the desired width / height. <br/>
+ * The aspect ratio cannot be changed from horizontal to vertical or vertical to horizontal
+ * while the PIP is shown. Any such changes will be ignored. <br/>
+ *
+ * Setting the expanded ratio shows the activity's support for expanded mode.
+ *
+ * @param expandedAspectRatio must not be between 2.39:1 and 1:2.39 (inclusive). If {@code
+ * null}, expanded picture-in-picture mode is not supported.
+ * @return this builder instance.
+ */
+ @RequiresFeature(PackageManager.FEATURE_EXPANDED_PICTURE_IN_PICTURE)
+ public @NonNull Builder setExpandedAspectRatio(@Nullable Rational expandedAspectRatio) {
+ mExpandedAspectRatio = expandedAspectRatio;
+ return this;
+ }
+
+ /**
* Sets the user actions. If there are more than
* {@link Activity#getMaxNumPictureInPictureActions()} actions, then the input list
* will be truncated to that number.
@@ -152,7 +175,8 @@
* @see Activity#setPictureInPictureParams(PictureInPictureParams)
*/
public PictureInPictureParams build() {
- PictureInPictureParams params = new PictureInPictureParams(mAspectRatio, mUserActions,
+ PictureInPictureParams params = new PictureInPictureParams(mAspectRatio,
+ mExpandedAspectRatio, mUserActions,
mSourceRectHint, mAutoEnterEnabled, mSeamlessResizeEnabled);
return params;
}
@@ -165,6 +189,12 @@
private Rational mAspectRatio;
/**
+ * The expected aspect ratio of the vertically expanded picture-in-picture window.
+ */
+ @Nullable
+ private Rational mExpandedAspectRatio;
+
+ /**
* The set of actions that are associated with this activity when in picture-in-picture.
*/
@Nullable
@@ -197,9 +227,8 @@
/** {@hide} */
PictureInPictureParams(Parcel in) {
- if (in.readInt() != 0) {
- mAspectRatio = new Rational(in.readInt(), in.readInt());
- }
+ mAspectRatio = readRationalFromParcel(in);
+ mExpandedAspectRatio = readRationalFromParcel(in);
if (in.readInt() != 0) {
mUserActions = new ArrayList<>();
in.readTypedList(mUserActions, RemoteAction.CREATOR);
@@ -216,9 +245,11 @@
}
/** {@hide} */
- PictureInPictureParams(Rational aspectRatio, List<RemoteAction> actions,
- Rect sourceRectHint, Boolean autoEnterEnabled, Boolean seamlessResizeEnabled) {
+ PictureInPictureParams(Rational aspectRatio, Rational expandedAspectRatio,
+ List<RemoteAction> actions, Rect sourceRectHint, Boolean autoEnterEnabled,
+ Boolean seamlessResizeEnabled) {
mAspectRatio = aspectRatio;
+ mExpandedAspectRatio = expandedAspectRatio;
mUserActions = actions;
mSourceRectHint = sourceRectHint;
mAutoEnterEnabled = autoEnterEnabled;
@@ -230,7 +261,7 @@
* @hide
*/
public PictureInPictureParams(PictureInPictureParams other) {
- this(other.mAspectRatio, other.mUserActions,
+ this(other.mAspectRatio, other.mExpandedAspectRatio, other.mUserActions,
other.hasSourceBoundsHint() ? new Rect(other.getSourceRectHint()) : null,
other.mAutoEnterEnabled, other.mSeamlessResizeEnabled);
}
@@ -243,6 +274,10 @@
if (otherArgs.hasSetAspectRatio()) {
mAspectRatio = otherArgs.mAspectRatio;
}
+
+ // Copy either way because null can be used to explicitly unset the value
+ mExpandedAspectRatio = otherArgs.mExpandedAspectRatio;
+
if (otherArgs.hasSetActions()) {
mUserActions = otherArgs.mUserActions;
}
@@ -283,6 +318,26 @@
}
/**
+ * @return the expanded aspect ratio. If none is set, return 0.
+ * @hide
+ */
+ @TestApi
+ public float getExpandedAspectRatio() {
+ if (mExpandedAspectRatio != null) {
+ return mExpandedAspectRatio.floatValue();
+ }
+ return 0f;
+ }
+
+ /**
+ * @return whether the expanded aspect ratio is set
+ * @hide
+ */
+ public boolean hasSetExpandedAspectRatio() {
+ return mExpandedAspectRatio != null;
+ }
+
+ /**
* @return the set of user actions.
* @hide
*/
@@ -349,7 +404,8 @@
*/
public boolean empty() {
return !hasSourceBoundsHint() && !hasSetActions() && !hasSetAspectRatio()
- && mAutoEnterEnabled != null && mSeamlessResizeEnabled != null;
+ && !hasSetExpandedAspectRatio() && mAutoEnterEnabled != null
+ && mSeamlessResizeEnabled != null;
}
@Override
@@ -360,13 +416,14 @@
return Objects.equals(mAutoEnterEnabled, that.mAutoEnterEnabled)
&& Objects.equals(mSeamlessResizeEnabled, that.mSeamlessResizeEnabled)
&& Objects.equals(mAspectRatio, that.mAspectRatio)
+ && Objects.equals(mExpandedAspectRatio, that.mExpandedAspectRatio)
&& Objects.equals(mUserActions, that.mUserActions)
&& Objects.equals(mSourceRectHint, that.mSourceRectHint);
}
@Override
public int hashCode() {
- return Objects.hash(mAspectRatio, mUserActions, mSourceRectHint,
+ return Objects.hash(mAspectRatio, mExpandedAspectRatio, mUserActions, mSourceRectHint,
mAutoEnterEnabled, mSeamlessResizeEnabled);
}
@@ -377,13 +434,8 @@
@Override
public void writeToParcel(Parcel out, int flags) {
- if (mAspectRatio != null) {
- out.writeInt(1);
- out.writeInt(mAspectRatio.getNumerator());
- out.writeInt(mAspectRatio.getDenominator());
- } else {
- out.writeInt(0);
- }
+ writeRationalToParcel(mAspectRatio, out);
+ writeRationalToParcel(mExpandedAspectRatio, out);
if (mUserActions != null) {
out.writeInt(1);
out.writeTypedList(mUserActions, 0);
@@ -410,10 +462,28 @@
}
}
+ private void writeRationalToParcel(Rational rational, Parcel out) {
+ if (rational != null) {
+ out.writeInt(1);
+ out.writeInt(rational.getNumerator());
+ out.writeInt(rational.getDenominator());
+ } else {
+ out.writeInt(0);
+ }
+ }
+
+ private Rational readRationalFromParcel(Parcel in) {
+ if (in.readInt() != 0) {
+ return new Rational(in.readInt(), in.readInt());
+ }
+ return null;
+ }
+
@Override
public String toString() {
return "PictureInPictureParams("
+ " aspectRatio=" + getAspectRatioRational()
+ + " expandedAspectRatio=" + mExpandedAspectRatio
+ " sourceRectHint=" + getSourceRectHint()
+ " hasSetActions=" + hasSetActions()
+ " isAutoPipEnabled=" + isAutoEnterEnabled()
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index da1ba52..5f00342 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -920,7 +920,7 @@
public void setNavBarModeOverride(@NavBarModeOverride int navBarModeOverride) {
if (navBarModeOverride != NAV_BAR_MODE_OVERRIDE_NONE
&& navBarModeOverride != NAV_BAR_MODE_OVERRIDE_KIDS) {
- throw new UnsupportedOperationException(
+ throw new IllegalArgumentException(
"Supplied navBarModeOverride not supported: " + navBarModeOverride);
}
@@ -1012,6 +1012,8 @@
*
* @param displayState the new state for media tap-to-transfer.
* @param routeInfo the media route information for the media being transferred.
+ * @param appIcon the icon of the app playing the media.
+ * @param appName the name of the app playing the media.
*
* @hide
*/
@@ -1019,11 +1021,13 @@
@RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
public void updateMediaTapToTransferReceiverDisplay(
@MediaTransferReceiverState int displayState,
- @NonNull MediaRoute2Info routeInfo) {
+ @NonNull MediaRoute2Info routeInfo,
+ @Nullable Icon appIcon,
+ @Nullable CharSequence appName) {
Objects.requireNonNull(routeInfo);
IStatusBarService svc = getService();
try {
- svc.updateMediaTapToTransferReceiverDisplay(displayState, routeInfo);
+ svc.updateMediaTapToTransferReceiverDisplay(displayState, routeInfo, appIcon, appName);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index f5f2fe0..eeb4705 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -25,7 +25,7 @@
import android.app.admin.DevicePolicyManager;
import android.app.admin.IDevicePolicyManager;
import android.app.ambientcontext.AmbientContextManager;
-import android.app.ambientcontext.IAmbientContextEventObserver;
+import android.app.ambientcontext.IAmbientContextManager;
import android.app.appsearch.AppSearchManagerFrameworkInitializer;
import android.app.blob.BlobStoreManagerFrameworkInitializer;
import android.app.cloudsearch.CloudSearchManager;
@@ -1542,8 +1542,8 @@
throws ServiceNotFoundException {
IBinder iBinder = ServiceManager.getServiceOrThrow(
Context.AMBIENT_CONTEXT_SERVICE);
- IAmbientContextEventObserver manager =
- IAmbientContextEventObserver.Stub.asInterface(iBinder);
+ IAmbientContextManager manager =
+ IAmbientContextManager.Stub.asInterface(iBinder);
return new AmbientContextManager(ctx.getOuterContext(), manager);
}});
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index b41b5f0..5e521b0 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -63,9 +63,14 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityWindowInfo;
import android.view.accessibility.IAccessibilityInteractionConnection;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputBinding;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputMethodSession;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.internal.view.IInputSessionWithIdCallback;
import libcore.io.IoUtils;
@@ -728,7 +733,8 @@
}
// Calling out without a lock held.
return AccessibilityInteractionClient.getInstance()
- .getRootInActiveWindow(connectionId);
+ .getRootInActiveWindow(connectionId,
+ AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS_HYBRID);
}
/**
@@ -1566,6 +1572,29 @@
}
@Override
+ public void createImeSession(IInputSessionWithIdCallback callback) {
+ /* do nothing */
+ }
+
+ @Override
+ public void setImeSessionEnabled(InputMethodSession session, boolean enabled) {
+ }
+
+ @Override
+ public void bindInput(InputBinding binding) {
+ }
+
+ @Override
+ public void unbindInput() {
+ }
+
+ @Override
+ public void startInput(@Nullable InputConnection inputConnection,
+ @NonNull EditorInfo editorInfo, boolean restarting,
+ @NonNull IBinder startInputToken) {
+ }
+
+ @Override
public boolean onGesture(AccessibilityGestureEvent gestureEvent) {
/* do nothing */
return false;
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index 73a9e5a..cfaffb1 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -517,7 +517,7 @@
* (and potentially an Activity lifecycle event) being applied to all running apps.
* Developers interested in an app-local implementation of night mode should consider using
* {@link #setApplicationNightMode(int)} to set and persist the -night qualifier locally or
- * {@link android.support.v7.app.AppCompatDelegate#setDefaultNightMode(int)} for the
+ * {@link androidx.appcompat.app.AppCompatDelegate#setDefaultNightMode(int)} for the
* backward compatible implementation.
*
* @param mode the night mode to set
@@ -595,7 +595,7 @@
* user clears the data for the application, or this application is uninstalled.
* <p>
* Developers interested in a non-persistent app-local implementation of night mode should
- * consider using {@link android.support.v7.app.AppCompatDelegate#setDefaultNightMode(int)}
+ * consider using {@link androidx.appcompat.app.AppCompatDelegate#setDefaultNightMode(int)}
* to manage the -night qualifier locally.
*
* @param mode the night mode to set
diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java
index 433b275..7014d69 100644
--- a/core/java/android/app/VoiceInteractor.java
+++ b/core/java/android/app/VoiceInteractor.java
@@ -1168,6 +1168,23 @@
}
}
+ /**
+ * @return the package name of the service providing the VoiceInteractionService.
+ */
+ @NonNull
+ public String getPackageName() {
+ String packageName = null;
+ if (mActivity != null && mInteractor != null) {
+ try {
+ packageName = ActivityTaskManager.getService()
+ .getVoiceInteractorPackageName(mInteractor.asBinder());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return packageName == null ? "" : packageName;
+ }
+
void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
String innerPrefix = prefix + " ";
if (mActiveRequests.size() > 0) {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 71d4ab4..9a7093e 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -720,6 +720,125 @@
"android.app.extra.PROVISIONING_ALLOW_OFFLINE";
/**
+ * A String extra holding a url that specifies the download location of the device manager
+ * role holder package.
+ *
+ * <p>This is only meant to be used in cases when a specific variant of the role holder package
+ * is needed (such as a debug variant). If not provided, the default variant of the device
+ * manager role holder package is downloaded.
+ *
+ * <p>Use in an intent with action {@link #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE}
+ * or in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+ * provisioning via an NFC bump.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_PROVISIONING_ROLE_HOLDER_PACKAGE_DOWNLOAD_LOCATION =
+ "android.app.extra.PROVISIONING_ROLE_HOLDER_PACKAGE_DOWNLOAD_LOCATION";
+
+ /**
+ * A String extra holding the URL-safe base64 encoded SHA-256 checksum of any signature of the
+ * android package archive at the download location specified in {@link
+ * #EXTRA_PROVISIONING_ROLE_HOLDER_PACKAGE_DOWNLOAD_LOCATION}.
+ *
+ * <p>The signatures of an android package archive can be obtained using
+ * {@link android.content.pm.PackageManager#getPackageArchiveInfo} with flag
+ * {@link android.content.pm.PackageManager#GET_SIGNING_CERTIFICATES}.
+ *
+ * <p>If {@link #EXTRA_PROVISIONING_ROLE_HOLDER_PACKAGE_DOWNLOAD_LOCATION} is provided, it must
+ * be accompanied by this extra. The provided checksum must match the checksum of any signature
+ * of the file at the download location. If the checksum does not match an error will be shown
+ * to the user and the user will be asked to factory reset the device.
+ *
+ * <p>Use in an intent with action {@link #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE}
+ * or in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+ * provisioning via an NFC bump.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_PROVISIONING_ROLE_HOLDER_SIGNATURE_CHECKSUM =
+ "android.app.extra.PROVISIONING_ROLE_HOLDER_SIGNATURE_CHECKSUM";
+
+ /**
+ * A String extra holding a http cookie header which should be used in the http request to the
+ * url specified in {@link #EXTRA_PROVISIONING_ROLE_HOLDER_PACKAGE_DOWNLOAD_LOCATION}.
+ *
+ * <p>Use in an intent with action {@link #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE}
+ * or in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+ * provisioning via an NFC bump.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_PROVISIONING_ROLE_HOLDER_PACKAGE_DOWNLOAD_COOKIE_HEADER =
+ "android.app.extra.PROVISIONING_ROLE_HOLDER_PACKAGE_DOWNLOAD_COOKIE_HEADER";
+
+ /**
+ * An extra of type {@link android.os.PersistableBundle} that allows the provisioning initiator
+ * to pass data to the device manager role holder.
+ *
+ * <p>The device manager role holder will receive this extra via the {@link
+ * #ACTION_ROLE_HOLDER_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE} intent.
+ *
+ * <p>The contents of this extra are up to the contract between the provisioning initiator
+ * and the device manager role holder.
+ *
+ * <p>Use in an intent with action {@link #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE}
+ * or in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+ * provisioning via an NFC bump.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_PROVISIONING_ROLE_HOLDER_EXTRAS_BUNDLE =
+ "android.app.extra.PROVISIONING_ROLE_HOLDER_EXTRAS_BUNDLE";
+
+ /**
+ * A String extra containing the package name of the provisioning initiator.
+ *
+ * <p>Use in an intent with action {@link
+ * #ACTION_ROLE_HOLDER_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE}.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_ROLE_HOLDER_PROVISIONING_INITIATOR_PACKAGE =
+ "android.app.extra.ROLE_HOLDER_PROVISIONING_INITIATOR_PACKAGE";
+
+ /**
+ * An {@link Intent} result extra specifying the {@link Intent} to be launched after
+ * provisioning is finalized.
+ *
+ * <p>If {@link #EXTRA_PROVISIONING_SHOULD_LAUNCH_RESULT_INTENT} is set to {@code false},
+ * this result will be supplied as part of the result {@link Intent} for provisioning actions
+ * such as {@link #ACTION_PROVISION_MANAGED_PROFILE}. This result will also be supplied as
+ * part of the result {@link Intent} for the device manager role holder provisioning actions.
+ */
+ public static final String EXTRA_RESULT_LAUNCH_INTENT =
+ "android.app.extra.RESULT_LAUNCH_INTENT";
+
+ /**
+ * A boolean extra that determines whether the provisioning flow should launch the resulting
+ * launch intent, if one is supplied by the device manager role holder via {@link
+ * #EXTRA_RESULT_LAUNCH_INTENT}. Default value is {@code false}.
+ *
+ * <p>If {@code true}, the resulting intent will be launched by the provisioning flow, if one
+ * is supplied by the device manager role holder.
+ *
+ * <p>If {@code false}, the resulting intent will be returned as {@link
+ * #EXTRA_RESULT_LAUNCH_INTENT} to the provisioning initiator, if one is supplied by the device
+ * manager role holder. It will be the responsibility of the provisioning initiator to launch
+ * this {@link Intent} after provisioning completes.
+ *
+ * <p>This extra is respected when provided via the provisioning intent actions such as {@link
+ * #ACTION_PROVISION_MANAGED_PROFILE}.
+ */
+ public static final String EXTRA_PROVISIONING_SHOULD_LAUNCH_RESULT_INTENT =
+ "android.app.extra.PROVISIONING_SHOULD_LAUNCH_RESULT_INTENT";
+
+ /**
* Action: Bugreport sharing with device owner has been accepted by the user.
*
* @hide
@@ -3584,11 +3703,13 @@
*/
@RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
android.Manifest.permission.INTERACT_ACROSS_USERS})
+ @UserHandleAware
+ @TestApi
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public void acknowledgeNewUserDisclaimer() {
if (mService != null) {
try {
- mService.acknowledgeNewUserDisclaimer();
+ mService.acknowledgeNewUserDisclaimer(mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3596,17 +3717,18 @@
}
/**
- * Checks whether the new managed user disclaimer was viewed by the current user.
+ * Checks whether the new managed user disclaimer was viewed by the user.
*
* @hide
*/
@RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
android.Manifest.permission.INTERACT_ACROSS_USERS})
@TestApi
+ @UserHandleAware
public boolean isNewUserDisclaimerAcknowledged() {
if (mService != null) {
try {
- return mService.isNewUserDisclaimerAcknowledged();
+ return mService.isNewUserDisclaimerAcknowledged(mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -8185,10 +8307,10 @@
* @hide
*/
@RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
- public void reportPasswordChanged(@UserIdInt int userId) {
+ public void reportPasswordChanged(PasswordMetrics metrics, @UserIdInt int userId) {
if (mService != null) {
try {
- mService.reportPasswordChanged(userId);
+ mService.reportPasswordChanged(metrics, userId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -9592,9 +9714,9 @@
* service. When zero or more packages have been added, accessibility services that are not in
* the list and not part of the system can not be enabled by the user.
* <p>
- * Calling with a null value for the list disables the restriction so that all services can be
- * used, calling with an empty list only allows the built-in system services. Any non-system
- * accessibility service that's currently enabled must be included in the list.
+ * Calling with a {@code null} value for the list disables the restriction so that all services
+ * can be used, calling with an empty list only allows the built-in system services. Any
+ * non-system accessibility service that's currently enabled must be included in the list.
* <p>
* System accessibility services are always available to the user and this method can't
* disable them.
@@ -9620,8 +9742,8 @@
/**
* Returns the list of permitted accessibility services set by this device or profile owner.
* <p>
- * An empty list means no accessibility services except system services are allowed. Null means
- * all accessibility services are allowed.
+ * An empty list means no accessibility services except system services are allowed.
+ * {@code null} means all accessibility services are allowed.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @return List of accessiblity service package names.
@@ -9666,7 +9788,7 @@
* Returns the list of accessibility services permitted by the device or profiles
* owners of this user.
*
- * <p>Null means all accessibility services are allowed, if a non-null list is returned
+ * <p>{@code null} means all accessibility services are allowed, if a non-null list is returned
* it will contain the intersection of the permitted lists for any device or profile
* owners that apply to this user. It will also include any system accessibility services.
*
@@ -9812,6 +9934,8 @@
*
* @return List of input method package names.
* @hide
+ *
+ * @see #setPermittedAccessibilityServices(ComponentName, List)
*/
@SystemApi
@RequiresPermission(anyOf = {
@@ -9832,29 +9956,30 @@
/**
* Returns the list of input methods permitted.
*
- * <p>When this method returns empty list means all input methods are allowed, if a non-empty
- * list is returned it will contain the intersection of the permitted lists for any device or
- * profile owners that apply to this user. It will also include any system input methods.
+ * <p>{@code null} means all input methods are allowed, if a non-null list is returned
+ * it will contain the intersection of the permitted lists for any device or profile
+ * owners that apply to this user. It will also include any system input methods.
*
* @return List of input method package names.
* @hide
+ *
+ * @see #setPermittedAccessibilityServices(ComponentName, List)
*/
@UserHandleAware
@RequiresPermission(allOf = {
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
android.Manifest.permission.MANAGE_USERS
}, conditional = true)
- public @NonNull List<String> getPermittedInputMethods() {
+ public @Nullable List<String> getPermittedInputMethods() {
throwIfParentInstance("getPermittedInputMethods");
- List<String> result = null;
if (mService != null) {
try {
- result = mService.getPermittedInputMethodsAsUser(myUserId());
+ return mService.getPermittedInputMethodsAsUser(myUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
- return result != null ? result : Collections.emptyList();
+ return null;
}
/**
@@ -10209,6 +10334,7 @@
throw re.rethrowFromSystemServer();
}
}
+
/**
* Gets the user a {@link #logoutUser(ComponentName)} call would switch to,
* or {@code null} if the current user is not in a session (i.e., if it was not
@@ -15516,4 +15642,40 @@
}
}
}
+
+ /**
+ * Returns the package name of the device manager role holder.
+ *
+ * <p>If the device manager role holder is not configured for this device, returns {@code null}.
+ */
+ @Nullable
+ public String getDeviceManagerRoleHolderPackageName() {
+ String deviceManagerConfig =
+ mContext.getString(com.android.internal.R.string.config_deviceManager);
+ return extractPackageNameFromDeviceManagerConfig(deviceManagerConfig);
+ }
+
+ /**
+ * Retrieves the package name for a given {@code deviceManagerConfig}.
+ *
+ * <p>Valid configs look like:
+ * <ul>
+ * <li>{@code com.package.name}</li>
+ * <li>{@code com.package.name:<SHA256 checksum>}</li>
+ * </ul>
+ *
+ * <p>If the supplied {@code deviceManagerConfig} is {@code null} or empty, returns
+ * {@code null}.
+ */
+ @Nullable
+ private String extractPackageNameFromDeviceManagerConfig(
+ @Nullable String deviceManagerConfig) {
+ if (TextUtils.isEmpty(deviceManagerConfig)) {
+ return null;
+ }
+ if (deviceManagerConfig.contains(":")) {
+ return deviceManagerConfig.split(":")[0];
+ }
+ return deviceManagerConfig;
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 0e1caca..0b9d51f 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -158,7 +158,7 @@
void forceRemoveActiveAdmin(in ComponentName policyReceiver, int userHandle);
boolean hasGrantedPolicy(in ComponentName policyReceiver, int usesPolicy, int userHandle);
- void reportPasswordChanged(int userId);
+ void reportPasswordChanged(in PasswordMetrics metrics, int userId);
void reportFailedPasswordAttempt(int userHandle);
void reportSuccessfulPasswordAttempt(int userHandle);
void reportFailedBiometricAttempt(int userHandle);
@@ -271,8 +271,8 @@
int logoutUserInternal(); // AIDL doesn't allow overloading name (logoutUser())
int getLogoutUserId();
List<UserHandle> getSecondaryUsers(in ComponentName who);
- void acknowledgeNewUserDisclaimer();
- boolean isNewUserDisclaimerAcknowledged();
+ void acknowledgeNewUserDisclaimer(int userId);
+ boolean isNewUserDisclaimerAcknowledged(int userId);
void enableSystemApp(in ComponentName admin, in String callerPackage, in String packageName);
int enableSystemAppWithIntent(in ComponentName admin, in String callerPackage, in Intent intent);
diff --git a/core/java/android/app/admin/SecurityLog.java b/core/java/android/app/admin/SecurityLog.java
index 8c59982..b170aa2 100644
--- a/core/java/android/app/admin/SecurityLog.java
+++ b/core/java/android/app/admin/SecurityLog.java
@@ -16,8 +16,12 @@
package android.app.admin;
+import android.Manifest;
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;
import android.content.ComponentName;
@@ -86,7 +90,12 @@
TAG_KEY_INTEGRITY_VIOLATION,
TAG_CERT_VALIDATION_FAILURE,
TAG_CAMERA_POLICY_SET,
- TAG_PASSWORD_COMPLEXITY_REQUIRED
+ TAG_PASSWORD_COMPLEXITY_REQUIRED,
+ TAG_PASSWORD_CHANGED,
+ TAG_WIFI_CONNECTION,
+ TAG_WIFI_DISCONNECTION,
+ TAG_BLUETOOTH_CONNECTION,
+ TAG_BLUETOOTH_DISCONNECTION,
})
public @interface SecurityLogTag {}
@@ -495,6 +504,65 @@
SecurityLogTags.SECURITY_PASSWORD_COMPLEXITY_REQUIRED;
/**
+ * Indicates that a user has just changed their lockscreen password.
+ * The log entry contains the following information about the
+ * event, encapsulated in an {@link Object} array and accessible via
+ * {@link SecurityEvent#getData()}:
+ * <li> [0] complexity for the new password ({@code Integer})
+ * <li> [1] target user ID ({@code Integer})
+ *
+ * <p>Password complexity levels are defined as in
+ * {@link DevicePolicyManager#getPasswordComplexity()}
+ */
+ public static final int TAG_PASSWORD_CHANGED = SecurityLogTags.SECURITY_PASSWORD_CHANGED;
+
+ /**
+ * Indicates that the device attempts to connect to a WiFi network.
+ * The log entry contains the following information about the
+ * event, encapsulated in an {@link Object} array and accessible via
+ * {@link SecurityEvent#getData()}:
+ * <li> [0] The SSID of the network ({@code String})
+ * <li> [1] The BSSID of the network ({@code String})
+ * <li> [2] Whether the connection is successful ({@code Integer}, 1 if successful, 0 otherwise)
+ * <li> [3] Optional human-readable failure reason, empty string if none ({@code String})
+ */
+ public static final int TAG_WIFI_CONNECTION = SecurityLogTags.SECURITY_WIFI_CONNECTION;
+
+ /**
+ * Indicates that the device disconnects from a connected WiFi network.
+ * The log entry contains the following information about the
+ * event, encapsulated in an {@link Object} array and accessible via
+ * {@link SecurityEvent#getData()}:
+ * <li> [0] The SSID of the connected network ({@code String})
+ * <li> [1] The BSSID of the connected network ({@code String})
+ * <li> [2] Optional human-readable disconnection reason, empty string if none ({@code String})
+ */
+ public static final int TAG_WIFI_DISCONNECTION = SecurityLogTags.SECURITY_WIFI_DISCONNECTION;
+
+ /**
+ * Indicates that the device attempts to connect to a Bluetooth device.
+ * The log entry contains the following information about the
+ * event, encapsulated in an {@link Object} array and accessible via
+ * {@link SecurityEvent#getData()}:
+ * <li> [0] The MAC address of the Bluetooth device ({@code String})
+ * <li> [1] Whether the connection is successful ({@code Integer}, 1 if successful, 0 otherwise)
+ * <li> [2] Optional human-readable failure reason, empty string if none ({@code String})
+ */
+ public static final int TAG_BLUETOOTH_CONNECTION =
+ SecurityLogTags.SECURITY_BLUETOOTH_CONNECTION;
+
+ /**
+ * Indicates that the device disconnects from a connected Bluetooth device.
+ * The log entry contains the following information about the
+ * event, encapsulated in an {@link Object} array and accessible via
+ * {@link SecurityEvent#getData()}:
+ * <li> [0] The MAC address of the connected Bluetooth device ({@code String})
+ * <li> [1] Optional human-readable disconnection reason, empty string if none ({@code String})
+ */
+ public static final int TAG_BLUETOOTH_DISCONNECTION =
+ SecurityLogTags.SECURITY_BLUETOOTH_DISCONNECTION;
+
+ /**
* Event severity level indicating that the event corresponds to normal workflow.
*/
public static final int LEVEL_INFO = 1;
@@ -635,6 +703,7 @@
case TAG_USER_RESTRICTION_REMOVED:
case TAG_CAMERA_POLICY_SET:
case TAG_PASSWORD_COMPLEXITY_REQUIRED:
+ case TAG_PASSWORD_CHANGED:
return LEVEL_INFO;
case TAG_CERT_AUTHORITY_REMOVED:
case TAG_CRYPTO_SELF_TEST_COMPLETED:
@@ -725,6 +794,13 @@
return null;
}
break;
+ case SecurityLog.TAG_PASSWORD_CHANGED:
+ try {
+ userId = getIntegerData(1);
+ } catch (Exception e) {
+ return null;
+ }
+ break;
default:
userId = UserHandle.USER_NULL;
}
@@ -840,15 +916,21 @@
throws IOException;
/**
- * Write a log entry to the underlying storage, with a string payload.
- * @hide
- */
- public static native int writeEvent(int tag, String str);
-
- /**
* Write a log entry to the underlying storage, with several payloads.
* Supported types of payload are: integer, long, float, string plus array of supported types.
+ *
+ * <p>Security log is part of Android's device management capability that tracks
+ * security-sensitive events for auditing purposes.
+ *
+ * @param tag the tag ID of the security event
+ * @param payloads a list of payload values. Each tag dictates the expected payload types
+ * and their meanings
+ * @see DevicePolicyManager#setSecurityLoggingEnabled(ComponentName, boolean)
+ *
* @hide
*/
- public static native int writeEvent(int tag, Object... payloads);
+ // TODO(b/218658622): enforce WRITE_SECURITY_LOG in logd.
+ @SystemApi
+ @RequiresPermission(Manifest.permission.WRITE_SECURITY_LOG)
+ public static native int writeEvent(@SecurityLogTag int tag, @NonNull Object... payloads);
}
diff --git a/core/java/android/app/admin/SecurityLogTags.logtags b/core/java/android/app/admin/SecurityLogTags.logtags
index db5245c..5f41109 100644
--- a/core/java/android/app/admin/SecurityLogTags.logtags
+++ b/core/java/android/app/admin/SecurityLogTags.logtags
@@ -40,3 +40,8 @@
210033 security_cert_validation_failure (reason|3)
210034 security_camera_policy_set (package|3),(admin_user|1),(target_user|1),(disabled|1)
210035 security_password_complexity_required (package|3),(admin_user|1),(target_user|1),(complexity|1)
+210036 security_password_changed (password_complexity|1),(target_user|1)
+210037 security_wifi_connection (ssid|3),(bssid|3),(success|1),(reason|3)
+210038 security_wifi_disconnection (ssid|3),(bssid|3),(reason|3)
+210039 security_bluetooth_connection (addr|3),(success|1),(reason|3)
+210040 security_bluetooth_disconnection (addr|3),(reason|3)
\ No newline at end of file
diff --git a/core/java/android/app/ambientcontext/AmbientContextEventRequest.java b/core/java/android/app/ambientcontext/AmbientContextEventRequest.java
index 82b16a2..0557acb 100644
--- a/core/java/android/app/ambientcontext/AmbientContextEventRequest.java
+++ b/core/java/android/app/ambientcontext/AmbientContextEventRequest.java
@@ -23,6 +23,9 @@
import android.os.PersistableBundle;
import android.util.ArraySet;
+import com.android.internal.util.AnnotationValidations;
+import com.android.internal.util.Preconditions;
+
import java.util.HashSet;
import java.util.Set;
@@ -36,15 +39,17 @@
@NonNull private final Set<Integer> mEventTypes;
@NonNull private final PersistableBundle mOptions;
- AmbientContextEventRequest(
+ private AmbientContextEventRequest(
@NonNull Set<Integer> eventTypes,
@NonNull PersistableBundle options) {
this.mEventTypes = eventTypes;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mEventTypes);
+ AnnotationValidations.validate(NonNull.class, null, mEventTypes);
+ Preconditions.checkArgument(!eventTypes.isEmpty(), "eventTypes cannot be empty");
+ for (int eventType : eventTypes) {
+ AnnotationValidations.validate(AmbientContextEvent.EventCode.class, null, eventType);
+ }
this.mOptions = options;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mOptions);
+ AnnotationValidations.validate(NonNull.class, null, mOptions);
}
/**
@@ -80,16 +85,20 @@
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
- AmbientContextEventRequest(@NonNull Parcel in) {
+ private AmbientContextEventRequest(@NonNull Parcel in) {
Set<Integer> eventTypes = (Set<Integer>) in.readArraySet(Integer.class.getClassLoader());
PersistableBundle options = (PersistableBundle) in.readTypedObject(
PersistableBundle.CREATOR);
this.mEventTypes = eventTypes;
- com.android.internal.util.AnnotationValidations.validate(
+ AnnotationValidations.validate(
NonNull.class, null, mEventTypes);
+ Preconditions.checkArgument(!eventTypes.isEmpty(), "eventTypes cannot be empty");
+ for (int eventType : eventTypes) {
+ AnnotationValidations.validate(AmbientContextEvent.EventCode.class, null, eventType);
+ }
this.mOptions = options;
- com.android.internal.util.AnnotationValidations.validate(
+ AnnotationValidations.validate(
NonNull.class, null, mOptions);
}
diff --git a/core/java/android/app/ambientcontext/AmbientContextEventResponse.java b/core/java/android/app/ambientcontext/AmbientContextEventResponse.java
deleted file mode 100644
index 472a78b..0000000
--- a/core/java/android/app/ambientcontext/AmbientContextEventResponse.java
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * 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.app.ambientcontext;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.app.PendingIntent;
-import android.os.Parcelable;
-
-import com.android.internal.util.AnnotationValidations;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Represents a response from the {@code AmbientContextEvent} service.
- *
- * @hide
- */
-@SystemApi
-public final class AmbientContextEventResponse implements Parcelable {
- /**
- * An unknown status.
- */
- public static final int STATUS_UNKNOWN = 0;
- /**
- * The value of the status code that indicates success.
- */
- public static final int STATUS_SUCCESS = 1;
- /**
- * The value of the status code that indicates one or more of the
- * requested events are not supported.
- */
- public static final int STATUS_NOT_SUPPORTED = 2;
- /**
- * The value of the status code that indicates service not available.
- */
- public static final int STATUS_SERVICE_UNAVAILABLE = 3;
- /**
- * The value of the status code that microphone is disabled.
- */
- public static final int STATUS_MICROPHONE_DISABLED = 4;
- /**
- * The value of the status code that the app is not granted access.
- */
- public static final int STATUS_ACCESS_DENIED = 5;
-
- /** @hide */
- @IntDef(prefix = { "STATUS_" }, value = {
- STATUS_UNKNOWN,
- STATUS_SUCCESS,
- STATUS_NOT_SUPPORTED,
- STATUS_SERVICE_UNAVAILABLE,
- STATUS_MICROPHONE_DISABLED,
- STATUS_ACCESS_DENIED
- }) public @interface StatusCode {}
-
- @StatusCode private final int mStatusCode;
- @NonNull private final List<AmbientContextEvent> mEvents;
- @NonNull private final String mPackageName;
- @Nullable private final PendingIntent mActionPendingIntent;
-
- /** @hide */
- public static String statusToString(@StatusCode int value) {
- switch (value) {
- case STATUS_UNKNOWN:
- return "STATUS_UNKNOWN";
- case STATUS_SUCCESS:
- return "STATUS_SUCCESS";
- case STATUS_NOT_SUPPORTED:
- return "STATUS_NOT_SUPPORTED";
- case STATUS_SERVICE_UNAVAILABLE:
- return "STATUS_SERVICE_UNAVAILABLE";
- case STATUS_MICROPHONE_DISABLED:
- return "STATUS_MICROPHONE_DISABLED";
- case STATUS_ACCESS_DENIED:
- return "STATUS_ACCESS_DENIED";
- default: return Integer.toHexString(value);
- }
- }
-
- AmbientContextEventResponse(
- @StatusCode int statusCode,
- @NonNull List<AmbientContextEvent> events,
- @NonNull String packageName,
- @Nullable PendingIntent actionPendingIntent) {
- this.mStatusCode = statusCode;
- AnnotationValidations.validate(StatusCode.class, null, mStatusCode);
- this.mEvents = events;
- AnnotationValidations.validate(NonNull.class, null, mEvents);
- this.mPackageName = packageName;
- AnnotationValidations.validate(NonNull.class, null, mPackageName);
- this.mActionPendingIntent = actionPendingIntent;
- }
-
- /**
- * The status of the response.
- */
- public @StatusCode int getStatusCode() {
- return mStatusCode;
- }
-
- /**
- * The detected event.
- */
- public @NonNull List<AmbientContextEvent> getEvents() {
- return mEvents;
- }
-
- /**
- * The package to deliver the response to.
- */
- public @NonNull String getPackageName() {
- return mPackageName;
- }
-
- /**
- * A {@link PendingIntent} that the client should call to allow further actions by user.
- * For example, with {@link STATUS_ACCESS_DENIED}, the PendingIntent can redirect users to the
- * grant access activity.
- */
- public @Nullable PendingIntent getActionPendingIntent() {
- return mActionPendingIntent;
- }
-
- @Override
- public String toString() {
- return "AmbientContextEventResponse { " + "statusCode = " + mStatusCode + ", "
- + "events = " + mEvents + ", " + "packageName = " + mPackageName + ", "
- + "callbackPendingIntent = " + mActionPendingIntent + " }";
- }
-
- @Override
- public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
- byte flg = 0;
- if (mActionPendingIntent != null) flg |= 0x8;
- dest.writeByte(flg);
- dest.writeInt(mStatusCode);
- dest.writeParcelableList(mEvents, flags);
- dest.writeString(mPackageName);
- if (mActionPendingIntent != null) dest.writeTypedObject(mActionPendingIntent, flags);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- /** @hide */
- @SuppressWarnings({"unchecked", "RedundantCast"})
- AmbientContextEventResponse(@NonNull android.os.Parcel in) {
- byte flg = in.readByte();
- int statusCode = in.readInt();
- List<AmbientContextEvent> events = new ArrayList<>();
- in.readParcelableList(events, AmbientContextEvent.class.getClassLoader(),
- AmbientContextEvent.class);
- String packageName = in.readString();
- PendingIntent callbackPendingIntent = (flg & 0x8) == 0 ? null
- : (PendingIntent) in.readTypedObject(PendingIntent.CREATOR);
-
- this.mStatusCode = statusCode;
- AnnotationValidations.validate(
- StatusCode.class, null, mStatusCode);
- this.mEvents = events;
- AnnotationValidations.validate(
- NonNull.class, null, mEvents);
- this.mPackageName = packageName;
- AnnotationValidations.validate(
- NonNull.class, null, mPackageName);
- this.mActionPendingIntent = callbackPendingIntent;
- }
-
- public static final @NonNull Parcelable.Creator<AmbientContextEventResponse> CREATOR =
- new Parcelable.Creator<AmbientContextEventResponse>() {
- @Override
- public AmbientContextEventResponse[] newArray(int size) {
- return new AmbientContextEventResponse[size];
- }
-
- @Override
- public AmbientContextEventResponse createFromParcel(@NonNull android.os.Parcel in) {
- return new AmbientContextEventResponse(in);
- }
- };
-
- /**
- * A builder for {@link AmbientContextEventResponse}
- */
- @SuppressWarnings("WeakerAccess")
- public static final class Builder {
- private @StatusCode int mStatusCode;
- private @NonNull List<AmbientContextEvent> mEvents;
- private @NonNull String mPackageName;
- private @Nullable PendingIntent mCallbackPendingIntent;
- private long mBuilderFieldsSet = 0L;
-
- public Builder() {
- }
-
- /**
- * The status of the response.
- */
- public @NonNull Builder setStatusCode(@StatusCode int value) {
- checkNotUsed();
- mBuilderFieldsSet |= 0x1;
- mStatusCode = value;
- return this;
- }
-
- /**
- * Adds an event to the builder.
- */
- public @NonNull Builder addEvent(@NonNull AmbientContextEvent value) {
- checkNotUsed();
- if (mEvents == null) {
- mBuilderFieldsSet |= 0x2;
- mEvents = new ArrayList<>();
- }
- mEvents.add(value);
- return this;
- }
-
- /**
- * The package to deliver the response to.
- */
- public @NonNull Builder setPackageName(@NonNull String value) {
- checkNotUsed();
- mBuilderFieldsSet |= 0x4;
- mPackageName = value;
- return this;
- }
-
- /**
- * A {@link PendingIntent} that the client should call to allow further actions by user.
- * For example, with {@link STATUS_ACCESS_DENIED}, the PendingIntent can redirect users to
- * the grant access activity.
- */
- public @NonNull Builder setActionPendingIntent(@NonNull PendingIntent value) {
- checkNotUsed();
- mBuilderFieldsSet |= 0x8;
- mCallbackPendingIntent = value;
- return this;
- }
-
- /** Builds the instance. This builder should not be touched after calling this! */
- public @NonNull AmbientContextEventResponse build() {
- checkNotUsed();
- mBuilderFieldsSet |= 0x10; // Mark builder used
-
- if ((mBuilderFieldsSet & 0x1) == 0) {
- mStatusCode = STATUS_UNKNOWN;
- }
- if ((mBuilderFieldsSet & 0x2) == 0) {
- mEvents = new ArrayList<>();
- }
- if ((mBuilderFieldsSet & 0x4) == 0) {
- mPackageName = "";
- }
- if ((mBuilderFieldsSet & 0x8) == 0) {
- mCallbackPendingIntent = null;
- }
- AmbientContextEventResponse o = new AmbientContextEventResponse(
- mStatusCode,
- mEvents,
- mPackageName,
- mCallbackPendingIntent);
- return o;
- }
-
- private void checkNotUsed() {
- if ((mBuilderFieldsSet & 0x10) != 0) {
- throw new IllegalStateException(
- "This Builder should not be reused. Use a new Builder instance instead");
- }
- }
- }
-}
diff --git a/core/java/android/app/ambientcontext/AmbientContextManager.java b/core/java/android/app/ambientcontext/AmbientContextManager.java
index 6841d1b..7f913e7 100644
--- a/core/java/android/app/ambientcontext/AmbientContextManager.java
+++ b/core/java/android/app/ambientcontext/AmbientContextManager.java
@@ -17,116 +17,280 @@
package android.app.ambientcontext;
import android.Manifest;
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
+import android.os.Binder;
+import android.os.RemoteCallback;
import android.os.RemoteException;
import com.android.internal.util.Preconditions;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
/**
- * Allows granted apps to register for particular pre-defined {@link AmbientContextEvent}s.
- * After successful registration, the app receives a callback on the provided {@link PendingIntent}
- * when the requested event is detected.
- * <p />
- *
- * Example:
- *
- * <pre><code>
- * // Create request
- * AmbientContextEventRequest request = new AmbientContextEventRequest.Builder()
- * .addEventType(AmbientContextEvent.EVENT_COUGH)
- * .addEventTYpe(AmbientContextEvent.EVENT_SNORE)
- * .build();
- * // Create PendingIntent
- * Intent intent = new Intent(actionString, null, context, MyBroadcastReceiver.class)
- * .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- * PendingIntent pendingIntent = PendingIntents.getBroadcastMutable(context, 0, intent, 0);
- * // Register for events
- * AmbientContextManager ambientContextManager =
- * context.getSystemService(AmbientContextManager.class);
- * ambientContextManager.registerObserver(request, pendingIntent);
- *
- * // Handle the callback intent in your receiver
- * {@literal @}Override
- * protected void onReceive(Context context, Intent intent) {
- * AmbientContextEventResponse response =
- * AmbientContextManager.getResponseFromIntent(intent);
- * if (response != null) {
- * if (response.getStatusCode() == AmbientContextEventResponse.STATUS_SUCCESS) {
- * // Do something useful with response.getEvent()
- * } else if (response.getStatusCode() == AmbientContextEventResponse.STATUS_ACCESS_DENIED) {
- * // Redirect users to grant access
- * PendingIntent callbackPendingIntent = response.getCallbackPendingIntent();
- * if (callbackPendingIntent != null) {
- * callbackPendingIntent.send();
- * }
- * } else ...
- * }
- * }
- * </code></pre>
+ * Allows granted apps to register for event types defined in {@link AmbientContextEvent}.
+ * After registration, the app receives a Consumer callback of the service status.
+ * If it is {@link STATUS_SUCCESSFUL}, when the requested events are detected, the provided
+ * {@link PendingIntent} callback will receive the list of detected {@link AmbientContextEvent}s.
+ * If it is {@link STATUS_ACCESS_DENIED}, the app can call {@link #startConsentActivity}
+ * to load the consent screen.
*
* @hide
*/
@SystemApi
@SystemService(Context.AMBIENT_CONTEXT_SERVICE)
public final class AmbientContextManager {
-
/**
- * The key of an Intent extra indicating the response.
+ * The bundle key for the service status query result, used in
+ * {@code RemoteCallback#sendResult}.
+ *
+ * @hide
*/
- public static final String EXTRA_AMBIENT_CONTEXT_EVENT_RESPONSE =
- "android.app.ambientcontext.extra.AMBIENT_CONTEXT_EVENT_RESPONSE";
+ public static final String STATUS_RESPONSE_BUNDLE_KEY =
+ "android.app.ambientcontext.AmbientContextStatusBundleKey";
/**
- * Allows clients to retrieve the response from the intent.
+ * The key of an intent extra indicating a list of detected {@link AmbientContextEvent}s.
+ * The intent is sent to the app in the app's registered {@link PendingIntent}.
+ */
+ public static final String EXTRA_AMBIENT_CONTEXT_EVENTS =
+ "android.app.ambientcontext.extra.AMBIENT_CONTEXT_EVENTS";
+
+ /**
+ * An unknown status.
+ */
+ public static final int STATUS_UNKNOWN = 0;
+
+ /**
+ * The value of the status code that indicates success.
+ */
+ public static final int STATUS_SUCCESS = 1;
+
+ /**
+ * The value of the status code that indicates one or more of the
+ * requested events are not supported.
+ */
+ public static final int STATUS_NOT_SUPPORTED = 2;
+
+ /**
+ * The value of the status code that indicates service not available.
+ */
+ public static final int STATUS_SERVICE_UNAVAILABLE = 3;
+
+ /**
+ * The value of the status code that microphone is disabled.
+ */
+ public static final int STATUS_MICROPHONE_DISABLED = 4;
+
+ /**
+ * The value of the status code that the app is not granted access.
+ */
+ public static final int STATUS_ACCESS_DENIED = 5;
+
+ /** @hide */
+ @IntDef(prefix = { "STATUS_" }, value = {
+ STATUS_UNKNOWN,
+ STATUS_SUCCESS,
+ STATUS_NOT_SUPPORTED,
+ STATUS_SERVICE_UNAVAILABLE,
+ STATUS_MICROPHONE_DISABLED,
+ STATUS_ACCESS_DENIED
+ }) public @interface StatusCode {}
+
+ /**
+ * Allows clients to retrieve the list of {@link AmbientContextEvent}s from the intent.
+ *
* @param intent received from the PendingIntent callback
*
- * @return the AmbientContextEventResponse, or null if not present
+ * @return the list of events, or an empty list if the intent doesn't have such events.
*/
- @Nullable
- public static AmbientContextEventResponse getResponseFromIntent(
- @NonNull Intent intent) {
- if (intent.hasExtra(AmbientContextManager.EXTRA_AMBIENT_CONTEXT_EVENT_RESPONSE)) {
- return intent.getParcelableExtra(EXTRA_AMBIENT_CONTEXT_EVENT_RESPONSE);
+ @NonNull public static List<AmbientContextEvent> getEventsFromIntent(@NonNull Intent intent) {
+ if (intent.hasExtra(AmbientContextManager.EXTRA_AMBIENT_CONTEXT_EVENTS)) {
+ return intent.getParcelableArrayListExtra(EXTRA_AMBIENT_CONTEXT_EVENTS);
} else {
- return null;
+ return new ArrayList<>();
}
}
private final Context mContext;
- private final IAmbientContextEventObserver mService;
+ private final IAmbientContextManager mService;
/**
* {@hide}
*/
- public AmbientContextManager(Context context, IAmbientContextEventObserver service) {
+ public AmbientContextManager(Context context, IAmbientContextManager service) {
mContext = context;
mService = service;
}
/**
+ * Queries the {@link AmbientContextEvent} service status for the calling package, and
+ * sends the result to the {@link Consumer} right after the call. This is used by foreground
+ * apps to check whether the requested events are enabled for detection on the device.
+ * If all events are enabled for detection, the response has
+ * {@link AmbientContextManager#STATUS_SUCCESS}.
+ * If any of the events are not consented by user, the response has
+ * {@link AmbientContextManager#STATUS_ACCESS_DENIED}, and the app can
+ * call {@link #startConsentActivity} to redirect the user to the consent screen.
+ * <p />
+ *
+ * Example:
+ *
+ * <pre><code>
+ * Set<Integer> eventTypes = new HashSet<>();
+ * eventTypes.add(AmbientContextEvent.EVENT_COUGH);
+ * eventTypes.add(AmbientContextEvent.EVENT_SNORE);
+ *
+ * // Create Consumer
+ * Consumer<Integer> statusConsumer = response -> {
+ * int status = status.getStatusCode();
+ * if (status == AmbientContextManager.STATUS_SUCCESS) {
+ * // Show user it's enabled
+ * } else if (status == AmbientContextManager.STATUS_ACCESS_DENIED) {
+ * // Send user to grant access
+ * startConsentActivity(eventTypes);
+ * }
+ * };
+ *
+ * // Query status
+ * AmbientContextManager ambientContextManager =
+ * context.getSystemService(AmbientContextManager.class);
+ * ambientContextManager.queryAmbientContextStatus(eventTypes, executor, statusConsumer);
+ * </code></pre>
+ *
+ * @param eventTypes The set of event codes to check status on.
+ * @param executor Executor on which to run the consumer callback.
+ * @param consumer The consumer that handles the status code.
+ */
+ @RequiresPermission(Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT)
+ public void queryAmbientContextServiceStatus(
+ @NonNull @AmbientContextEvent.EventCode Set<Integer> eventTypes,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull @StatusCode Consumer<Integer> consumer) {
+ try {
+ RemoteCallback callback = new RemoteCallback(result -> {
+ int status = result.getInt(STATUS_RESPONSE_BUNDLE_KEY);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> consumer.accept(status));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ });
+ mService.queryServiceStatus(integerSetToIntArray(eventTypes),
+ mContext.getOpPackageName(), callback);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Requests the consent data host to open an activity that allows users to modify consent.
+ *
+ * @param eventTypes The set of event codes to be consented.
+ */
+ @RequiresPermission(Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT)
+ public void startConsentActivity(
+ @NonNull @AmbientContextEvent.EventCode Set<Integer> eventTypes) {
+ try {
+ mService.startConsentActivity(
+ integerSetToIntArray(eventTypes), mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @NonNull
+ private static int[] integerSetToIntArray(@NonNull Set<Integer> integerSet) {
+ int[] intArray = new int[integerSet.size()];
+ int i = 0;
+ for (Integer type : integerSet) {
+ intArray[i++] = type;
+ }
+ return intArray;
+ }
+
+ /**
* Allows app to register as a {@link AmbientContextEvent} observer. The
* observer receives a callback on the provided {@link PendingIntent} when the requested
* event is detected. Registering another observer from the same package that has already been
* registered will override the previous observer.
+ * <p />
+ *
+ * Example:
+ *
+ * <pre><code>
+ * // Create request
+ * AmbientContextEventRequest request = new AmbientContextEventRequest.Builder()
+ * .addEventType(AmbientContextEvent.EVENT_COUGH)
+ * .addEventType(AmbientContextEvent.EVENT_SNORE)
+ * .build();
+ *
+ * // Create PendingIntent for delivering detection results to my receiver
+ * Intent intent = new Intent(actionString, null, context, MyBroadcastReceiver.class)
+ * .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ * PendingIntent pendingIntent =
+ * PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ *
+ * // Create Consumer of service status
+ * Consumer<Integer> statusConsumer = status -> {
+ * if (status == AmbientContextManager.STATUS_ACCESS_DENIED) {
+ * // User did not consent event detection. See #queryAmbientContextServiceStatus and
+ * // #startConsentActivity
+ * }
+ * };
+ *
+ * // Register as observer
+ * AmbientContextManager ambientContextManager =
+ * context.getSystemService(AmbientContextManager.class);
+ * ambientContextManager.registerObserver(request, pendingIntent, executor, statusConsumer);
+ *
+ * // Handle the list of {@link AmbientContextEvent}s in your receiver
+ * {@literal @}Override
+ * protected void onReceive(Context context, Intent intent) {
+ * List<AmbientContextEvent> events = AmbientContextManager.getEventsFromIntent(intent);
+ * if (!events.isEmpty()) {
+ * // Do something useful with the events.
+ * }
+ * }
+ * </code></pre>
*
* @param request The request with events to observe.
- * @param pendingIntent A mutable {@link PendingIntent} that will be dispatched when any
- * requested event is detected.
+ * @param resultPendingIntent A mutable {@link PendingIntent} that will be dispatched after the
+ * requested events are detected.
+ * @param executor Executor on which to run the consumer callback.
+ * @param statusConsumer A consumer that handles the status code, which is returned
+ * right after the call.
*/
@RequiresPermission(Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT)
public void registerObserver(
@NonNull AmbientContextEventRequest request,
- @NonNull PendingIntent pendingIntent) {
- Preconditions.checkArgument(!pendingIntent.isImmutable());
+ @NonNull PendingIntent resultPendingIntent,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull @StatusCode Consumer<Integer> statusConsumer) {
+ Preconditions.checkArgument(!resultPendingIntent.isImmutable());
try {
- mService.registerObserver(request, pendingIntent);
+ RemoteCallback callback = new RemoteCallback(result -> {
+ int statusCode = result.getInt(STATUS_RESPONSE_BUNDLE_KEY);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> statusConsumer.accept(statusCode));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ });
+ mService.registerObserver(request, resultPendingIntent, callback);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/ambientcontext/IAmbientContextEventObserver.aidl b/core/java/android/app/ambientcontext/IAmbientContextManager.aidl
similarity index 66%
rename from core/java/android/app/ambientcontext/IAmbientContextEventObserver.aidl
rename to core/java/android/app/ambientcontext/IAmbientContextManager.aidl
index 9032fe1..3b15bcb 100644
--- a/core/java/android/app/ambientcontext/IAmbientContextEventObserver.aidl
+++ b/core/java/android/app/ambientcontext/IAmbientContextManager.aidl
@@ -18,13 +18,19 @@
import android.app.PendingIntent;
import android.app.ambientcontext.AmbientContextEventRequest;
+import android.os.RemoteCallback;
/**
- * Interface for an AmbientContextEventManager that provides access to AmbientContextEvents.
+ * Interface for an AmbientContextManager that provides access to AmbientContextEvents.
*
* @hide
*/
-oneway interface IAmbientContextEventObserver {
- void registerObserver(in AmbientContextEventRequest request, in PendingIntent pendingIntent);
+oneway interface IAmbientContextManager {
+ void registerObserver(in AmbientContextEventRequest request,
+ in PendingIntent resultPendingIntent,
+ in RemoteCallback statusCallback);
void unregisterObserver(in String callingPackage);
+ void queryServiceStatus(in int[] eventTypes, in String callingPackage,
+ in RemoteCallback statusCallback);
+ void startConsentActivity(in int[] eventTypes, in String callingPackage);
}
\ No newline at end of file
diff --git a/core/java/android/app/assist/ActivityId.java b/core/java/android/app/assist/ActivityId.java
index fb0d056..1cc4b02 100644
--- a/core/java/android/app/assist/ActivityId.java
+++ b/core/java/android/app/assist/ActivityId.java
@@ -22,6 +22,7 @@
import android.annotation.TestApi;
import android.os.IBinder;
import android.os.Parcel;
+import android.os.Parcelable;
import android.service.contentcapture.ContentCaptureService;
import android.view.contentcapture.ContentCaptureContext;
import android.view.translation.UiTranslationManager;
@@ -38,7 +39,8 @@
*/
@Immutable
@SystemApi
-public class ActivityId {
+@TestApi
+public final class ActivityId implements Parcelable {
/**
* The identifier of the task this activity is in.
@@ -53,6 +55,7 @@
/**
* @hide
*/
+ @TestApi
public ActivityId(int taskId, @Nullable IBinder activityId) {
mTaskId = taskId;
mActivityId = activityId;
@@ -87,13 +90,39 @@
}
/**
- * @hide
+ * {@inheritDoc}
*/
- public void writeToParcel(@NonNull Parcel dest, int parcelableFlags) {
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mTaskId);
dest.writeStrongBinder(mActivityId);
}
+ /**
+ * Creates {@link ActivityId} instances from parcels.
+ */
+ @NonNull
+ public static final Parcelable.Creator<ActivityId> CREATOR =
+ new Parcelable.Creator<ActivityId>() {
+ @Override
+ public ActivityId createFromParcel(Parcel parcel) {
+ return new ActivityId(parcel);
+ }
+
+ @Override
+ public ActivityId[] newArray(int size) {
+ return new ActivityId[size];
+ }
+ };
+
@Override
public String toString() {
return "ActivityId { taskId = " + mTaskId + ", activityId = " + mActivityId + " }";
diff --git a/core/java/android/app/cloudsearch/SearchRequest.java b/core/java/android/app/cloudsearch/SearchRequest.java
index 0c5c30c..ef66c0c 100644
--- a/core/java/android/app/cloudsearch/SearchRequest.java
+++ b/core/java/android/app/cloudsearch/SearchRequest.java
@@ -21,6 +21,7 @@
import android.annotation.Nullable;
import android.annotation.StringDef;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -91,6 +92,14 @@
@NonNull
private Bundle mSearchConstraints;
+ /** Auto set by system servier, and the caller cannot set it.
+ *
+ * The caller's package name.
+ *
+ */
+ @NonNull
+ private String mSource;
+
private SearchRequest(Parcel in) {
this.mQuery = in.readString();
this.mResultOffset = in.readInt();
@@ -98,15 +107,17 @@
this.mMaxLatencyMillis = in.readFloat();
this.mSearchConstraints = in.readBundle();
this.mId = in.readString();
+ this.mSource = in.readString();
}
private SearchRequest(String query, int resultOffset, int resultNumber, float maxLatencyMillis,
- Bundle searchConstraints) {
+ Bundle searchConstraints, String source) {
mQuery = query;
mResultOffset = resultOffset;
mResultNumber = resultNumber;
mMaxLatencyMillis = maxLatencyMillis;
mSearchConstraints = searchConstraints;
+ mSource = source;
}
/** Returns the original query. */
@@ -136,35 +147,37 @@
return mSearchConstraints;
}
+ /** Gets the caller's package name. */
+ @NonNull
+ public String getSource() {
+ return mSource;
+ }
+
/** Returns the search request id, which is used to identify the request. */
@NonNull
public String getRequestId() {
if (mId == null || mId.length() == 0) {
- boolean isPresubmit =
- mSearchConstraints.containsKey(CONSTRAINT_IS_PRESUBMIT_SUGGESTION)
- && mSearchConstraints.getBoolean(CONSTRAINT_IS_PRESUBMIT_SUGGESTION);
-
- String searchProvider = "EMPTY";
- if (mSearchConstraints.containsKey(CONSTRAINT_SEARCH_PROVIDER_FILTER)) {
- searchProvider = mSearchConstraints.getString(CONSTRAINT_SEARCH_PROVIDER_FILTER);
- }
-
- String rawContent = String.format("%s\t%d\t%d\t%f\t%b\t%s",
- mQuery, mResultOffset, mResultNumber, mMaxLatencyMillis,
- isPresubmit, searchProvider);
-
- mId = String.valueOf(rawContent.hashCode());
+ mId = String.valueOf(toString().hashCode());
}
return mId;
}
+ /** Sets the caller, and this will be set by the system server.
+ *
+ * @hide
+ */
+ public void setSource(@NonNull String source) {
+ this.mSource = source;
+ }
+
private SearchRequest(Builder b) {
mQuery = requireNonNull(b.mQuery);
mResultOffset = b.mResultOffset;
mResultNumber = b.mResultNumber;
mMaxLatencyMillis = b.mMaxLatencyMillis;
mSearchConstraints = requireNonNull(b.mSearchConstraints);
+ mSource = requireNonNull(b.mSource);
}
/**
@@ -192,6 +205,7 @@
dest.writeFloat(this.mMaxLatencyMillis);
dest.writeBundle(this.mSearchConstraints);
dest.writeString(getRequestId());
+ dest.writeString(this.mSource);
}
@Override
@@ -214,13 +228,30 @@
&& mResultOffset == that.mResultOffset
&& mResultNumber == that.mResultNumber
&& mMaxLatencyMillis == that.mMaxLatencyMillis
- && Objects.equals(mSearchConstraints, that.mSearchConstraints);
+ && Objects.equals(mSearchConstraints, that.mSearchConstraints)
+ && Objects.equals(mSource, that.mSource);
+ }
+
+ @Override
+ public String toString() {
+ boolean isPresubmit =
+ mSearchConstraints.containsKey(CONSTRAINT_IS_PRESUBMIT_SUGGESTION)
+ && mSearchConstraints.getBoolean(CONSTRAINT_IS_PRESUBMIT_SUGGESTION);
+
+ String searchProvider = "EMPTY";
+ if (mSearchConstraints.containsKey(CONSTRAINT_SEARCH_PROVIDER_FILTER)) {
+ searchProvider = mSearchConstraints.getString(CONSTRAINT_SEARCH_PROVIDER_FILTER);
+ }
+
+ return String.format("SearchRequest: {query:%s,offset:%d;number:%d;max_latency:%f;"
+ + "is_presubmit:%b;search_provider:%s;source:%s}", mQuery, mResultOffset,
+ mResultNumber, mMaxLatencyMillis, isPresubmit, searchProvider, mSource);
}
@Override
public int hashCode() {
return Objects.hash(mQuery, mResultOffset, mResultNumber, mMaxLatencyMillis,
- mSearchConstraints);
+ mSearchConstraints, mSource);
}
/**
@@ -235,6 +266,7 @@
private int mResultNumber;
private float mMaxLatencyMillis;
private Bundle mSearchConstraints;
+ private String mSource;
/**
*
@@ -250,6 +282,7 @@
mResultNumber = 10;
mMaxLatencyMillis = 200;
mSearchConstraints = Bundle.EMPTY;
+ mSource = "DEFAULT_CALLER";
}
/** Sets the input query. */
@@ -288,6 +321,17 @@
return this;
}
+ /** Sets the caller, and this will be set by the system server.
+ *
+ * @hide
+ */
+ @NonNull
+ @TestApi
+ public Builder setSource(@NonNull String source) {
+ this.mSource = source;
+ return this;
+ }
+
/** Builds a SearchRequest based-on the given params. */
@NonNull
public SearchRequest build() {
@@ -297,7 +341,7 @@
}
return new SearchRequest(mQuery, mResultOffset, mResultNumber, mMaxLatencyMillis,
- mSearchConstraints);
+ mSearchConstraints, mSource);
}
}
}
diff --git a/core/java/android/app/time/ExternalTimeSuggestion.java b/core/java/android/app/time/ExternalTimeSuggestion.java
index 0f98b44..c118558 100644
--- a/core/java/android/app/time/ExternalTimeSuggestion.java
+++ b/core/java/android/app/time/ExternalTimeSuggestion.java
@@ -50,16 +50,17 @@
* <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 @@
};
@NonNull
- private final TimestampedValue<Long> mUtcTime;
+ private final TimestampedValue<Long> mUnixEpochTime;
@Nullable
private ArrayList<String> mDebugInfo;
@@ -92,12 +93,12 @@
* 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 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeParcelable(mUtcTime, 0);
+ dest.writeParcelable(mUnixEpochTime, 0);
dest.writeList(mDebugInfo);
}
@@ -125,8 +126,8 @@
* {@hide}
*/
@NonNull
- public TimestampedValue<Long> getUtcTime() {
- return mUtcTime;
+ public TimestampedValue<Long> getUnixEpochTime() {
+ return mUnixEpochTime;
}
/**
@@ -160,17 +161,18 @@
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 8ccff62..463e5f0 100644
--- a/core/java/android/app/timedetector/GnssTimeSuggestion.java
+++ b/core/java/android/app/timedetector/GnssTimeSuggestion.java
@@ -31,11 +31,11 @@
/**
* 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,19 +57,21 @@
}
};
- @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 */, android.os.TimestampedValue.class);
- GnssTimeSuggestion suggestion = new GnssTimeSuggestion(utcTime);
+ TimestampedValue<Long> unixEpochTime =
+ in.readParcelable(null /* classLoader */, android.os.TimestampedValue.class);
+ GnssTimeSuggestion suggestion = new GnssTimeSuggestion(unixEpochTime);
@SuppressWarnings("unchecked")
- ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */, java.lang.String.class);
+ ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(
+ null /* classLoader */, java.lang.String.class);
suggestion.mDebugInfo = debugInfo;
return suggestion;
}
@@ -81,13 +83,13 @@
@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 +119,18 @@
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 1699a5f..247d971 100644
--- a/core/java/android/app/timedetector/ManualTimeSuggestion.java
+++ b/core/java/android/app/timedetector/ManualTimeSuggestion.java
@@ -31,9 +31,9 @@
/**
* 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,19 +57,21 @@
}
};
- @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 */, android.os.TimestampedValue.class);
- ManualTimeSuggestion suggestion = new ManualTimeSuggestion(utcTime);
+ TimestampedValue<Long> unixEpochTime =
+ in.readParcelable(null /* classLoader */, android.os.TimestampedValue.class);
+ ManualTimeSuggestion suggestion = new ManualTimeSuggestion(unixEpochTime);
@SuppressWarnings("unchecked")
- ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */, java.lang.String.class);
+ ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(
+ null /* classLoader */, java.lang.String.class);
suggestion.mDebugInfo = debugInfo;
return suggestion;
}
@@ -81,13 +83,13 @@
@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 +119,18 @@
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 2030083..f620bc9 100644
--- a/core/java/android/app/timedetector/NetworkTimeSuggestion.java
+++ b/core/java/android/app/timedetector/NetworkTimeSuggestion.java
@@ -31,11 +31,12 @@
/**
* 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,19 +58,21 @@
}
};
- @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 */, android.os.TimestampedValue.class);
- NetworkTimeSuggestion suggestion = new NetworkTimeSuggestion(utcTime);
+ TimestampedValue<Long> unixEpochTime =
+ in.readParcelable(null /* classLoader */, android.os.TimestampedValue.class);
+ NetworkTimeSuggestion suggestion = new NetworkTimeSuggestion(unixEpochTime);
@SuppressWarnings("unchecked")
- ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */, java.lang.String.class);
+ ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(
+ null /* classLoader */, java.lang.String.class);
suggestion.mDebugInfo = debugInfo;
return suggestion;
}
@@ -81,13 +84,13 @@
@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 +120,18 @@
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 52d0bbe..1fa392a 100644
--- a/core/java/android/app/timedetector/TelephonyTimeSuggestion.java
+++ b/core/java/android/app/timedetector/TelephonyTimeSuggestion.java
@@ -34,12 +34,12 @@
* <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,22 +65,25 @@
};
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 */, android.os.TimestampedValue.class);
TelephonyTimeSuggestion suggestion = new TelephonyTimeSuggestion.Builder(slotIndex)
- .setUtcTime(in.readParcelable(null /* classLoader */, android.os.TimestampedValue.class))
+ .setUnixEpochTime(unixEpochTime)
.build();
@SuppressWarnings("unchecked")
- ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */, java.lang.String.class);
+ ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(
+ null /* classLoader */, java.lang.String.class);
if (debugInfo != null) {
suggestion.addDebugInfo(debugInfo);
}
@@ -95,7 +98,7 @@
@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 +114,11 @@
/**
* 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 +166,19 @@
}
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 +190,7 @@
*/
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 +205,16 @@
/**
* 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/app/trust/ITrustManager.aidl b/core/java/android/app/trust/ITrustManager.aidl
index edabccf..b786444 100644
--- a/core/java/android/app/trust/ITrustManager.aidl
+++ b/core/java/android/app/trust/ITrustManager.aidl
@@ -33,8 +33,8 @@
void unregisterTrustListener(in ITrustListener trustListener);
void reportKeyguardShowingChanged();
void setDeviceLockedForUser(int userId, boolean locked);
- boolean isDeviceLocked(int userId);
- boolean isDeviceSecure(int userId);
+ boolean isDeviceLocked(int userId, int displayId);
+ boolean isDeviceSecure(int userId, int displayId);
boolean isTrustUsuallyManaged(int userId);
void unlockedByBiometricForUser(int userId, in BiometricSourceType source);
void clearAllBiometricRecognized(in BiometricSourceType target, int unlockedUser);
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index 0f5cd4e..3c256ad 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -1037,6 +1037,7 @@
// Data can be too large for a transact. Write the data as a Blob, which will be written to
// ashmem if too large.
dest.writeBlob(data.marshall());
+ data.recycle();
}
public static final @android.annotation.NonNull Creator<UsageEvents> CREATOR = new Creator<UsageEvents>() {
diff --git a/core/java/android/companion/AssociationInfo.java b/core/java/android/companion/AssociationInfo.java
index 373a8d9..f7f0235 100644
--- a/core/java/android/companion/AssociationInfo.java
+++ b/core/java/android/companion/AssociationInfo.java
@@ -207,6 +207,18 @@
return macAddress.equals(mDeviceMacAddress);
}
+ /**
+ * Utility method to be used by CdmService only.
+ *
+ * @return whether CdmService should bind the companion application that "owns" this association
+ * when the device is present.
+ *
+ * @hide
+ */
+ public boolean shouldBindWhenPresent() {
+ return mNotifyOnDeviceNearby || mSelfManaged;
+ }
+
/** @hide */
public @NonNull String toShortString() {
final StringBuilder sb = new StringBuilder();
diff --git a/core/java/android/companion/AssociationRequest.java b/core/java/android/companion/AssociationRequest.java
index bd8ba9e..257530b 100644
--- a/core/java/android/companion/AssociationRequest.java
+++ b/core/java/android/companion/AssociationRequest.java
@@ -260,9 +260,9 @@
}
/**
- * Indicates that the application would prefer the CompanionDeviceManager to collect an explicit
- * confirmation from the user before creating an association, even if such confirmation is not
- * required.
+ * Indicates whether the application requires the {@link CompanionDeviceManager} service to
+ * collect an explicit confirmation from the user before creating an association, even if
+ * such confirmation is not required from the service's perspective.
*
* @see Builder#setForceConfirmation(boolean)
*/
@@ -391,9 +391,9 @@
}
/**
- * Indicates whether the application would prefer the CompanionDeviceManager to collect an
- * explicit confirmation from the user before creating an association, even if such
- * confirmation is not required.
+ * Indicates whether the application requires the {@link CompanionDeviceManager} service to
+ * collect an explicit confirmation from the user before creating an association, even if
+ * such confirmation is not required from the service's perspective.
*/
@RequiresPermission(REQUEST_COMPANION_SELF_MANAGED)
@NonNull
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index 36802ea..1568500 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -780,9 +780,9 @@
}
/**
- * Notify the system that the given self-managed association has just 'appeared'.
+ * Notify the system that the given self-managed association has just appeared.
* This causes the system to bind to the companion app to keep it running until the association
- * is reported as 'disappeared'
+ * is reported as disappeared
*
* <p>This API is only available for the companion apps that manage the connectivity by
* themselves.</p>
@@ -803,7 +803,7 @@
}
/**
- * Notify the system that the given self-managed association has just 'disappeared'.
+ * Notify the system that the given self-managed association has just disappeared.
* This causes the system to unbind to the companion app.
*
* <p>This API is only available for the companion apps that manage the connectivity by
diff --git a/core/java/android/companion/CompanionDeviceService.java b/core/java/android/companion/CompanionDeviceService.java
index cb96ebe..9e1bf4b 100644
--- a/core/java/android/companion/CompanionDeviceService.java
+++ b/core/java/android/companion/CompanionDeviceService.java
@@ -77,10 +77,11 @@
* {@link #onDeviceAppeared(AssociationInfo)} and {@link #onDeviceDisappeared(AssociationInfo)}
* only to one "primary" services.
* Applications that declare multiple {@link CompanionDeviceService}-s should indicate the "primary"
- * service using "android.companion.primary" tag.
+ * service using "android.companion.PROPERTY_PRIMARY_COMPANION_DEVICE_SERVICE" service level
+ * property.
* <pre>{@code
- * <meta-data
- * android:name="android.companion.primary"
+ * <property
+ * android:name="android.companion.PROPERTY_PRIMARY_COMPANION_DEVICE_SERVICE"
* android:value="true" />
* }</pre>
*
diff --git a/core/java/android/companion/virtual/IVirtualDevice.aidl b/core/java/android/companion/virtual/IVirtualDevice.aidl
index 8fc24fd..e285999 100644
--- a/core/java/android/companion/virtual/IVirtualDevice.aidl
+++ b/core/java/android/companion/virtual/IVirtualDevice.aidl
@@ -17,6 +17,7 @@
package android.companion.virtual;
import android.app.PendingIntent;
+import android.companion.virtual.audio.IAudioSessionCallback;
import android.graphics.Point;
import android.graphics.PointF;
import android.hardware.input.VirtualKeyEvent;
@@ -45,6 +46,15 @@
*/
void close();
+ /**
+ * Notifies of an audio session being started.
+ */
+ void onAudioSessionStarting(
+ int displayId,
+ IAudioSessionCallback callback);
+
+ void onAudioSessionEnded();
+
void createVirtualKeyboard(
int displayId,
String inputDeviceName,
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index 69033a6..f1abb05 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -16,19 +16,23 @@
package android.companion.virtual;
+import android.annotation.CallbackExecutor;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
-import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.app.Activity;
import android.app.PendingIntent;
import android.companion.AssociationInfo;
+import android.companion.virtual.audio.VirtualAudioDevice;
+import android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChangeCallback;
import android.content.ComponentName;
import android.content.Context;
import android.graphics.Point;
import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManager.VirtualDisplayFlag;
import android.hardware.display.VirtualDisplay;
import android.hardware.display.VirtualDisplayConfig;
import android.hardware.input.VirtualKeyboard;
@@ -44,6 +48,7 @@
import android.util.ArrayMap;
import android.view.Surface;
+import java.util.Objects;
import java.util.concurrent.Executor;
/**
@@ -208,25 +213,22 @@
* {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_PUBLIC VIRTUAL_DISPLAY_FLAG_PUBLIC} and
* {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
* VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY}.
+ * @param executor The executor on which {@code callback} will be invoked. This is ignored
+ * if {@code callback} is {@code null}.
* @param callback Callback to call when the state of the {@link VirtualDisplay} changes
- * @param handler The handler on which the listener should be invoked, or null
- * if the listener should be invoked on the calling thread's looper.
* @return The newly created virtual display, or {@code null} if the application could
* not create the virtual display.
*
* @see DisplayManager#createVirtualDisplay
*/
- // Suppress "ExecutorRegistration" because DisplayManager.createVirtualDisplay takes a
- // handler
- @SuppressLint("ExecutorRegistration")
@Nullable
public VirtualDisplay createVirtualDisplay(
- int width,
- int height,
- int densityDpi,
+ @IntRange(from = 1) int width,
+ @IntRange(from = 1) int height,
+ @IntRange(from = 1) int densityDpi,
@Nullable Surface surface,
- int flags,
- @Nullable Handler handler,
+ @VirtualDisplayFlag int flags,
+ @NonNull @CallbackExecutor Executor executor,
@Nullable VirtualDisplay.Callback callback) {
// TODO(b/205343547): Handle display groups properly instead of creating a new display
// group for every new virtual display created using this API.
@@ -242,13 +244,14 @@
.setFlags(getVirtualDisplayFlags(flags))
.build(),
callback,
- handler);
+ Objects.requireNonNull(executor));
}
/**
* Closes the virtual device, stopping and tearing down any virtual displays,
* audio policies, and event injection that's currently in progress.
*/
+ @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
public void close() {
try {
mVirtualDevice.close();
@@ -262,8 +265,8 @@
*
* @param display the display that the events inputted through this device should target
* @param inputDeviceName the name to call this input device
- * @param vendorId the vendor id
- * @param productId the product id
+ * @param vendorId the vendor id, as defined by uinput's uinput_setup struct (PCI vendor id)
+ * @param productId the product id, as defined by uinput's uinput_setup struct
*/
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
@NonNull
@@ -288,8 +291,8 @@
*
* @param display the display that the events inputted through this device should target
* @param inputDeviceName the name to call this input device
- * @param vendorId the vendor id
- * @param productId the product id
+ * @param vendorId the vendor id, as defined by uinput's uinput_setup struct (PCI vendor id)
+ * @param productId the product id, as defined by uinput's uinput_setup struct
*/
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
@NonNull
@@ -314,8 +317,8 @@
*
* @param display the display that the events inputted through this device should target
* @param inputDeviceName the name to call this input device
- * @param vendorId the vendor id
- * @param productId the product id
+ * @param vendorId the vendor id, as defined by uinput's uinput_setup struct (PCI vendor id)
+ * @param productId the product id, as defined by uinput's uinput_setup struct
*/
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
@NonNull
@@ -338,6 +341,30 @@
}
/**
+ * Creates a VirtualAudioDevice, capable of recording audio emanating from this device,
+ * or injecting audio from another device.
+ *
+ * <p>Note: This object does not support capturing privileged playback, such as voice call
+ * audio.
+ *
+ * @param display The target virtual display to capture from and inject into.
+ * @param executor The {@link Executor} object for the thread on which to execute
+ * the callback. If <code>null</code>, the {@link Executor} associated with
+ * the main {@link Looper} will be used.
+ * @param callback Interface to be notified when playback or recording configuration of
+ * applications running on virtual display is changed.
+ * @return A {@link VirtualAudioDevice} instance.
+ */
+ @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
+ @NonNull
+ public VirtualAudioDevice createVirtualAudioDevice(
+ @NonNull VirtualDisplay display,
+ @Nullable Executor executor,
+ @Nullable AudioConfigurationChangeCallback callback) {
+ return new VirtualAudioDevice(mContext, mVirtualDevice, display, executor, callback);
+ }
+
+ /**
* Sets the visibility of the pointer icon for this VirtualDevice's associated displays.
*
* @param showPointerIcon True if the pointer should be shown; false otherwise. The default
diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java
index 1d0f7c0..45d0ad5 100644
--- a/core/java/android/companion/virtual/VirtualDeviceParams.java
+++ b/core/java/android/companion/virtual/VirtualDeviceParams.java
@@ -48,15 +48,16 @@
/** @hide */
@IntDef(prefix = "LOCK_STATE_",
- value = {LOCK_STATE_ALWAYS_LOCKED, LOCK_STATE_ALWAYS_UNLOCKED})
+ value = {LOCK_STATE_DEFAULT, LOCK_STATE_ALWAYS_UNLOCKED})
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
public @interface LockState {}
/**
- * Indicates that the lock state of the virtual device should be always locked.
+ * Indicates that the lock state of the virtual device will be the same as the default physical
+ * display.
*/
- public static final int LOCK_STATE_ALWAYS_LOCKED = 0;
+ public static final int LOCK_STATE_DEFAULT = 0;
/**
* Indicates that the lock state of the virtual device should be always unlocked.
@@ -199,7 +200,7 @@
*/
public static final class Builder {
- private @LockState int mLockState = LOCK_STATE_ALWAYS_LOCKED;
+ private @LockState int mLockState = LOCK_STATE_DEFAULT;
private Set<UserHandle> mUsersWithMatchingAccounts;
@Nullable private Set<ComponentName> mBlockedActivities;
@Nullable private Set<ComponentName> mAllowedActivities;
@@ -207,9 +208,9 @@
/**
* Sets the lock state of the device. The permission {@code ADD_ALWAYS_UNLOCKED_DISPLAY}
* is required if this is set to {@link #LOCK_STATE_ALWAYS_UNLOCKED}.
- * The default is {@link #LOCK_STATE_ALWAYS_LOCKED}.
+ * The default is {@link #LOCK_STATE_DEFAULT}.
*
- * @param lockState The lock state, either {@link #LOCK_STATE_ALWAYS_LOCKED} or
+ * @param lockState The lock state, either {@link #LOCK_STATE_DEFAULT} or
* {@link #LOCK_STATE_ALWAYS_UNLOCKED}.
*/
@RequiresPermission(value = ADD_ALWAYS_UNLOCKED_DISPLAY, conditional = true)
diff --git a/core/java/android/companion/virtual/audio/AudioCapture.java b/core/java/android/companion/virtual/audio/AudioCapture.java
new file mode 100644
index 0000000..ebe17db
--- /dev/null
+++ b/core/java/android/companion/virtual/audio/AudioCapture.java
@@ -0,0 +1,124 @@
+/*
+ * 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.companion.virtual.audio;
+
+import static android.media.AudioRecord.RECORDSTATE_RECORDING;
+import static android.media.AudioRecord.RECORDSTATE_STOPPED;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.media.AudioRecord;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Wrapper around {@link AudioRecord} that allows for the underlying {@link AudioRecord} to
+ * be swapped out while recording is ongoing.
+ *
+ * @hide
+ */
+// The stop() actually doesn't release resources, so should not force implementing Closeable.
+@SuppressLint("NotCloseable")
+@SystemApi
+public final class AudioCapture {
+ private static final String TAG = "AudioCapture";
+
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ @Nullable
+ private AudioRecord mAudioRecord;
+
+ @GuardedBy("mLock")
+ private int mRecordingState = RECORDSTATE_STOPPED;
+
+ /**
+ * Sets the {@link AudioRecord} to handle audio capturing.
+ * Callers may call this multiple times with different audio records to change
+ * the underlying {@link AudioRecord} without stopping and re-starting recording.
+ *
+ * @param audioRecord The underlying {@link AudioRecord} to use for capture,
+ * or null if no audio (i.e. silence) should be captured while still keeping the
+ * record in a recording state.
+ */
+ void setAudioRecord(@Nullable AudioRecord audioRecord) {
+ Log.d(TAG, "set AudioRecord with " + audioRecord);
+ synchronized (mLock) {
+ // Release old reference.
+ if (mAudioRecord != null) {
+ mAudioRecord.release();
+ }
+ // Sync recording state for new reference.
+ if (audioRecord != null) {
+ if (mRecordingState == RECORDSTATE_RECORDING
+ && audioRecord.getRecordingState() != RECORDSTATE_RECORDING) {
+ audioRecord.startRecording();
+ }
+ if (mRecordingState == RECORDSTATE_STOPPED
+ && audioRecord.getRecordingState() != RECORDSTATE_STOPPED) {
+ audioRecord.stop();
+ }
+ }
+ mAudioRecord = audioRecord;
+ }
+ }
+
+ /** See {@link AudioRecord#read(ByteBuffer, int)}. */
+ public int read(@NonNull ByteBuffer audioBuffer, int sizeInBytes) {
+ final int sizeRead;
+ synchronized (mLock) {
+ if (mAudioRecord != null) {
+ sizeRead = mAudioRecord.read(audioBuffer, sizeInBytes);
+ } else {
+ sizeRead = 0;
+ }
+ }
+ return sizeRead;
+ }
+
+ /** See {@link AudioRecord#startRecording()}. */
+ public void startRecording() {
+ synchronized (mLock) {
+ mRecordingState = RECORDSTATE_RECORDING;
+ if (mAudioRecord != null && mAudioRecord.getRecordingState() != RECORDSTATE_RECORDING) {
+ mAudioRecord.startRecording();
+ }
+ }
+ }
+
+ /** See {@link AudioRecord#stop()}. */
+ public void stop() {
+ synchronized (mLock) {
+ mRecordingState = RECORDSTATE_STOPPED;
+ if (mAudioRecord != null && mAudioRecord.getRecordingState() != RECORDSTATE_STOPPED) {
+ mAudioRecord.stop();
+ }
+ }
+ }
+
+ /** See {@link AudioRecord#getRecordingState()}. */
+ public int getRecordingState() {
+ synchronized (mLock) {
+ return mRecordingState;
+ }
+ }
+}
diff --git a/core/java/android/companion/virtual/audio/AudioInjection.java b/core/java/android/companion/virtual/audio/AudioInjection.java
new file mode 100644
index 0000000..5e8e0a4
--- /dev/null
+++ b/core/java/android/companion/virtual/audio/AudioInjection.java
@@ -0,0 +1,131 @@
+/*
+ * 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.companion.virtual.audio;
+
+import static android.media.AudioTrack.PLAYSTATE_PLAYING;
+import static android.media.AudioTrack.PLAYSTATE_STOPPED;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.media.AudioTrack;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Wrapper around {@link AudioTrack} that allows for the underlying {@link AudioTrack} to
+ * be swapped out while playout is ongoing.
+ *
+ * @hide
+ */
+// The stop() actually doesn't release resources, so should not force implementing Closeable.
+@SuppressLint("NotCloseable")
+@SystemApi
+public final class AudioInjection {
+ private static final String TAG = "AudioInjection";
+
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
+ @Nullable
+ private AudioTrack mAudioTrack;
+ @GuardedBy("mLock")
+ private int mPlayState = PLAYSTATE_STOPPED;
+ @GuardedBy("mLock")
+ private boolean mIsSilent;
+
+ /** Sets if the injected microphone sound is silent. */
+ void setSilent(boolean isSilent) {
+ synchronized (mLock) {
+ mIsSilent = isSilent;
+ }
+ }
+
+ /**
+ * Sets the {@link AudioTrack} to handle audio injection.
+ * Callers may call this multiple times with different audio tracks to change
+ * the underlying {@link AudioTrack} without stopping and re-starting injection.
+ *
+ * @param audioTrack The underlying {@link AudioTrack} to use for injection,
+ * or null if no audio (i.e. silence) should be injected while still keeping the
+ * record in a playing state.
+ */
+ void setAudioTrack(@Nullable AudioTrack audioTrack) {
+ Log.d(TAG, "set AudioTrack with " + audioTrack);
+ synchronized (mLock) {
+ // Release old reference.
+ if (mAudioTrack != null) {
+ mAudioTrack.release();
+ }
+ // Sync play state for new reference.
+ if (audioTrack != null) {
+ if (mPlayState == PLAYSTATE_PLAYING
+ && audioTrack.getPlayState() != PLAYSTATE_PLAYING) {
+ audioTrack.play();
+ }
+ if (mPlayState == PLAYSTATE_STOPPED
+ && audioTrack.getPlayState() != PLAYSTATE_STOPPED) {
+ audioTrack.stop();
+ }
+ }
+ mAudioTrack = audioTrack;
+ }
+ }
+
+ /** See {@link AudioTrack#write(ByteBuffer, int, int)}. */
+ public int write(@NonNull ByteBuffer audioBuffer, int sizeInBytes, int writeMode) {
+ final int sizeWrite;
+ synchronized (mLock) {
+ if (mAudioTrack != null && !mIsSilent) {
+ sizeWrite = mAudioTrack.write(audioBuffer, sizeInBytes, writeMode);
+ } else {
+ sizeWrite = 0;
+ }
+ }
+ return sizeWrite;
+ }
+
+ /** See {@link AudioTrack#play()}. */
+ public void play() {
+ synchronized (mLock) {
+ mPlayState = PLAYSTATE_PLAYING;
+ if (mAudioTrack != null && mAudioTrack.getPlayState() != PLAYSTATE_PLAYING) {
+ mAudioTrack.play();
+ }
+ }
+ }
+
+ /** See {@link AudioTrack#stop()}. */
+ public void stop() {
+ synchronized (mLock) {
+ mPlayState = PLAYSTATE_STOPPED;
+ if (mAudioTrack != null && mAudioTrack.getPlayState() != PLAYSTATE_STOPPED) {
+ mAudioTrack.stop();
+ }
+ }
+ }
+
+ /** See {@link AudioTrack#getPlayState()}. */
+ public int getPlayState() {
+ synchronized (mLock) {
+ return mPlayState;
+ }
+ }
+}
diff --git a/core/java/android/companion/virtual/audio/IAudioSessionCallback.aidl b/core/java/android/companion/virtual/audio/IAudioSessionCallback.aidl
new file mode 100644
index 0000000..e22ce14
--- /dev/null
+++ b/core/java/android/companion/virtual/audio/IAudioSessionCallback.aidl
@@ -0,0 +1,44 @@
+/*
+ * 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.companion.virtual.audio;
+
+import android.media.AudioPlaybackConfiguration;
+import android.media.AudioRecordingConfiguration;
+
+/**
+ * Callback to control audio rerouting, notify playback and recording state of applications running
+ * on virtual device.
+ *
+ * @hide
+ */
+oneway interface IAudioSessionCallback {
+
+ /** Updates the set of applications that need to have their audio rerouted. */
+ void onAppsNeedingAudioRoutingChanged(in int[] appUids);
+
+ /**
+ * Called whenever the playback configuration of applications running on virtual device has
+ * changed.
+ */
+ void onPlaybackConfigChanged(in List<AudioPlaybackConfiguration> configs);
+
+ /**
+ * Called whenever the recording configuration of applications running on virtual device has
+ * changed.
+ */
+ void onRecordingConfigChanged(in List<AudioRecordingConfiguration> configs);
+}
diff --git a/core/java/android/companion/virtual/audio/UserRestrictionsDetector.java b/core/java/android/companion/virtual/audio/UserRestrictionsDetector.java
new file mode 100644
index 0000000..5c246d3
--- /dev/null
+++ b/core/java/android/companion/virtual/audio/UserRestrictionsDetector.java
@@ -0,0 +1,96 @@
+/*
+ * 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.companion.virtual.audio;
+
+import android.annotation.NonNull;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.os.UserManager;
+
+import com.android.internal.annotations.GuardedBy;
+
+/**
+ * Class to detect the user restrictions change for microphone usage.
+ */
+final class UserRestrictionsDetector extends BroadcastReceiver {
+ private static final String TAG = "UserRestrictionsDetector";
+
+ /** Interface for listening user restrictions change. */
+ interface UserRestrictionsCallback {
+
+ /** Notifies when value of {@link UserManager#DISALLOW_UNMUTE_MICROPHONE} is changed. */
+ void onMicrophoneRestrictionChanged(boolean isUnmuteMicDisallowed);
+ }
+
+ private final Context mContext;
+ private final UserManager mUserManager;
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
+ private boolean mIsUnmuteMicDisallowed;
+ private UserRestrictionsCallback mUserRestrictionsCallback;
+
+ UserRestrictionsDetector(Context context) {
+ mContext = context;
+ mUserManager = context.getSystemService(UserManager.class);
+ }
+
+ /** Returns value of {@link UserManager#DISALLOW_UNMUTE_MICROPHONE}. */
+ boolean isUnmuteMicrophoneDisallowed() {
+ Bundle bundle = mUserManager.getUserRestrictions();
+ return bundle.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE);
+ }
+
+ /** Registers user restrictions change. */
+ void register(@NonNull UserRestrictionsCallback callback) {
+ mUserRestrictionsCallback = callback;
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(UserManager.ACTION_USER_RESTRICTIONS_CHANGED);
+ mContext.registerReceiver(/* receiver= */ this, filter);
+
+ synchronized (mLock) {
+ // Gets initial value.
+ mIsUnmuteMicDisallowed = isUnmuteMicrophoneDisallowed();
+ }
+ }
+
+ /** Unregisters user restrictions change. */
+ void unregister() {
+ mUserRestrictionsCallback = null;
+ mContext.unregisterReceiver(/* receiver= */ this);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (UserManager.ACTION_USER_RESTRICTIONS_CHANGED.equals(action)) {
+ boolean isUnmuteMicDisallowed = isUnmuteMicrophoneDisallowed();
+ synchronized (mLock) {
+ if (isUnmuteMicDisallowed == mIsUnmuteMicDisallowed) {
+ return;
+ }
+ mIsUnmuteMicDisallowed = isUnmuteMicDisallowed;
+ }
+ if (mUserRestrictionsCallback != null) {
+ mUserRestrictionsCallback.onMicrophoneRestrictionChanged(isUnmuteMicDisallowed);
+ }
+ }
+ }
+}
diff --git a/core/java/android/companion/virtual/audio/VirtualAudioDevice.java b/core/java/android/companion/virtual/audio/VirtualAudioDevice.java
new file mode 100644
index 0000000..38e37ec
--- /dev/null
+++ b/core/java/android/companion/virtual/audio/VirtualAudioDevice.java
@@ -0,0 +1,167 @@
+/*
+ * 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.companion.virtual.audio;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.companion.virtual.IVirtualDevice;
+import android.content.Context;
+import android.hardware.display.VirtualDisplay;
+import android.media.AudioFormat;
+import android.media.AudioPlaybackConfiguration;
+import android.media.AudioRecordingConfiguration;
+import android.os.RemoteException;
+
+import java.io.Closeable;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * The class stores an {@link AudioCapture} for audio capturing and an {@link AudioInjection} for
+ * audio injection.
+ *
+ * @hide
+ */
+@SystemApi
+public final class VirtualAudioDevice implements Closeable {
+
+ /**
+ * Interface to be notified when playback or recording configuration of applications running on
+ * virtual display was changed.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface AudioConfigurationChangeCallback {
+ /**
+ * Notifies when playback configuration of applications running on virtual display was
+ * changed.
+ */
+ void onPlaybackConfigChanged(@NonNull List<AudioPlaybackConfiguration> configs);
+
+ /**
+ * Notifies when recording configuration of applications running on virtual display was
+ * changed.
+ */
+ void onRecordingConfigChanged(@NonNull List<AudioRecordingConfiguration> configs);
+ }
+
+ private final Context mContext;
+ private final IVirtualDevice mVirtualDevice;
+ private final VirtualDisplay mVirtualDisplay;
+ private final AudioConfigurationChangeCallback mCallback;
+ private final Executor mExecutor;
+ @Nullable
+ private VirtualAudioSession mOngoingSession;
+
+ /**
+ * @hide
+ */
+ public VirtualAudioDevice(Context context, IVirtualDevice virtualDevice,
+ VirtualDisplay virtualDisplay, Executor executor,
+ AudioConfigurationChangeCallback callback) {
+ mContext = context;
+ mVirtualDevice = virtualDevice;
+ mVirtualDisplay = virtualDisplay;
+ mExecutor = executor;
+ mCallback = callback;
+ }
+
+ /**
+ * Begins injecting audio from a remote device into this device.
+ *
+ * @return An {@link AudioInjection} containing the injected audio.
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @NonNull
+ public AudioInjection startAudioInjection(@NonNull AudioFormat injectionFormat) {
+ Objects.requireNonNull(injectionFormat, "injectionFormat must not be null");
+
+ if (mOngoingSession != null && mOngoingSession.getAudioInjection() != null) {
+ throw new IllegalStateException("Cannot start an audio injection while a session is "
+ + "ongoing. Call close() on this device first to end the previous injection.");
+ }
+ if (mOngoingSession == null) {
+ mOngoingSession = new VirtualAudioSession(mContext, mCallback, mExecutor);
+ }
+
+ try {
+ mVirtualDevice.onAudioSessionStarting(mVirtualDisplay.getDisplay().getDisplayId(),
+ /* callback= */ mOngoingSession);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ return mOngoingSession.startAudioInjection(injectionFormat);
+ }
+
+ /**
+ * Begins recording audio emanating from this device.
+ *
+ * @return An {@link AudioCapture} containing the recorded audio.
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @NonNull
+ public AudioCapture startAudioCapture(@NonNull AudioFormat captureFormat) {
+ Objects.requireNonNull(captureFormat, "captureFormat must not be null");
+
+ if (mOngoingSession != null && mOngoingSession.getAudioCapture() != null) {
+ throw new IllegalStateException("Cannot start an audio capture while a session is "
+ + "ongoing. Call close() on this device first to end the previous session.");
+ }
+ if (mOngoingSession == null) {
+ mOngoingSession = new VirtualAudioSession(mContext, mCallback, mExecutor);
+ }
+
+ try {
+ mVirtualDevice.onAudioSessionStarting(mVirtualDisplay.getDisplay().getDisplayId(),
+ /* callback= */ mOngoingSession);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ return mOngoingSession.startAudioCapture(captureFormat);
+ }
+
+ /** Returns the {@link AudioCapture} instance. */
+ @Nullable
+ public AudioCapture getAudioCapture() {
+ return mOngoingSession != null ? mOngoingSession.getAudioCapture() : null;
+ }
+
+ /** Returns the {@link AudioInjection} instance. */
+ @Nullable
+ public AudioInjection getAudioInjection() {
+ return mOngoingSession != null ? mOngoingSession.getAudioInjection() : null;
+ }
+
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @Override
+ public void close() {
+ if (mOngoingSession != null) {
+ mOngoingSession.close();
+ mOngoingSession = null;
+
+ try {
+ mVirtualDevice.onAudioSessionEnded();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+}
diff --git a/core/java/android/companion/virtual/audio/VirtualAudioSession.java b/core/java/android/companion/virtual/audio/VirtualAudioSession.java
new file mode 100644
index 0000000..bc71bd6
--- /dev/null
+++ b/core/java/android/companion/virtual/audio/VirtualAudioSession.java
@@ -0,0 +1,319 @@
+/*
+ * 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.companion.virtual.audio;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.companion.virtual.audio.UserRestrictionsDetector.UserRestrictionsCallback;
+import android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChangeCallback;
+import android.content.Context;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioPlaybackConfiguration;
+import android.media.AudioRecord;
+import android.media.AudioRecordingConfiguration;
+import android.media.AudioTrack;
+import android.media.audiopolicy.AudioMix;
+import android.media.audiopolicy.AudioMixingRule;
+import android.media.audiopolicy.AudioPolicy;
+import android.util.IntArray;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.Closeable;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * Manages an ongiong audio session in which audio can be captured (recorded) and/or
+ * injected from a remote device.
+ *
+ * @hide
+ */
+@VisibleForTesting
+public final class VirtualAudioSession extends IAudioSessionCallback.Stub implements
+ UserRestrictionsCallback, Closeable {
+ private static final String TAG = "VirtualAudioSession";
+
+ private final Context mContext;
+ private final UserRestrictionsDetector mUserRestrictionsDetector;
+ /** The {@link Executor} for sending {@link AudioConfigurationChangeCallback} to the caller */
+ private final Executor mExecutor;
+ @Nullable
+ private final AudioConfigurationChangeCallback mCallback;
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
+ private final IntArray mReroutedAppUids = new IntArray();
+ @Nullable
+ @GuardedBy("mLock")
+ private AudioPolicy mAudioPolicy;
+ @Nullable
+ @GuardedBy("mLock")
+ private AudioFormat mCaptureFormat;
+ @Nullable
+ @GuardedBy("mLock")
+ private AudioFormat mInjectionFormat;
+ @Nullable
+ @GuardedBy("mLock")
+ private AudioCapture mAudioCapture;
+ @Nullable
+ @GuardedBy("mLock")
+ private AudioInjection mAudioInjection;
+
+ @VisibleForTesting
+ public VirtualAudioSession(Context context,
+ @Nullable AudioConfigurationChangeCallback callback, @Nullable Executor executor) {
+ mContext = context;
+ mUserRestrictionsDetector = new UserRestrictionsDetector(context);
+ mCallback = callback;
+ mExecutor = executor != null ? executor : context.getMainExecutor();
+ }
+
+ /**
+ * Begins recording audio emanating from this device.
+ *
+ * @return An {@link AudioCapture} containing the recorded audio.
+ */
+ @VisibleForTesting
+ @NonNull
+ public AudioCapture startAudioCapture(@NonNull AudioFormat captureFormat) {
+ Objects.requireNonNull(captureFormat, "captureFormat must not be null");
+
+ synchronized (mLock) {
+ if (mAudioCapture != null) {
+ throw new IllegalStateException(
+ "Cannot start capture while another capture is ongoing.");
+ }
+
+ mCaptureFormat = captureFormat;
+ mAudioCapture = new AudioCapture();
+ mAudioCapture.startRecording();
+ return mAudioCapture;
+ }
+ }
+
+ /**
+ * Begins injecting audio from a remote device into this device.
+ *
+ * @return An {@link AudioInjection} containing the injected audio.
+ */
+ @VisibleForTesting
+ @NonNull
+ public AudioInjection startAudioInjection(@NonNull AudioFormat injectionFormat) {
+ Objects.requireNonNull(injectionFormat, "injectionFormat must not be null");
+ mUserRestrictionsDetector.register(/* callback= */ this);
+ synchronized (mLock) {
+ if (mAudioInjection != null) {
+ throw new IllegalStateException(
+ "Cannot start injection while injection is already ongoing.");
+ }
+
+ mInjectionFormat = injectionFormat;
+ mAudioInjection = new AudioInjection();
+ mAudioInjection.play();
+ mAudioInjection.setSilent(mUserRestrictionsDetector.isUnmuteMicrophoneDisallowed());
+ return mAudioInjection;
+ }
+ }
+
+ /** @hide */
+ @VisibleForTesting
+ @Nullable
+ public AudioCapture getAudioCapture() {
+ synchronized (mLock) {
+ return mAudioCapture;
+ }
+ }
+
+ /** @hide */
+ @VisibleForTesting
+ @Nullable
+ public AudioInjection getAudioInjection() {
+ synchronized (mLock) {
+ return mAudioInjection;
+ }
+ }
+
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @Override
+ public void onAppsNeedingAudioRoutingChanged(int[] appUids) {
+ synchronized (mLock) {
+ if (Arrays.equals(mReroutedAppUids.toArray(), appUids)) {
+ return;
+ }
+ }
+
+ releaseAudioStreams();
+
+ if (appUids.length == 0) {
+ return;
+ }
+
+ createAudioStreams(appUids);
+ }
+
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @Override
+ public void close() {
+ mUserRestrictionsDetector.unregister();
+ releaseAudioStreams();
+ synchronized (mLock) {
+ mAudioCapture = null;
+ mAudioInjection = null;
+ mCaptureFormat = null;
+ mInjectionFormat = null;
+ }
+ }
+
+ @Override
+ public void onMicrophoneRestrictionChanged(boolean isUnmuteMicDisallowed) {
+ synchronized (mLock) {
+ if (mAudioInjection != null) {
+ mAudioInjection.setSilent(isUnmuteMicDisallowed);
+ }
+ }
+ }
+
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ private void createAudioStreams(int[] appUids) {
+ synchronized (mLock) {
+ if (mCaptureFormat == null && mInjectionFormat == null) {
+ throw new IllegalStateException(
+ "At least one of captureFormat and injectionFormat must be specified.");
+ }
+ if (mAudioPolicy != null) {
+ throw new IllegalStateException(
+ "Cannot create audio streams while the audio policy is registered. Call "
+ + "releaseAudioStreams() first to unregister the previous audio "
+ + "policy."
+ );
+ }
+
+ mReroutedAppUids.clear();
+ for (int appUid : appUids) {
+ mReroutedAppUids.add(appUid);
+ }
+
+ AudioMix audioRecordMix = null;
+ AudioMix audioTrackMix = null;
+ AudioPolicy.Builder builder = new AudioPolicy.Builder(mContext);
+ if (mCaptureFormat != null) {
+ audioRecordMix = createAudioRecordMix(mCaptureFormat, appUids);
+ builder.addMix(audioRecordMix);
+ }
+ if (mInjectionFormat != null) {
+ audioTrackMix = createAudioTrackMix(mInjectionFormat, appUids);
+ builder.addMix(audioTrackMix);
+ }
+ mAudioPolicy = builder.build();
+ AudioManager audioManager = mContext.getSystemService(AudioManager.class);
+ if (audioManager.registerAudioPolicy(mAudioPolicy) == AudioManager.ERROR) {
+ Log.e(TAG, "Failed to register audio policy!");
+ }
+
+ AudioRecord audioRecord =
+ audioRecordMix != null ? mAudioPolicy.createAudioRecordSink(audioRecordMix)
+ : null;
+ AudioTrack audioTrack =
+ audioTrackMix != null ? mAudioPolicy.createAudioTrackSource(audioTrackMix)
+ : null;
+
+ if (mAudioCapture != null) {
+ mAudioCapture.setAudioRecord(audioRecord);
+ }
+ if (mAudioInjection != null) {
+ mAudioInjection.setAudioTrack(audioTrack);
+ }
+ }
+ }
+
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ private void releaseAudioStreams() {
+ synchronized (mLock) {
+ if (mAudioCapture != null) {
+ mAudioCapture.setAudioRecord(null);
+ }
+ if (mAudioInjection != null) {
+ mAudioInjection.setAudioTrack(null);
+ }
+ mReroutedAppUids.clear();
+ if (mAudioPolicy != null) {
+ AudioManager audioManager = mContext.getSystemService(AudioManager.class);
+ audioManager.unregisterAudioPolicy(mAudioPolicy);
+ mAudioPolicy = null;
+ Log.i(TAG, "AudioPolicy unregistered");
+ }
+ }
+ }
+
+ @Override
+ public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {
+ if (mCallback != null) {
+ mExecutor.execute(() -> mCallback.onPlaybackConfigChanged(configs));
+ }
+ }
+
+ @Override
+ public void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs) {
+ if (mCallback != null) {
+ mExecutor.execute(() -> mCallback.onRecordingConfigChanged(configs));
+ }
+ }
+
+ /** @hide */
+ @VisibleForTesting
+ public IntArray getReroutedAppUids() {
+ synchronized (mLock) {
+ return mReroutedAppUids;
+ }
+ }
+
+ private static AudioMix createAudioRecordMix(@NonNull AudioFormat audioFormat, int[] appUids) {
+ AudioMixingRule.Builder builder = new AudioMixingRule.Builder();
+ builder.setTargetMixRole(AudioMixingRule.MIX_ROLE_PLAYERS);
+ for (int uid : appUids) {
+ builder.addMixRule(AudioMixingRule.RULE_MATCH_UID, uid);
+ }
+ AudioMixingRule audioMixingRule = builder.allowPrivilegedPlaybackCapture(false).build();
+ AudioMix audioMix =
+ new AudioMix.Builder(audioMixingRule)
+ .setFormat(audioFormat)
+ .setRouteFlags(AudioMix.ROUTE_FLAG_LOOP_BACK)
+ .build();
+ return audioMix;
+ }
+
+ private static AudioMix createAudioTrackMix(@NonNull AudioFormat audioFormat, int[] appUids) {
+ AudioMixingRule.Builder builder = new AudioMixingRule.Builder();
+ builder.setTargetMixRole(AudioMixingRule.MIX_ROLE_INJECTOR);
+ for (int uid : appUids) {
+ builder.addMixRule(AudioMixingRule.RULE_MATCH_UID, uid);
+ }
+ AudioMixingRule audioMixingRule = builder.build();
+ AudioMix audioMix =
+ new AudioMix.Builder(audioMixingRule)
+ .setFormat(audioFormat)
+ .setRouteFlags(AudioMix.ROUTE_FLAG_LOOP_BACK)
+ .build();
+ return audioMix;
+ }
+}
diff --git a/core/java/android/content/AsyncTaskLoader.java b/core/java/android/content/AsyncTaskLoader.java
index 14c3387..3e544b2 100644
--- a/core/java/android/content/AsyncTaskLoader.java
+++ b/core/java/android/content/AsyncTaskLoader.java
@@ -52,7 +52,7 @@
* @param <D> the data type to be loaded.
*
* @deprecated Use the <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>
- * {@link android.support.v4.content.AsyncTaskLoader}
+ * {@link androidx.loader.content.AsyncTaskLoader}
*/
@Deprecated
public abstract class AsyncTaskLoader<D> extends Loader<D> {
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index d46a0c6..2a19d37 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -376,7 +376,7 @@
* to run, allowing them to execute for 30 seconds or even a bit more. This is something that
* receivers should rarely take advantage of (long work should be punted to another system
* facility such as {@link android.app.job.JobScheduler}, {@link android.app.Service}, or
- * see especially {@link android.support.v4.app.JobIntentService}), but can be useful in
+ * see especially {@link androidx.core.app.JobIntentService}), but can be useful in
* certain rare cases where it is necessary to do some work as soon as the broadcast is
* delivered. Keep in mind that the work you do here will block further broadcasts until
* it completes, so taking advantage of this at all excessively can be counter-productive
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 2074125..0fed733 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -36,6 +36,7 @@
import android.annotation.TestApi;
import android.annotation.UiContext;
import android.annotation.UserIdInt;
+import android.app.Activity;
import android.app.ActivityManager;
import android.app.BroadcastOptions;
import android.app.GameManager;
@@ -45,6 +46,8 @@
import android.app.ambientcontext.AmbientContextManager;
import android.app.people.PeopleManager;
import android.app.time.TimeManager;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -85,6 +88,7 @@
import android.view.textclassifier.TextClassificationManager;
import android.window.WindowContext;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.compat.IPlatformCompat;
import com.android.internal.compat.IPlatformCompatNative;
@@ -111,6 +115,19 @@
* broadcasting and receiving intents, etc.
*/
public abstract class Context {
+ /**
+ * After {@link Build.VERSION_CODES#TIRAMISU},
+ * {@link #registerComponentCallbacks(ComponentCallbacks)} will add a {@link ComponentCallbacks}
+ * to {@link Activity} or {@link ContextWrapper#getBaseContext()} instead of always adding to
+ * {@link #getApplicationContext()}.
+ *
+ * @hide
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
+ @VisibleForTesting
+ public static final long OVERRIDABLE_COMPONENT_CALLBACKS = 193247900L;
+
/** @hide */
@IntDef(flag = true, prefix = { "MODE_" }, value = {
MODE_PRIVATE,
@@ -163,7 +180,7 @@
* {@link BroadcastReceiver}, and {@link android.app.Service}.
* There are no guarantees that this access mode will remain on
* a file, such as when it goes through a backup and restore.
- * @see android.support.v4.content.FileProvider
+ * @see androidx.core.content.FileProvider
* @see Intent#FLAG_GRANT_WRITE_URI_PERMISSION
*/
@Deprecated
@@ -183,7 +200,7 @@
* {@link BroadcastReceiver}, and {@link android.app.Service}.
* There are no guarantees that this access mode will remain on
* a file, such as when it goes through a backup and restore.
- * @see android.support.v4.content.FileProvider
+ * @see androidx.core.content.FileProvider
* @see Intent#FLAG_GRANT_WRITE_URI_PERMISSION
*/
@Deprecated
@@ -7058,6 +7075,18 @@
public abstract int getDisplayId();
/**
+ * @return Returns the id of the Display object associated with this Context or
+ * {@link Display#INVALID_DISPLAY} if no Display has been associated.
+ * @see #getDisplay()
+ * @see #getDisplayId()
+ *
+ * @hide
+ */
+ public int getAssociatedDisplayId() {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
+
+ /**
* @hide
*/
@SuppressWarnings("HiddenAbstractMethod")
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 98ced6d..9adf173 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -25,8 +25,6 @@
import android.app.IApplicationThread;
import android.app.IServiceConnection;
import android.app.compat.CompatChanges;
-import android.compat.annotation.ChangeId;
-import android.compat.annotation.EnabledSince;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -74,16 +72,6 @@
Context mBase;
/**
- * After {@link Build.VERSION_CODES#TIRAMISU},
- * {@link #registerComponentCallbacks(ComponentCallbacks)} will delegate to
- * {@link #getBaseContext()} instead of {@link #getApplicationContext()}.
- */
- @ChangeId
- @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
- @VisibleForTesting
- static final long COMPONENT_CALLBACK_ON_WRAPPER = 193247900L;
-
- /**
* A list to store {@link ComponentCallbacks} which
* passes to {@link #registerComponentCallbacks(ComponentCallbacks)} before
* {@link #attachBaseContext(Context)}.
@@ -1355,7 +1343,7 @@
public void registerComponentCallbacks(ComponentCallbacks callback) {
if (mBase != null) {
mBase.registerComponentCallbacks(callback);
- } else if (!CompatChanges.isChangeEnabled(COMPONENT_CALLBACK_ON_WRAPPER)) {
+ } else if (!CompatChanges.isChangeEnabled(OVERRIDABLE_COMPONENT_CALLBACKS)) {
super.registerComponentCallbacks(callback);
synchronized (mLock) {
// Also register ComponentCallbacks to ContextWrapper, so we can find the correct
@@ -1397,7 +1385,7 @@
mCallbacksRegisteredToSuper.remove(callback);
} else if (mBase != null) {
mBase.unregisterComponentCallbacks(callback);
- } else if (CompatChanges.isChangeEnabled(COMPONENT_CALLBACK_ON_WRAPPER)) {
+ } else if (CompatChanges.isChangeEnabled(OVERRIDABLE_COMPONENT_CALLBACKS)) {
// Throw exception for Application that is targeting S-v2+
throw new IllegalStateException("ComponentCallbacks must be unregistered after "
+ "this ContextWrapper is attached to a base Context.");
diff --git a/core/java/android/content/CursorLoader.java b/core/java/android/content/CursorLoader.java
index fda646c..cfb0f95 100644
--- a/core/java/android/content/CursorLoader.java
+++ b/core/java/android/content/CursorLoader.java
@@ -42,7 +42,7 @@
* and {@link #setProjection(String[])}.
*
* @deprecated Use the <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>
- * {@link android.support.v4.content.CursorLoader}
+ * {@link androidx.loader.content.CursorLoader}
*/
@Deprecated
public class CursorLoader extends AsyncTaskLoader<Cursor> {
diff --git a/core/java/android/content/Loader.java b/core/java/android/content/Loader.java
index b0555d4..afd495b 100644
--- a/core/java/android/content/Loader.java
+++ b/core/java/android/content/Loader.java
@@ -50,7 +50,7 @@
* @param <D> The result returned when the load is complete
*
* @deprecated Use the <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>
- * {@link android.support.v4.content.Loader}
+ * {@link androidx.loader.content.Loader}
*/
@Deprecated
public class Loader<D> {
@@ -71,7 +71,7 @@
* it is used for you by {@link CursorLoader} to take care of executing
* an update when the cursor's backing data changes.
*
- * @deprecated Use {@link android.support.v4.content.Loader.ForceLoadContentObserver}
+ * @deprecated Use {@link androidx.loader.content.Loader.ForceLoadContentObserver}
*/
@Deprecated
public final class ForceLoadContentObserver extends ContentObserver {
@@ -98,7 +98,7 @@
* be reported to its client. This interface should only be used if a
* Loader is not being used in conjunction with LoaderManager.
*
- * @deprecated Use {@link android.support.v4.content.Loader.OnLoadCompleteListener}
+ * @deprecated Use {@link androidx.loader.content.Loader.OnLoadCompleteListener}
*/
@Deprecated
public interface OnLoadCompleteListener<D> {
@@ -119,7 +119,7 @@
* can schedule the next Loader. This interface should only be used if a
* Loader is not being used in conjunction with LoaderManager.
*
- * @deprecated Use {@link android.support.v4.content.Loader.OnLoadCanceledListener}
+ * @deprecated Use {@link androidx.loader.content.Loader.OnLoadCanceledListener}
*/
@Deprecated
public interface OnLoadCanceledListener<D> {
diff --git a/core/java/android/content/integrity/AppInstallMetadata.java b/core/java/android/content/integrity/AppInstallMetadata.java
index 4f38fae..9874890 100644
--- a/core/java/android/content/integrity/AppInstallMetadata.java
+++ b/core/java/android/content/integrity/AppInstallMetadata.java
@@ -37,6 +37,8 @@
private final String mPackageName;
// Raw string encoding for the SHA-256 hash of the certificate of the app.
private final List<String> mAppCertificates;
+ // Raw string encoding for the SHA-256 hash of the certificate lineage/history of the app.
+ private final List<String> mAppCertificateLineage;
private final String mInstallerName;
// Raw string encoding for the SHA-256 hash of the certificate of the installer.
private final List<String> mInstallerCertificates;
@@ -52,6 +54,7 @@
private AppInstallMetadata(Builder builder) {
this.mPackageName = builder.mPackageName;
this.mAppCertificates = builder.mAppCertificates;
+ this.mAppCertificateLineage = builder.mAppCertificateLineage;
this.mInstallerName = builder.mInstallerName;
this.mInstallerCertificates = builder.mInstallerCertificates;
this.mVersionCode = builder.mVersionCode;
@@ -74,6 +77,11 @@
}
@NonNull
+ public List<String> getAppCertificateLineage() {
+ return mAppCertificateLineage;
+ }
+
+ @NonNull
public String getInstallerName() {
return mInstallerName;
}
@@ -126,6 +134,7 @@
+ " %b, StampVerified = %b, StampTrusted = %b, StampCert = %s }",
mPackageName,
mAppCertificates,
+ mAppCertificateLineage,
mInstallerName == null ? "null" : mInstallerName,
mInstallerCertificates == null ? "null" : mInstallerCertificates,
mVersionCode,
@@ -140,6 +149,7 @@
public static final class Builder {
private String mPackageName;
private List<String> mAppCertificates;
+ private List<String> mAppCertificateLineage;
private String mInstallerName;
private List<String> mInstallerCertificates;
private long mVersionCode;
@@ -192,6 +202,20 @@
}
/**
+ * Set the list of (old and new) certificates used for signing the app to be installed.
+ *
+ * <p>It is represented as the raw string encoding for the SHA-256 hash of the certificate
+ * lineage/history of the app.
+ *
+ * @see AppInstallMetadata#getAppCertificateLineage()
+ */
+ @NonNull
+ public Builder setAppCertificateLineage(@NonNull List<String> appCertificateLineage) {
+ this.mAppCertificateLineage = Objects.requireNonNull(appCertificateLineage);
+ return this;
+ }
+
+ /**
* Set name of the installer installing the app.
*
* @see AppInstallMetadata#getInstallerName()
@@ -294,6 +318,7 @@
public AppInstallMetadata build() {
Objects.requireNonNull(mPackageName);
Objects.requireNonNull(mAppCertificates);
+ Objects.requireNonNull(mAppCertificateLineage);
return new AppInstallMetadata(this);
}
}
diff --git a/core/java/android/content/integrity/AtomicFormula.java b/core/java/android/content/integrity/AtomicFormula.java
index e359800..f888813 100644
--- a/core/java/android/content/integrity/AtomicFormula.java
+++ b/core/java/android/content/integrity/AtomicFormula.java
@@ -56,6 +56,7 @@
PRE_INSTALLED,
STAMP_TRUSTED,
STAMP_CERTIFICATE_HASH,
+ APP_CERTIFICATE_LINEAGE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface Key {}
@@ -122,6 +123,13 @@
*/
public static final int STAMP_CERTIFICATE_HASH = 7;
+ /**
+ * SHA-256 of a certificate in the signing lineage of the app.
+ *
+ * <p>Can only be used in {@link StringAtomicFormula}.
+ */
+ public static final int APP_CERTIFICATE_LINEAGE = 8;
+
public static final int EQ = 0;
public static final int GT = 1;
public static final int GTE = 2;
@@ -225,6 +233,11 @@
}
@Override
+ public boolean isAppCertificateLineageFormula() {
+ return false;
+ }
+
+ @Override
public boolean isInstallerFormula() {
return false;
}
@@ -314,7 +327,8 @@
|| key == APP_CERTIFICATE
|| key == INSTALLER_CERTIFICATE
|| key == INSTALLER_NAME
- || key == STAMP_CERTIFICATE_HASH,
+ || key == STAMP_CERTIFICATE_HASH
+ || key == APP_CERTIFICATE_LINEAGE,
"Key %s cannot be used with StringAtomicFormula", keyToString(key));
mValue = null;
mIsHashedValue = null;
@@ -335,7 +349,8 @@
|| key == APP_CERTIFICATE
|| key == INSTALLER_CERTIFICATE
|| key == INSTALLER_NAME
- || key == STAMP_CERTIFICATE_HASH,
+ || key == STAMP_CERTIFICATE_HASH
+ || key == APP_CERTIFICATE_LINEAGE,
"Key %s cannot be used with StringAtomicFormula", keyToString(key));
mValue = value;
mIsHashedValue = isHashed;
@@ -348,8 +363,9 @@
* <p>The value will be automatically hashed with SHA256 and the hex digest will be computed
* when the key is PACKAGE_NAME or INSTALLER_NAME and the value is more than 32 characters.
*
- * <p>The APP_CERTIFICATES, INSTALLER_CERTIFICATES, and STAMP_CERTIFICATE_HASH are always
- * delivered in hashed form. So the isHashedValue is set to true by default.
+ * <p>The APP_CERTIFICATES, INSTALLER_CERTIFICATES, STAMP_CERTIFICATE_HASH and
+ * APP_CERTIFICATE_LINEAGE are always delivered in hashed form. So the isHashedValue is set
+ * to true by default.
*
* @throws IllegalArgumentException if {@code key} cannot be used with string value.
*/
@@ -360,13 +376,15 @@
|| key == APP_CERTIFICATE
|| key == INSTALLER_CERTIFICATE
|| key == INSTALLER_NAME
- || key == STAMP_CERTIFICATE_HASH,
+ || key == STAMP_CERTIFICATE_HASH
+ || key == APP_CERTIFICATE_LINEAGE,
"Key %s cannot be used with StringAtomicFormula", keyToString(key));
mValue = hashValue(key, value);
mIsHashedValue =
(key == APP_CERTIFICATE
|| key == INSTALLER_CERTIFICATE
- || key == STAMP_CERTIFICATE_HASH)
+ || key == STAMP_CERTIFICATE_HASH
+ || key == APP_CERTIFICATE_LINEAGE)
|| !mValue.equals(value);
}
@@ -409,6 +427,11 @@
}
@Override
+ public boolean isAppCertificateLineageFormula() {
+ return getKey() == APP_CERTIFICATE_LINEAGE;
+ }
+
+ @Override
public boolean isInstallerFormula() {
return getKey() == INSTALLER_NAME || getKey() == INSTALLER_CERTIFICATE;
}
@@ -474,6 +497,8 @@
return Collections.singletonList(appInstallMetadata.getInstallerName());
case AtomicFormula.STAMP_CERTIFICATE_HASH:
return Collections.singletonList(appInstallMetadata.getStampCertificateHash());
+ case AtomicFormula.APP_CERTIFICATE_LINEAGE:
+ return appInstallMetadata.getAppCertificateLineage();
default:
throw new IllegalStateException(
"Unexpected key in StringAtomicFormula: " + key);
@@ -577,6 +602,11 @@
}
@Override
+ public boolean isAppCertificateLineageFormula() {
+ return false;
+ }
+
+ @Override
public boolean isInstallerFormula() {
return false;
}
@@ -660,6 +690,8 @@
return "STAMP_TRUSTED";
case STAMP_CERTIFICATE_HASH:
return "STAMP_CERTIFICATE_HASH";
+ case APP_CERTIFICATE_LINEAGE:
+ return "APP_CERTIFICATE_LINEAGE";
default:
throw new IllegalArgumentException("Unknown key " + key);
}
@@ -686,6 +718,7 @@
|| key == INSTALLER_CERTIFICATE
|| key == PRE_INSTALLED
|| key == STAMP_TRUSTED
- || key == STAMP_CERTIFICATE_HASH;
+ || key == STAMP_CERTIFICATE_HASH
+ || key == APP_CERTIFICATE_LINEAGE;
}
}
diff --git a/core/java/android/content/integrity/CompoundFormula.java b/core/java/android/content/integrity/CompoundFormula.java
index 1ffabd0..23ee1d9 100644
--- a/core/java/android/content/integrity/CompoundFormula.java
+++ b/core/java/android/content/integrity/CompoundFormula.java
@@ -137,6 +137,11 @@
}
@Override
+ public boolean isAppCertificateLineageFormula() {
+ return getFormulas().stream().anyMatch(formula -> formula.isAppCertificateLineageFormula());
+ }
+
+ @Override
public boolean isInstallerFormula() {
return getFormulas().stream().anyMatch(formula -> formula.isInstallerFormula());
}
diff --git a/core/java/android/content/integrity/InstallerAllowedByManifestFormula.java b/core/java/android/content/integrity/InstallerAllowedByManifestFormula.java
index 9d37299..5bcbef6 100644
--- a/core/java/android/content/integrity/InstallerAllowedByManifestFormula.java
+++ b/core/java/android/content/integrity/InstallerAllowedByManifestFormula.java
@@ -73,6 +73,11 @@
}
@Override
+ public boolean isAppCertificateLineageFormula() {
+ return false;
+ }
+
+ @Override
public boolean isInstallerFormula() {
return true;
}
diff --git a/core/java/android/content/integrity/IntegrityFormula.java b/core/java/android/content/integrity/IntegrityFormula.java
index d965ef5..9e2a332 100644
--- a/core/java/android/content/integrity/IntegrityFormula.java
+++ b/core/java/android/content/integrity/IntegrityFormula.java
@@ -49,14 +49,23 @@
}
/**
- * Returns an integrity formula that checks if the app certificates contain {@code
- * appCertificate}.
+ * Returns an integrity formula that checks if the app certificates contain the string
+ * provided by the appCertificate parameter.
*/
@NonNull
public static IntegrityFormula certificatesContain(@NonNull String appCertificate) {
return new StringAtomicFormula(AtomicFormula.APP_CERTIFICATE, appCertificate);
}
+ /**
+ * Returns an integrity formula that checks if the app certificate lineage contains the
+ * string provided by the appCertificate parameter.
+ */
+ @NonNull
+ public static IntegrityFormula certificateLineageContains(@NonNull String appCertificate) {
+ return new StringAtomicFormula(AtomicFormula.APP_CERTIFICATE_LINEAGE, appCertificate);
+ }
+
/** Returns an integrity formula that checks the equality to a version code. */
@NonNull
public static IntegrityFormula versionCodeEquals(@NonNull long versionCode) {
@@ -187,6 +196,14 @@
public abstract boolean isAppCertificateFormula();
/**
+ * Returns true when the formula (or one of its atomic formulas) has app certificate lineage as
+ * key.
+ *
+ * @hide
+ */
+ public abstract boolean isAppCertificateLineageFormula();
+
+ /**
* Returns true when the formula (or one of its atomic formulas) has installer package name or
* installer certificate as key.
*
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 8bea006..0673b3a 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -18,6 +18,8 @@
import android.annotation.FloatRange;
import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.TestApi;
import android.app.Activity;
import android.app.compat.CompatChanges;
@@ -35,10 +37,16 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
+import android.util.ArraySet;
import android.util.Printer;
+import com.android.internal.util.Parcelling;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Collections;
+import java.util.Locale;
+import java.util.Set;
/**
* Information you can retrieve about a particular application
@@ -48,6 +56,9 @@
*/
public class ActivityInfo extends ComponentInfo implements Parcelable {
+ private static final Parcelling.BuiltIn.ForStringSet sForStringSet =
+ Parcelling.Cache.getOrCreate(Parcelling.BuiltIn.ForStringSet.class);
+
// NOTE: When adding new data members be sure to update the copy-constructor, Parcel
// constructor, and writeToParcel.
@@ -525,6 +536,13 @@
public static final int FLAG_PREFER_MINIMAL_POST_PROCESSING = 0x2000000;
/**
+ * Bit in {@link #flags}: If set, indicates that the activity can be embedded by untrusted
+ * hosts. In this case the interactions with and visibility of the embedded activity may be
+ * limited. Set from the {@link android.R.attr#allowUntrustedActivityEmbedding} attribute.
+ */
+ public static final int FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING = 0x10000000;
+
+ /**
* @hide Bit in {@link #flags}: If set, this component will only be seen
* by the system user. Only works with broadcast receivers. Set from the
* android.R.attr#systemUserOnly attribute.
@@ -561,7 +579,8 @@
* {@link #FLAG_STATE_NOT_NEEDED}, {@link #FLAG_EXCLUDE_FROM_RECENTS},
* {@link #FLAG_ALLOW_TASK_REPARENTING}, {@link #FLAG_NO_HISTORY},
* {@link #FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS},
- * {@link #FLAG_HARDWARE_ACCELERATED}, {@link #FLAG_SINGLE_USER}.
+ * {@link #FLAG_HARDWARE_ACCELERATED}, {@link #FLAG_SINGLE_USER},
+ * {@link #FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING}.
*/
public int flags;
@@ -1080,6 +1099,13 @@
private static final long CHECK_MIN_WIDTH_HEIGHT_FOR_MULTI_WINDOW = 197654537L;
/**
+ * Optional set of a certificates identifying apps that are allowed to embed this activity. From
+ * the "knownActivityEmbeddingCerts" attribute.
+ */
+ @Nullable
+ private Set<String> mKnownActivityEmbeddingCerts;
+
+ /**
* Convert Java change bits to native.
*
* @hide
@@ -1227,6 +1253,7 @@
launchMode = orig.launchMode;
documentLaunchMode = orig.documentLaunchMode;
permission = orig.permission;
+ mKnownActivityEmbeddingCerts = orig.mKnownActivityEmbeddingCerts;
taskAffinity = orig.taskAffinity;
targetActivity = orig.targetActivity;
flags = orig.flags;
@@ -1442,6 +1469,31 @@
return mMinAspectRatio;
}
+ /**
+ * Gets the trusted host certificate digests of apps that are allowed to embed this activity.
+ * The digests are computed using the SHA-256 digest algorithm.
+ * @see android.R.attr#knownActivityEmbeddingCerts
+ */
+ @NonNull
+ public Set<String> getKnownActivityEmbeddingCerts() {
+ return mKnownActivityEmbeddingCerts == null ? Collections.emptySet()
+ : mKnownActivityEmbeddingCerts;
+ }
+
+ /**
+ * Sets the trusted host certificates of apps that are allowed to embed this activity.
+ * @see #getKnownActivityEmbeddingCerts()
+ * @hide
+ */
+ public void setKnownActivityEmbeddingCerts(@NonNull Set<String> knownActivityEmbeddingCerts) {
+ // Convert the provided digest to upper case for consistent Set membership
+ // checks when verifying the signing certificate digests of requesting apps.
+ mKnownActivityEmbeddingCerts = new ArraySet<>();
+ for (String knownCert : knownActivityEmbeddingCerts) {
+ mKnownActivityEmbeddingCerts.add(knownCert.toUpperCase(Locale.US));
+ }
+ }
+
private boolean isChangeEnabled(long changeId) {
return CompatChanges.isChangeEnabled(changeId, applicationInfo.packageName,
UserHandle.getUserHandleForUid(applicationInfo.uid));
@@ -1573,6 +1625,9 @@
if (supportsSizeChanges) {
pw.println(prefix + "supportsSizeChanges=true");
}
+ if (mKnownActivityEmbeddingCerts != null) {
+ pw.println(prefix + "knownActivityEmbeddingCerts=" + mKnownActivityEmbeddingCerts);
+ }
super.dumpBack(pw, prefix, dumpFlags);
}
@@ -1618,6 +1673,7 @@
dest.writeFloat(mMaxAspectRatio);
dest.writeFloat(mMinAspectRatio);
dest.writeBoolean(supportsSizeChanges);
+ sForStringSet.parcel(mKnownActivityEmbeddingCerts, dest, flags);
}
/**
@@ -1739,6 +1795,10 @@
mMaxAspectRatio = source.readFloat();
mMinAspectRatio = source.readFloat();
supportsSizeChanges = source.readBoolean();
+ mKnownActivityEmbeddingCerts = sForStringSet.unparcel(source);
+ if (mKnownActivityEmbeddingCerts.isEmpty()) {
+ mKnownActivityEmbeddingCerts = null;
+ }
}
/**
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 567f649..2528e16 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -35,6 +35,7 @@
import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Printer;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
@@ -52,7 +53,9 @@
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
+import java.util.Locale;
import java.util.Objects;
+import java.util.Set;
import java.util.UUID;
/**
@@ -62,6 +65,8 @@
*/
public class ApplicationInfo extends PackageItemInfo implements Parcelable {
private static ForBoolean sForBoolean = Parcelling.Cache.getOrCreate(ForBoolean.class);
+ private static final Parcelling.BuiltIn.ForStringSet sForStringSet =
+ Parcelling.Cache.getOrCreate(Parcelling.BuiltIn.ForStringSet.class);
/**
* Default task affinity of all activities in this application. See
@@ -1550,6 +1555,13 @@
*/
private int localeConfigRes;
+ /**
+ * Optional set of a certificates identifying apps that are allowed to embed activities of this
+ * application. From the "knownActivityEmbeddingCerts" attribute.
+ */
+ @Nullable
+ private Set<String> mKnownActivityEmbeddingCerts;
+
public void dump(Printer pw, String prefix) {
dump(pw, prefix, DUMP_FLAG_ALL);
}
@@ -1673,6 +1685,9 @@
}
}
pw.println(prefix + "createTimestamp=" + createTimestamp);
+ if (mKnownActivityEmbeddingCerts != null) {
+ pw.println(prefix + "knownActivityEmbeddingCerts=" + mKnownActivityEmbeddingCerts);
+ }
super.dumpBack(pw, prefix);
}
@@ -1787,6 +1802,11 @@
}
proto.end(detailToken);
}
+ if (!ArrayUtils.isEmpty(mKnownActivityEmbeddingCerts)) {
+ for (String knownCert : mKnownActivityEmbeddingCerts) {
+ proto.write(ApplicationInfoProto.KNOWN_ACTIVITY_EMBEDDING_CERTS, knownCert);
+ }
+ }
proto.end(token);
}
@@ -1837,6 +1857,7 @@
super(orig);
taskAffinity = orig.taskAffinity;
permission = orig.permission;
+ mKnownActivityEmbeddingCerts = orig.mKnownActivityEmbeddingCerts;
processName = orig.processName;
className = orig.className;
theme = orig.theme;
@@ -2006,6 +2027,7 @@
}
}
dest.writeInt(localeConfigRes);
+ sForStringSet.parcel(mKnownActivityEmbeddingCerts, dest, flags);
}
public static final @android.annotation.NonNull Parcelable.Creator<ApplicationInfo> CREATOR
@@ -2102,6 +2124,10 @@
}
}
localeConfigRes = source.readInt();
+ mKnownActivityEmbeddingCerts = sForStringSet.unparcel(source);
+ if (mKnownActivityEmbeddingCerts.isEmpty()) {
+ mKnownActivityEmbeddingCerts = null;
+ }
}
/**
@@ -2658,7 +2684,6 @@
return localeConfigRes;
}
-
/**
* List of all shared libraries this application is linked against. This
* list will only be set if the {@link PackageManager#GET_SHARED_LIBRARY_FILES
@@ -2675,4 +2700,29 @@
return sharedLibraryInfos;
}
+ /**
+ * Gets the trusted host certificate digests of apps that are allowed to embed activities of
+ * this application. The digests are computed using the SHA-256 digest algorithm.
+ * @see android.R.attr#knownActivityEmbeddingCerts
+ */
+ @NonNull
+ public Set<String> getKnownActivityEmbeddingCerts() {
+ return mKnownActivityEmbeddingCerts == null ? Collections.emptySet()
+ : mKnownActivityEmbeddingCerts;
+ }
+
+ /**
+ * Sets the trusted host certificates of apps that are allowed to embed activities of this
+ * application.
+ * @see #getKnownActivityEmbeddingCerts()
+ * @hide
+ */
+ public void setKnownActivityEmbeddingCerts(@NonNull Set<String> knownActivityEmbeddingCerts) {
+ // Convert the provided digest to upper case for consistent Set membership
+ // checks when verifying the signing certificate digests of requesting apps.
+ mKnownActivityEmbeddingCerts = new ArraySet<>();
+ for (String knownCert : knownActivityEmbeddingCerts) {
+ mKnownActivityEmbeddingCerts.add(knownCert.toUpperCase(Locale.US));
+ }
+ }
}
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index cb8988e..08cfbf7 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -58,7 +58,7 @@
void startActivityAsUser(in IApplicationThread caller, String callingPackage,
String callingFeatureId, in ComponentName component, in Rect sourceBounds,
in Bundle opts, in UserHandle user);
- PendingIntent getActivityLaunchIntent(in ComponentName component, in Bundle opts,
+ PendingIntent getActivityLaunchIntent(String callingPackage, in ComponentName component,
in UserHandle user);
void showAppDetailsAsUser(in IApplicationThread caller, String callingPackage,
String callingFeatureId, in ComponentName component, in Rect sourceBounds,
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index a0d348f..301d1bbc 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -749,23 +749,29 @@
}
/**
- * Returns a PendingIntent that would start the same activity started from
- * {@link #startMainActivity(ComponentName, UserHandle, Rect, Bundle)}.
+ * Returns a mutable PendingIntent that would start the same activity started from
+ * {@link #startMainActivity(ComponentName, UserHandle, Rect, Bundle)}. The caller needs to
+ * take care in ensuring that the mutable intent returned is not passed to untrusted parties.
*
* @param component The ComponentName of the activity to launch
- * @param startActivityOptions Options to pass to startActivity
+ * @param startActivityOptions This parameter is no longer supported
* @param user The UserHandle of the profile
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.START_TASKS_FROM_RECENTS)
@Nullable
public PendingIntent getMainActivityLaunchIntent(@NonNull ComponentName component,
@Nullable Bundle startActivityOptions, @NonNull UserHandle user) {
+ if (mContext.checkSelfPermission(android.Manifest.permission.START_TASKS_FROM_RECENTS)
+ != PackageManager.PERMISSION_GRANTED) {
+ Log.w(TAG, "Only allowed for recents.");
+ }
logErrorForInvalidProfileAccess(user);
if (DEBUG) {
Log.i(TAG, "GetMainActivityLaunchIntent " + component + " " + user);
}
try {
- return mService.getActivityLaunchIntent(component, startActivityOptions, user);
+ return mService.getActivityLaunchIntent(mContext.getPackageName(), component, user);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -860,7 +866,7 @@
*
* @param packageName The packageName of the shortcut
* @param shortcutId The id of the shortcut
- * @param opts Options to pass to the PendingIntent
+ * @param opts This parameter is no longer supported
* @param user The UserHandle of the profile
*/
@Nullable
@@ -872,8 +878,9 @@
Log.i(TAG, "GetShortcutIntent " + packageName + "/" + shortcutId + " " + user);
}
try {
+ // due to b/209607104, opts will be ignored
return mService.getShortcutIntent(
- mContext.getPackageName(), packageName, shortcutId, opts, user);
+ mContext.getPackageName(), packageName, shortcutId, null /* opts */, user);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index ce549c3..dc79ee6 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3797,6 +3797,16 @@
/**
* Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+ * The device supports expanded picture-in-picture multi-window mode.
+ *
+ * @see android.app.PictureInPictureParams.Builder#setExpandedAspectRatio
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_EXPANDED_PICTURE_IN_PICTURE
+ = "android.software.expanded_picture_in_picture";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
* The device supports running activities on secondary displays.
*/
@SdkConstant(SdkConstantType.FEATURE)
@@ -4342,6 +4352,21 @@
= "android.content.pm.extra.REQUEST_PERMISSIONS_RESULTS";
/**
+ * Indicates that the package requesting permissions has legacy access for some permissions,
+ * or had it, but it was recently revoked. These request dialogs may show different text,
+ * indicating that the app is requesting continued access to a permission. Will be cleared
+ * from any permission request intent, if set by a non-system server app.
+ * <p>
+ * <strong>Type:</strong> String[]
+ * </p>
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_REQUEST_PERMISSIONS_LEGACY_ACCESS_PERMISSION_NAMES
+ = "android.content.pm.extra.REQUEST_PERMISSIONS_LEGACY_ACCESS_PERMISSION_NAMES";
+
+ /**
* String extra for {@link PackageInstallObserver} in the 'extras' Bundle in case of
* {@link #INSTALL_FAILED_DUPLICATE_PERMISSION}. This extra names the package which provides
* the existing definition for the permission.
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index 7dbfd08..70b90e6 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -532,7 +532,7 @@
* app.
*
* <p><b>Note:</b> See also the support library counterpart
- * {@link android.support.v4.content.pm.ShortcutManagerCompat#isRequestPinShortcutSupported(
+ * {@link androidx.core.content.pm.ShortcutManagerCompat#isRequestPinShortcutSupported(
* Context)}, which supports Android versions lower than {@link VERSION_CODES#O} using the
* legacy private intent {@code com.android.launcher.action.INSTALL_SHORTCUT}.
*
@@ -561,7 +561,7 @@
* previous requests.
*
* <p><b>Note:</b> See also the support library counterpart
- * {@link android.support.v4.content.pm.ShortcutManagerCompat#requestPinShortcut(
+ * {@link androidx.core.content.pm.ShortcutManagerCompat#requestPinShortcut(
* Context, ShortcutInfoCompat, IntentSender)},
* which supports Android versions lower than {@link VERSION_CODES#O} using the
* legacy private intent {@code com.android.launcher.action.INSTALL_SHORTCUT}.
@@ -767,7 +767,7 @@
* order to make sure shortcuts exist and are up-to-date, without the need to explicitly handle
* the shortcut count limit.
* @see android.app.NotificationManager#notify(int, Notification)
- * @see Notification.Builder#setShortcutId(String)
+ * @see android.app.Notification.Builder#setShortcutId(String)
*
* <p>If {@link #getMaxShortcutCountPerActivity()} is already reached, an existing shortcut with
* the lowest rank will be removed to add space for the new shortcut.
diff --git a/core/java/android/hardware/HardwareBuffer.java b/core/java/android/hardware/HardwareBuffer.java
index 515a009..ac1bcf3 100644
--- a/core/java/android/hardware/HardwareBuffer.java
+++ b/core/java/android/hardware/HardwareBuffer.java
@@ -131,7 +131,8 @@
/** Usage: The buffer will be written to by the GPU */
public static final long USAGE_GPU_COLOR_OUTPUT = 1 << 9;
/**
- * The buffer will be used as a composer HAL overlay layer.
+ * The buffer will be used as a hardware composer overlay layer. That is, it will be displayed
+ * using the system compositor via {@link SurfaceControl}
*
* This flag is currently only needed when using
* {@link android.view.SurfaceControl.Transaction#setBuffer(SurfaceControl, HardwareBuffer)}
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index a06566c..524fe79 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -3455,6 +3455,30 @@
new Key<android.hardware.camera2.params.MandatoryStreamCombination[]>("android.scaler.mandatoryTenBitOutputStreamCombinations", android.hardware.camera2.params.MandatoryStreamCombination[].class);
/**
+ * <p>An array of mandatory stream combinations which are applicable when device lists
+ * {@code PREVIEW_STABILIZATION} in {@link CameraCharacteristics#CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES android.control.availableVideoStabilizationModes}.
+ * This is an app-readable conversion of the maximum resolution mandatory stream combination
+ * {@link android.hardware.camera2.CameraDevice#createCaptureSession tables}.</p>
+ * <p>The array of
+ * {@link android.hardware.camera2.params.MandatoryStreamCombination combinations} is
+ * generated according to the documented
+ * {@link android.hardware.camera2.CameraDevice#createCaptureSession guideline} for each
+ * device which supports {@code PREVIEW_STABILIZATION}
+ * Clients can use the array as a quick reference to find an appropriate camera stream
+ * combination.
+ * The mandatory stream combination array will be {@code null} in case the device does not
+ * list {@code PREVIEW_STABILIZATION} in {@link CameraCharacteristics#CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES android.control.availableVideoStabilizationModes}.</p>
+ * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ *
+ * @see CameraCharacteristics#CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES
+ */
+ @PublicKey
+ @NonNull
+ @SyntheticKey
+ public static final Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_PREVIEW_STABILIZATION_OUTPUT_STREAM_COMBINATIONS =
+ new Key<android.hardware.camera2.params.MandatoryStreamCombination[]>("android.scaler.mandatoryPreviewStabilizationOutputStreamCombinations", android.hardware.camera2.params.MandatoryStreamCombination[].class);
+
+ /**
* <p>Whether the camera device supports multi-resolution input or output streams</p>
* <p>A logical multi-camera or an ultra high resolution camera may support multi-resolution
* input or output streams. With multi-resolution output streams, the camera device is able
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 1a42eaf..8f42b1f 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -883,6 +883,27 @@
* </table><br>
* </p>
*
+ *<p> For devices where {@link CameraCharacteristics#CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES}
+ * includes {@link CameraMetadata#CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION},
+ * the following stream combinations are guaranteed,
+ * for CaptureRequests where {@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE} is set to
+ * {@link CameraMetadata#CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION} <p>
+ * <table>
+ * <tr><th colspan="7">Preview stabilization guaranteed stream configurations</th></tr>
+ * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th rowspan="2">Sample use case(s)</th> </tr>
+ * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
+ * <tr> <td>{@code PRIV / YUV}</td><td id="rb">{@code RECORD}</td><td colspan="4" id="rb"></td> <td>Stabilized preview, GPU video processing, or no-preview stabilized video recording.</td> </tr>
+ * <tr> <td>{@code PRIV / YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG / YUV}</td><td id="rb">{@code MAXIMUM }</td><td>Standard still imaging with stabilized preview.</td> </tr>
+ * <tr> <td>{@code PRIV / YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV / YUV}</td><td id="rb">{@code RECORD }</td><td>High-resolution recording with stabilized preview and recording stream.</td> </tr>
+ * </table><br>
+ * <p>
+ * For the maximum size column, PREVIEW refers to the best size match to the device's screen
+ * resolution, or to 1080p (1920x1080), whichever is smaller. RECORD refers to the camera
+ * device's maximum supported recording resolution, as determined by
+ * {@link android.media.CamcorderProfile}. MAXIMUM refers to the camera device's maximum output
+ * resolution for that format or target from {@link StreamConfigurationMap#getOutputSizes(int)}.
+ * </p>
+ *
* <p>Since the capabilities of camera devices vary greatly, a given camera device may support
* target combinations with sizes outside of these guarantees, but this can only be tested for
* by calling {@link #isSessionConfigurationSupported} or attempting to create a session with
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 9b67633..4fb496d 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -334,6 +334,7 @@
private static final int MANDATORY_STREAM_CONFIGURATIONS_CONCURRENT = 2;
private static final int MANDATORY_STREAM_CONFIGURATIONS_10BIT = 3;
private static final int MANDATORY_STREAM_CONFIGURATIONS_USE_CASE = 4;
+ private static final int MANDATORY_STREAM_CONFIGURATIONS_PREVIEW_STABILIZATION = 5;
private static String translateLocationProviderToProcess(final String provider) {
if (provider == null) {
@@ -709,6 +710,15 @@
return (T) metadata.getMandatoryUseCaseStreamCombinations();
}
});
+ sGetCommandMap.put(
+ CameraCharacteristics.SCALER_MANDATORY_PREVIEW_STABILIZATION_OUTPUT_STREAM_COMBINATIONS.getNativeKey(),
+ new GetCommand() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
+ return (T) metadata.getMandatoryPreviewStabilizationStreamCombinations();
+ }
+ });
sGetCommandMap.put(
CameraCharacteristics.CONTROL_MAX_REGIONS_AE.getNativeKey(), new GetCommand() {
@@ -1400,6 +1410,24 @@
CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE);
}
+ private boolean isPreviewStabilizationSupported() {
+ boolean ret = false;
+
+ int[] videoStabilizationModes =
+ getBase(CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES);
+ if (videoStabilizationModes == null) {
+ return false;
+ }
+ for (int mode : videoStabilizationModes) {
+ if (mode == CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION) {
+ ret = true;
+ break;
+ }
+ }
+
+ return ret;
+ }
+
private MandatoryStreamCombination[] getMandatoryStreamCombinationsHelper(
int mandatoryStreamsType) {
int[] capabilities = getBase(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
@@ -1411,7 +1439,7 @@
int hwLevel = getBase(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
MandatoryStreamCombination.Builder build = new MandatoryStreamCombination.Builder(
mCameraId, hwLevel, mDisplaySize, caps, getStreamConfigurationMap(),
- getStreamConfigurationMapMaximumResolution());
+ getStreamConfigurationMapMaximumResolution(), isPreviewStabilizationSupported());
List<MandatoryStreamCombination> combs = null;
switch (mandatoryStreamsType) {
@@ -1427,6 +1455,9 @@
case MANDATORY_STREAM_CONFIGURATIONS_USE_CASE:
combs = build.getAvailableMandatoryStreamUseCaseCombinations();
break;
+ case MANDATORY_STREAM_CONFIGURATIONS_PREVIEW_STABILIZATION:
+ combs = build.getAvailableMandatoryPreviewStabilizedStreamCombinations();
+ break;
default:
combs = build.getAvailableMandatoryStreamCombinations();
}
@@ -1464,6 +1495,11 @@
return getMandatoryStreamCombinationsHelper(MANDATORY_STREAM_CONFIGURATIONS_USE_CASE);
}
+ private MandatoryStreamCombination[] getMandatoryPreviewStabilizationStreamCombinations() {
+ return getMandatoryStreamCombinationsHelper(
+ MANDATORY_STREAM_CONFIGURATIONS_PREVIEW_STABILIZATION);
+ }
+
private StreamConfigurationMap getStreamConfigurationMap() {
StreamConfiguration[] configurations = getBase(
CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
diff --git a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
index 0d93c98..8c0dcfc 100644
--- a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
+++ b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
@@ -1262,6 +1262,50 @@
"Preview, in-application image processing, and YUV still image capture"),
};
+ private static StreamCombinationTemplate sPreviewStabilizedStreamCombinations[] = {
+ // 1 stream combinations
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD)},
+ "Stabilized preview, GPU video processing, or no-preview stabilized recording"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD)},
+ "Stabilized preview, GPU video processing, or no-preview stabilized recording"),
+ //2 stream combinations
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM),
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)},
+ "Standard JPEG still imaging with stabilized preview"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM),
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)},
+ "Standard YUV still imaging with stabilized preview"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM),
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW)},
+ "Standard YUV still imaging with stabilized in-app image processing stream"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM),
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW)},
+ "Standard JPEG still imaging with stabilized in-app image processing stream"),
+
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD),
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)},
+ "High-resolution video recording with preview both streams stabilized"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD),
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW)},
+ "High-resolution video recording with preview both streams stabilized"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD),
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW)},
+ "High-resolution video recording with preview both streams stabilized"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD),
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)},
+ "High-resolution video recording with preview both streams stabilized"),
+ };
+
/**
* Helper builder class to generate a list of available mandatory stream combinations.
* @hide
@@ -1273,6 +1317,7 @@
private StreamConfigurationMap mStreamConfigMap;
private StreamConfigurationMap mStreamConfigMapMaximumResolution;
private boolean mIsHiddenPhysicalCamera;
+ private boolean mIsPreviewStabilizationSupported;
private final Size kPreviewSizeBound = new Size(1920, 1088);
@@ -1289,7 +1334,7 @@
*/
public Builder(int cameraId, int hwLevel, @NonNull Size displaySize,
@NonNull List<Integer> capabilities, @NonNull StreamConfigurationMap sm,
- StreamConfigurationMap smMaxResolution) {
+ StreamConfigurationMap smMaxResolution, boolean previewStabilization) {
mCameraId = cameraId;
mDisplaySize = displaySize;
mCapabilities = capabilities;
@@ -1298,24 +1343,12 @@
mHwLevel = hwLevel;
mIsHiddenPhysicalCamera =
CameraManager.isHiddenPhysicalCamera(Integer.toString(mCameraId));
+ mIsPreviewStabilizationSupported = previewStabilization;
}
- /**
- * Retrieve a list of all available mandatory 10-bit output capable stream combinations.
- *
- * @return a non-modifiable list of supported mandatory 10-bit capable stream combinations,
- * null in case device is not 10-bit output capable.
- */
- public @NonNull List<MandatoryStreamCombination>
- getAvailableMandatory10BitStreamCombinations() {
- // Since 10-bit streaming support is optional, we mandate these stream
- // combinations regardless of camera device capabilities.
-
- StreamCombinationTemplate []chosenStreamCombinations = s10BitOutputStreamCombinations;
- if (!is10BitOutputSupported()) {
- Log.v(TAG, "Device is not able to output 10-bit!");
- return null;
- }
+ private @Nullable List<MandatoryStreamCombination>
+ getAvailableMandatoryStreamCombinationsInternal(
+ StreamCombinationTemplate []chosenStreamCombinations, boolean s10Bit) {
HashMap<Pair<SizeThreshold, Integer>, List<Size>> availableSizes =
enumerateAvailableSizes();
@@ -1334,7 +1367,7 @@
Pair<SizeThreshold, Integer> pair;
pair = new Pair<>(template.mSizeThreshold, new Integer(template.mFormat));
sizes = availableSizes.get(pair);
- if (template.mFormat == ImageFormat.YCBCR_P010) {
+ if (s10Bit && template.mFormat == ImageFormat.YCBCR_P010) {
// Make sure that exactly the same 10 and 8-bit YUV streams sizes are
// supported
pair = new Pair<>(template.mSizeThreshold,
@@ -1354,7 +1387,8 @@
streamInfo = new MandatoryStreamInformation(sizes, template.mFormat,
isMaximumSize, /*isInput*/ false,
/*isUltraHighResolution*/ false,
- /*is10BitCapable*/ template.mFormat != ImageFormat.JPEG);
+ /*is10BitCapable*/ s10Bit ? template.mFormat != ImageFormat.JPEG :
+ false);
} catch (IllegalArgumentException e) {
Log.e(TAG, "No available sizes found for format: " + template.mFormat +
" size threshold: " + template.mSizeThreshold + " combination: " +
@@ -1381,6 +1415,52 @@
}
/**
+ * Retrieve a list of all available mandatory stream combinations for devices supporting
+ * preview stabilization.
+ *
+ * @return a non-modifiable list of supported mandatory stream combinations on which
+ * preview stabilization is supported.,
+ * null in case device is not 10-bit output capable.
+ */
+ public @Nullable List<MandatoryStreamCombination>
+ getAvailableMandatoryPreviewStabilizedStreamCombinations() {
+ // Since preview stabilization support is optional, we mandate these stream
+ // combinations regardless of camera device capabilities.
+
+ StreamCombinationTemplate []chosenStreamCombinations =
+ sPreviewStabilizedStreamCombinations;
+
+ if (mIsPreviewStabilizationSupported) {
+ Log.v(TAG, "Device does not support preview stabilization");
+ return null;
+ }
+
+ return getAvailableMandatoryStreamCombinationsInternal(chosenStreamCombinations,
+ /*10bit*/false);
+ }
+
+
+ /**
+ * Retrieve a list of all available mandatory 10-bit output capable stream combinations.
+ *
+ * @return a non-modifiable list of supported mandatory 10-bit capable stream combinations,
+ * null in case device is not 10-bit output capable.
+ */
+ public @Nullable List<MandatoryStreamCombination>
+ getAvailableMandatory10BitStreamCombinations() {
+ // Since 10-bit streaming support is optional, we mandate these stream
+ // combinations regardless of camera device capabilities.
+
+ StreamCombinationTemplate []chosenStreamCombinations = s10BitOutputStreamCombinations;
+ if (!is10BitOutputSupported()) {
+ Log.v(TAG, "Device is not able to output 10-bit!");
+ return null;
+ }
+ return getAvailableMandatoryStreamCombinationsInternal(chosenStreamCombinations,
+ /*10bit*/true);
+ }
+
+ /**
* Retrieve a list of all available mandatory stream combinations with stream use cases.
* when the camera device has {@link
* CameraMetdata.REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE} capability.
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index f67a5b4..8093764 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -264,6 +264,44 @@
public @interface StreamUseCase {};
/**
+ * Automatic mirroring based on camera facing
+ *
+ * <p>This is the default mirroring mode for the camera device. With this mode,
+ * the camera output is mirrored horizontally for front-facing cameras. There is
+ * no mirroring for rear-facing and external cameras.</p>
+ */
+ public static final int MIRROR_MODE_AUTO = 0;
+
+ /**
+ * No mirror transform is applied
+ *
+ * <p>No mirroring is applied to the camera output regardless of the camera facing.</p>
+ */
+ public static final int MIRROR_MODE_NONE = 1;
+
+ /**
+ * Camera output is mirrored horizontally
+ *
+ * <p>The camera output is mirrored horizontally, the same behavior as in AUTO mode for
+ * front facing camera.</p>
+ */
+ public static final int MIRROR_MODE_H = 2;
+
+ /**
+ * Camera output is mirrored vertically
+ */
+ public static final int MIRROR_MODE_V = 3;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"MIRROR_MODE_"}, value =
+ {MIRROR_MODE_AUTO,
+ MIRROR_MODE_NONE,
+ MIRROR_MODE_H,
+ MIRROR_MODE_V})
+ public @interface MirrorMode {};
+
+ /**
* Create a new {@link OutputConfiguration} instance with a {@link Surface}.
*
* @param surface
@@ -461,6 +499,7 @@
mDynamicRangeProfile = DynamicRangeProfiles.STANDARD;
mStreamUseCase = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT;
mTimestampBase = TIMESTAMP_BASE_DEFAULT;
+ mMirrorMode = MIRROR_MODE_AUTO;
}
/**
@@ -945,6 +984,42 @@
}
/**
+ * Set the mirroring mode for this output target
+ *
+ * <p>If this function is not called, the mirroring mode for this output is
+ * {@link #MIRROR_MODE_AUTO}, with which the camera API will mirror the output images
+ * horizontally for front facing camera.</p>
+ *
+ * <p>For efficiency, the mirror effect is applied as a transform flag, so it is only effective
+ * in some outputs. It works automatically for SurfaceView and TextureView outputs. For manual
+ * use of SurfaceTexture, it is reflected in the value of
+ * {@link android.graphics.SurfaceTexture#getTransformMatrix}. For other end points, such as
+ * ImageReader, MediaRecorder, or MediaCodec, the mirror mode has no effect. If mirroring is
+ * needed for such outputs, the application needs to mirror the image buffers itself before
+ * passing them onward.</p>
+ */
+ public void setMirrorMode(@MirrorMode int mirrorMode) {
+ // Verify that the value is in range
+ if (mirrorMode < MIRROR_MODE_AUTO ||
+ mirrorMode > MIRROR_MODE_V) {
+ throw new IllegalArgumentException("Not a valid mirror mode " + mirrorMode);
+ }
+ mMirrorMode = mirrorMode;
+ }
+
+ /**
+ * Get the current mirroring mode
+ *
+ * <p>If no {@link #setMirrorMode} is called first, this function returns
+ * {@link #MIRROR_MODE_AUTO}.</p>
+ *
+ * @return The currently set mirroring mode
+ */
+ public @MirrorMode int getMirrorMode() {
+ return mMirrorMode;
+ }
+
+ /**
* Create a new {@link OutputConfiguration} instance with another {@link OutputConfiguration}
* instance.
*
@@ -973,6 +1048,7 @@
this.mDynamicRangeProfile = other.mDynamicRangeProfile;
this.mStreamUseCase = other.mStreamUseCase;
this.mTimestampBase = other.mTimestampBase;
+ this.mMirrorMode = other.mMirrorMode;
}
/**
@@ -998,6 +1074,8 @@
DynamicRangeProfiles.checkProfileValue(dynamicRangeProfile);
int timestampBase = source.readInt();
+ int mirrorMode = source.readInt();
+
mSurfaceGroupId = surfaceSetId;
mRotation = rotation;
mSurfaces = surfaces;
@@ -1023,6 +1101,7 @@
mDynamicRangeProfile = dynamicRangeProfile;
mStreamUseCase = streamUseCase;
mTimestampBase = timestampBase;
+ mMirrorMode = mirrorMode;
}
/**
@@ -1141,6 +1220,7 @@
dest.writeInt(mDynamicRangeProfile);
dest.writeInt(mStreamUseCase);
dest.writeInt(mTimestampBase);
+ dest.writeInt(mMirrorMode);
}
/**
@@ -1173,7 +1253,8 @@
!Objects.equals(mPhysicalCameraId, other.mPhysicalCameraId) ||
mIsMultiResolution != other.mIsMultiResolution ||
mStreamUseCase != other.mStreamUseCase ||
- mTimestampBase != other.mTimestampBase)
+ mTimestampBase != other.mTimestampBase ||
+ mMirrorMode != other.mMirrorMode)
return false;
if (mSensorPixelModesUsed.size() != other.mSensorPixelModesUsed.size()) {
return false;
@@ -1211,7 +1292,7 @@
mSurfaceGroupId, mSurfaceType, mIsShared ? 1 : 0,
mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode(),
mIsMultiResolution ? 1 : 0, mSensorPixelModesUsed.hashCode(),
- mDynamicRangeProfile, mStreamUseCase, mTimestampBase);
+ mDynamicRangeProfile, mStreamUseCase, mTimestampBase, mMirrorMode);
}
return HashCodeHelpers.hashCode(
@@ -1220,7 +1301,8 @@
mConfiguredDataspace, mSurfaceGroupId, mIsShared ? 1 : 0,
mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode(),
mIsMultiResolution ? 1 : 0, mSensorPixelModesUsed.hashCode(),
- mDynamicRangeProfile, mStreamUseCase, mTimestampBase);
+ mDynamicRangeProfile, mStreamUseCase, mTimestampBase,
+ mMirrorMode);
}
private static final String TAG = "OutputConfiguration";
@@ -1258,4 +1340,6 @@
private int mStreamUseCase;
// Timestamp base
private int mTimestampBase;
+ // Mirroring mode
+ private int mMirrorMode;
}
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index eefa1d3..971b61b 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -22,6 +22,7 @@
import android.Manifest;
import android.annotation.FloatRange;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.LongDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -38,6 +39,8 @@
import android.media.projection.MediaProjection;
import android.os.Build;
import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.Looper;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
@@ -48,6 +51,7 @@
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.Executor;
/**
@@ -104,6 +108,25 @@
public static final String DISPLAY_CATEGORY_PRESENTATION =
"android.hardware.display.category.PRESENTATION";
+ /** @hide **/
+ @IntDef(prefix = "VIRTUAL_DISPLAY_FLAG_", flag = true, value = {
+ VIRTUAL_DISPLAY_FLAG_PUBLIC,
+ VIRTUAL_DISPLAY_FLAG_PRESENTATION,
+ VIRTUAL_DISPLAY_FLAG_SECURE,
+ VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY,
+ VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
+ VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD,
+ VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH,
+ VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT,
+ VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL,
+ VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS,
+ VIRTUAL_DISPLAY_FLAG_TRUSTED,
+ VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP,
+ VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface VirtualDisplayFlag {}
+
/**
* Virtual display flag: Create a public display.
*
@@ -820,7 +843,11 @@
* VirtualDisplay.Callback, Handler)
*/
public VirtualDisplay createVirtualDisplay(@NonNull String name,
- int width, int height, int densityDpi, @Nullable Surface surface, int flags) {
+ @IntRange(from = 1) int width,
+ @IntRange(from = 1) int height,
+ @IntRange(from = 1) int densityDpi,
+ @Nullable Surface surface,
+ @VirtualDisplayFlag int flags) {
return createVirtualDisplay(name, width, height, densityDpi, surface, flags, null, null);
}
@@ -868,8 +895,13 @@
* a virtual display with the specified flags.
*/
public VirtualDisplay createVirtualDisplay(@NonNull String name,
- int width, int height, int densityDpi, @Nullable Surface surface, int flags,
- @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
+ @IntRange(from = 1) int width,
+ @IntRange(from = 1) int height,
+ @IntRange(from = 1) int densityDpi,
+ @Nullable Surface surface,
+ @VirtualDisplayFlag int flags,
+ @Nullable VirtualDisplay.Callback callback,
+ @Nullable Handler handler) {
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width,
height, densityDpi);
builder.setFlags(flags);
@@ -882,9 +914,16 @@
// TODO : Remove this hidden API after remove all callers. (Refer to MultiDisplayService)
/** @hide */
- public VirtualDisplay createVirtualDisplay(@Nullable MediaProjection projection,
- @NonNull String name, int width, int height, int densityDpi, @Nullable Surface surface,
- int flags, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler,
+ public VirtualDisplay createVirtualDisplay(
+ @Nullable MediaProjection projection,
+ @NonNull String name,
+ @IntRange(from = 1) int width,
+ @IntRange(from = 1) int height,
+ @IntRange(from = 1) int densityDpi,
+ @Nullable Surface surface,
+ @VirtualDisplayFlag int flags,
+ @Nullable VirtualDisplay.Callback callback,
+ @Nullable Handler handler,
@Nullable String uniqueId) {
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width,
height, densityDpi);
@@ -904,16 +943,24 @@
@NonNull VirtualDisplayConfig virtualDisplayConfig,
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler,
@Nullable Context windowContext) {
+ Executor executor = null;
+ // If callback is null, the executor will not be used. Avoid creating the handler and the
+ // handler executor.
+ if (callback != null) {
+ executor = new HandlerExecutor(
+ Handler.createAsync(handler != null ? handler.getLooper() : Looper.myLooper()));
+ }
return mGlobal.createVirtualDisplay(mContext, projection, null /* virtualDevice */,
- virtualDisplayConfig, callback, handler, windowContext);
+ virtualDisplayConfig, callback, executor, windowContext);
}
/** @hide */
public VirtualDisplay createVirtualDisplay(@Nullable IVirtualDevice virtualDevice,
@NonNull VirtualDisplayConfig virtualDisplayConfig,
- @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
+ @Nullable VirtualDisplay.Callback callback,
+ @NonNull Executor executor) {
return mGlobal.createVirtualDisplay(mContext, null /* projection */, virtualDevice,
- virtualDisplayConfig, callback, handler, null);
+ virtualDisplayConfig, callback, executor, null);
}
/**
@@ -1214,17 +1261,6 @@
}
/**
- * Returns whether the specified display supports DISPLAY_DECORATION.
- *
- * @param displayId The display to query support.
- *
- * @hide
- */
- public boolean getDisplayDecorationSupport(int displayId) {
- return mGlobal.getDisplayDecorationSupport(displayId);
- }
-
- /**
* Returns the user preference for "Match content frame rate".
* <p>
* Never: Even if the app requests it, the device will never try to match its output to the
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index af8ec27..889100d 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -32,6 +32,7 @@
import android.graphics.ColorSpace;
import android.graphics.Point;
import android.hardware.display.DisplayManager.DisplayListener;
+import android.hardware.graphics.common.DisplayDecorationSupport;
import android.media.projection.IMediaProjection;
import android.media.projection.MediaProjection;
import android.os.Handler;
@@ -55,6 +56,8 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executor;
/**
* Manager communication with the display manager service on behalf of
@@ -584,8 +587,9 @@
public VirtualDisplay createVirtualDisplay(@NonNull Context context, MediaProjection projection,
IVirtualDevice virtualDevice, @NonNull VirtualDisplayConfig virtualDisplayConfig,
- VirtualDisplay.Callback callback, Handler handler, @Nullable Context windowContext) {
- VirtualDisplayCallback callbackWrapper = new VirtualDisplayCallback(callback, handler);
+ VirtualDisplay.Callback callback, @Nullable Executor executor,
+ @Nullable Context windowContext) {
+ VirtualDisplayCallback callbackWrapper = new VirtualDisplayCallback(callback, executor);
IMediaProjection projectionToken = projection != null ? projection.getProjection() : null;
int displayId;
try {
@@ -812,13 +816,13 @@
}
/**
- * Report whether the display supports DISPLAY_DECORATION.
+ * Report whether/how the display supports DISPLAY_DECORATION.
*
* @param displayId The display whose support is being queried.
*
* @hide
*/
- public boolean getDisplayDecorationSupport(int displayId) {
+ public DisplayDecorationSupport getDisplayDecorationSupport(int displayId) {
try {
return mDm.getDisplayDecorationSupport(displayId);
} catch (RemoteException ex) {
@@ -1047,61 +1051,36 @@
}
private final static class VirtualDisplayCallback extends IVirtualDisplayCallback.Stub {
- private VirtualDisplayCallbackDelegate mDelegate;
+ @Nullable private final VirtualDisplay.Callback mCallback;
+ @Nullable private final Executor mExecutor;
- public VirtualDisplayCallback(VirtualDisplay.Callback callback, Handler handler) {
- if (callback != null) {
- mDelegate = new VirtualDisplayCallbackDelegate(callback, handler);
- }
+ VirtualDisplayCallback(VirtualDisplay.Callback callback, Executor executor) {
+ mCallback = callback;
+ mExecutor = mCallback != null ? Objects.requireNonNull(executor) : null;
}
+ // These methods are called from the binder thread, but the AIDL is oneway, so it should be
+ // safe to call the callback on arbitrary executors directly without risking blocking
+ // the system.
+
@Override // Binder call
public void onPaused() {
- if (mDelegate != null) {
- mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_PAUSED);
+ if (mCallback != null) {
+ mExecutor.execute(mCallback::onPaused);
}
}
@Override // Binder call
public void onResumed() {
- if (mDelegate != null) {
- mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_RESUMED);
+ if (mCallback != null) {
+ mExecutor.execute(mCallback::onResumed);
}
}
@Override // Binder call
public void onStopped() {
- if (mDelegate != null) {
- mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_STOPPED);
- }
- }
- }
-
- private final static class VirtualDisplayCallbackDelegate extends Handler {
- public static final int MSG_DISPLAY_PAUSED = 0;
- public static final int MSG_DISPLAY_RESUMED = 1;
- public static final int MSG_DISPLAY_STOPPED = 2;
-
- private final VirtualDisplay.Callback mCallback;
-
- public VirtualDisplayCallbackDelegate(VirtualDisplay.Callback callback,
- Handler handler) {
- super(handler != null ? handler.getLooper() : Looper.myLooper(), null, true /*async*/);
- mCallback = callback;
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_DISPLAY_PAUSED:
- mCallback.onPaused();
- break;
- case MSG_DISPLAY_RESUMED:
- mCallback.onResumed();
- break;
- case MSG_DISPLAY_STOPPED:
- mCallback.onStopped();
- break;
+ if (mCallback != null) {
+ mExecutor.execute(mCallback::onStopped);
}
}
}
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index b3af52b..ddd18f4 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -22,6 +22,7 @@
import android.hardware.display.BrightnessConfiguration;
import android.hardware.display.BrightnessInfo;
import android.hardware.display.Curve;
+import android.hardware.graphics.common.DisplayDecorationSupport;
import android.hardware.display.IDisplayManagerCallback;
import android.hardware.display.IVirtualDisplayCallback;
import android.hardware.display.VirtualDisplayConfig;
@@ -183,5 +184,5 @@
int getRefreshRateSwitchingType();
// Query for DISPLAY_DECORATION support.
- boolean getDisplayDecorationSupport(int displayId);
+ DisplayDecorationSupport getDisplayDecorationSupport(int displayId);
}
diff --git a/core/java/android/hardware/display/VirtualDisplayConfig.java b/core/java/android/hardware/display/VirtualDisplayConfig.java
index 0e86f43..e292394 100644
--- a/core/java/android/hardware/display/VirtualDisplayConfig.java
+++ b/core/java/android/hardware/display/VirtualDisplayConfig.java
@@ -21,6 +21,7 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.hardware.display.DisplayManager.VirtualDisplayFlag;
import android.media.projection.MediaProjection;
import android.os.Handler;
import android.os.IBinder;
@@ -70,6 +71,7 @@
* {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY},
* or {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR}.
*/
+ @VirtualDisplayFlag
private int mFlags = 0;
/**
@@ -120,7 +122,7 @@
@IntRange(from = 1) int width,
@IntRange(from = 1) int height,
@IntRange(from = 1) int densityDpi,
- int flags,
+ @VirtualDisplayFlag int flags,
@Nullable Surface surface,
@Nullable String uniqueId,
int displayIdToMirror,
@@ -141,6 +143,8 @@
IntRange.class, null, mDensityDpi,
"from", 1);
this.mFlags = flags;
+ com.android.internal.util.AnnotationValidations.validate(
+ VirtualDisplayFlag.class, null, mFlags);
this.mSurface = surface;
this.mUniqueId = uniqueId;
this.mDisplayIdToMirror = displayIdToMirror;
@@ -190,7 +194,7 @@
* or {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR}.
*/
@DataClass.Generated.Member
- public int getFlags() {
+ public @VirtualDisplayFlag int getFlags() {
return mFlags;
}
@@ -291,6 +295,8 @@
IntRange.class, null, mDensityDpi,
"from", 1);
this.mFlags = flags;
+ com.android.internal.util.AnnotationValidations.validate(
+ VirtualDisplayFlag.class, null, mFlags);
this.mSurface = surface;
this.mUniqueId = uniqueId;
this.mDisplayIdToMirror = displayIdToMirror;
@@ -324,7 +330,7 @@
private @IntRange(from = 1) int mWidth;
private @IntRange(from = 1) int mHeight;
private @IntRange(from = 1) int mDensityDpi;
- private int mFlags;
+ private @VirtualDisplayFlag int mFlags;
private @Nullable Surface mSurface;
private @Nullable String mUniqueId;
private int mDisplayIdToMirror;
@@ -419,7 +425,7 @@
* or {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR}.
*/
@DataClass.Generated.Member
- public @NonNull Builder setFlags(int value) {
+ public @NonNull Builder setFlags(@VirtualDisplayFlag int value) {
checkNotUsed();
mBuilderFieldsSet |= 0x10;
mFlags = value;
@@ -517,10 +523,10 @@
}
@DataClass.Generated(
- time = 1620657851981L,
+ time = 1643938791506L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/hardware/display/VirtualDisplayConfig.java",
- inputSignatures = "private @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.IntRange int mWidth\nprivate @android.annotation.IntRange int mHeight\nprivate @android.annotation.IntRange int mDensityDpi\nprivate int mFlags\nprivate @android.annotation.Nullable android.view.Surface mSurface\nprivate @android.annotation.Nullable java.lang.String mUniqueId\nprivate int mDisplayIdToMirror\nprivate @android.annotation.Nullable android.os.IBinder mWindowTokenClientToMirror\nclass VirtualDisplayConfig extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true)")
+ inputSignatures = "private @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.IntRange int mWidth\nprivate @android.annotation.IntRange int mHeight\nprivate @android.annotation.IntRange int mDensityDpi\nprivate @android.hardware.display.DisplayManager.VirtualDisplayFlag int mFlags\nprivate @android.annotation.Nullable android.view.Surface mSurface\nprivate @android.annotation.Nullable java.lang.String mUniqueId\nprivate int mDisplayIdToMirror\nprivate @android.annotation.Nullable android.os.IBinder mWindowTokenClientToMirror\nclass VirtualDisplayConfig extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/hardware/input/VirtualKeyEvent.java b/core/java/android/hardware/input/VirtualKeyEvent.java
index d875156..26d74df 100644
--- a/core/java/android/hardware/input/VirtualKeyEvent.java
+++ b/core/java/android/hardware/input/VirtualKeyEvent.java
@@ -114,9 +114,56 @@
}
/**
- * Sets the Android key code of the event. The set of allowed characters include digits 0-9,
- * characters A-Z, and standard punctuation, as well as numpad keys, function keys F1-F12,
- * and meta keys (caps lock, shift, etc.).
+ * Sets the Android key code of the event. The set of allowed keys include digits
+ * {@link android.view.KeyEvent#KEYCODE_0} through
+ * {@link android.view.KeyEvent#KEYCODE_9}, characters
+ * {@link android.view.KeyEvent#KEYCODE_A} through
+ * {@link android.view.KeyEvent#KEYCODE_Z}, function keys
+ * {@link android.view.KeyEvent#KEYCODE_F1} through
+ * {@link android.view.KeyEvent#KEYCODE_F12}, numpad keys
+ * {@link android.view.KeyEvent#KEYCODE_NUMPAD_0} through
+ * {@link android.view.KeyEvent#KEYCODE_NUMPAD_RIGHT_PAREN},
+ * and these additional keys:
+ * {@link android.view.KeyEvent#KEYCODE_GRAVE}
+ * {@link android.view.KeyEvent#KEYCODE_MINUS}
+ * {@link android.view.KeyEvent#KEYCODE_EQUALS}
+ * {@link android.view.KeyEvent#KEYCODE_LEFT_BRACKET}
+ * {@link android.view.KeyEvent#KEYCODE_RIGHT_BRACKET}
+ * {@link android.view.KeyEvent#KEYCODE_BACKSLASH}
+ * {@link android.view.KeyEvent#KEYCODE_SEMICOLON}
+ * {@link android.view.KeyEvent#KEYCODE_APOSTROPHE}
+ * {@link android.view.KeyEvent#KEYCODE_COMMA}
+ * {@link android.view.KeyEvent#KEYCODE_PERIOD}
+ * {@link android.view.KeyEvent#KEYCODE_SLASH}
+ * {@link android.view.KeyEvent#KEYCODE_ALT_LEFT}
+ * {@link android.view.KeyEvent#KEYCODE_ALT_RIGHT}
+ * {@link android.view.KeyEvent#KEYCODE_CTRL_LEFT}
+ * {@link android.view.KeyEvent#KEYCODE_CTRL_RIGHT}
+ * {@link android.view.KeyEvent#KEYCODE_SHIFT_LEFT}
+ * {@link android.view.KeyEvent#KEYCODE_SHIFT_RIGHT}
+ * {@link android.view.KeyEvent#KEYCODE_META_LEFT}
+ * {@link android.view.KeyEvent#KEYCODE_META_RIGHT}
+ * {@link android.view.KeyEvent#KEYCODE_CAPS_LOCK}
+ * {@link android.view.KeyEvent#KEYCODE_SCROLL_LOCK}
+ * {@link android.view.KeyEvent#KEYCODE_NUM_LOCK}
+ * {@link android.view.KeyEvent#KEYCODE_ENTER}
+ * {@link android.view.KeyEvent#KEYCODE_TAB}
+ * {@link android.view.KeyEvent#KEYCODE_SPACE}
+ * {@link android.view.KeyEvent#KEYCODE_DPAD_DOWN}
+ * {@link android.view.KeyEvent#KEYCODE_DPAD_UP}
+ * {@link android.view.KeyEvent#KEYCODE_DPAD_LEFT}
+ * {@link android.view.KeyEvent#KEYCODE_DPAD_RIGHT}
+ * {@link android.view.KeyEvent#KEYCODE_MOVE_END}
+ * {@link android.view.KeyEvent#KEYCODE_MOVE_HOME}
+ * {@link android.view.KeyEvent#KEYCODE_PAGE_DOWN}
+ * {@link android.view.KeyEvent#KEYCODE_PAGE_UP}
+ * {@link android.view.KeyEvent#KEYCODE_DEL}
+ * {@link android.view.KeyEvent#KEYCODE_FORWARD_DEL}
+ * {@link android.view.KeyEvent#KEYCODE_INSERT}
+ * {@link android.view.KeyEvent#KEYCODE_ESCAPE}
+ * {@link android.view.KeyEvent#KEYCODE_BREAK}
+ * {@link android.view.KeyEvent#KEYCODE_BACK}
+ * {@link android.view.KeyEvent#KEYCODE_FORWARD}
*
* @return this builder, to allow for chaining of calls
*/
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java
index b0439d0..c363909 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.java
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java
@@ -61,6 +61,7 @@
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Locale;
import java.util.UUID;
@@ -1576,31 +1577,58 @@
}
/**
- * Additional data conveyed by a {@link KeyphraseRecognitionEvent}
- * for a key phrase detection.
- *
- * @hide
+ * Additional data conveyed by a {@link KeyphraseRecognitionEvent}
+ * for a key phrase detection.
*/
- public static class KeyphraseRecognitionExtra implements Parcelable {
- /** The keyphrase ID */
+ public static final class KeyphraseRecognitionExtra implements Parcelable {
+ /**
+ * The keyphrase ID
+ *
+ * @hide
+ */
@UnsupportedAppUsage
public final int id;
- /** Recognition modes matched for this event */
+ /**
+ * Recognition modes matched for this event
+ *
+ * @hide
+ */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public final int recognitionModes;
- /** Confidence level for mode RECOGNITION_MODE_VOICE_TRIGGER when user identification
- * is not performed */
+ /**
+ * Confidence level for mode RECOGNITION_MODE_VOICE_TRIGGER when user identification
+ * is not performed
+ *
+ * @hide
+ */
@UnsupportedAppUsage
public final int coarseConfidenceLevel;
- /** Confidence levels for all users recognized (KeyphraseRecognitionEvent) or to
- * be recognized (RecognitionConfig) */
+ /**
+ * Confidence levels for all users recognized (KeyphraseRecognitionEvent) or to
+ * be recognized (RecognitionConfig)
+ *
+ * @hide
+ */
@UnsupportedAppUsage
@NonNull
public final ConfidenceLevel[] confidenceLevels;
+
+ /**
+ * @hide
+ */
+ @TestApi
+ public KeyphraseRecognitionExtra(int id, @RecognitionModes int recognitionModes,
+ int coarseConfidenceLevel) {
+ this(id, recognitionModes, coarseConfidenceLevel, new ConfidenceLevel[0]);
+ }
+
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public KeyphraseRecognitionExtra(int id, int recognitionModes, int coarseConfidenceLevel,
@Nullable ConfidenceLevel[] confidenceLevels) {
@@ -1611,7 +1639,47 @@
confidenceLevels != null ? confidenceLevels : new ConfidenceLevel[0];
}
- public static final @android.annotation.NonNull Parcelable.Creator<KeyphraseRecognitionExtra> CREATOR
+ /**
+ * The keyphrase ID associated with this class' additional data
+ */
+ public int getKeyphraseId() {
+ return id;
+ }
+
+ /**
+ * Recognition modes matched for this event
+ */
+ @RecognitionModes
+ public int getRecognitionModes() {
+ return recognitionModes;
+ }
+
+ /**
+ * Confidence level for mode RECOGNITION_MODE_VOICE_TRIGGER when user identification
+ * is not performed
+ *
+ * <p>The confidence level is expressed in percent (0% -100%).
+ */
+ public int getCoarseConfidenceLevel() {
+ return coarseConfidenceLevel;
+ }
+
+ /**
+ * Detected confidence level for users defined in a keyphrase.
+ *
+ * <p>The confidence level is expressed in percent (0% -100%).
+ *
+ * <p>The user ID is derived from the system ID
+ * {@link android.os.UserHandle#getIdentifier()}.
+ *
+ * @hide
+ */
+ @NonNull
+ public Collection<ConfidenceLevel> getConfidenceLevels() {
+ return Arrays.asList(confidenceLevels);
+ }
+
+ public static final @NonNull Parcelable.Creator<KeyphraseRecognitionExtra> CREATOR
= new Parcelable.Creator<KeyphraseRecognitionExtra>() {
public KeyphraseRecognitionExtra createFromParcel(Parcel in) {
return KeyphraseRecognitionExtra.fromParcel(in);
@@ -1632,7 +1700,7 @@
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(id);
dest.writeInt(recognitionModes);
dest.writeInt(coarseConfidenceLevel);
@@ -1657,21 +1725,28 @@
@Override
public boolean equals(@Nullable Object obj) {
- if (this == obj)
+ if (this == obj) {
return true;
- if (obj == null)
+ }
+ if (obj == null) {
return false;
- if (getClass() != obj.getClass())
+ }
+ if (getClass() != obj.getClass()) {
return false;
+ }
KeyphraseRecognitionExtra other = (KeyphraseRecognitionExtra) obj;
- if (!Arrays.equals(confidenceLevels, other.confidenceLevels))
+ if (!Arrays.equals(confidenceLevels, other.confidenceLevels)) {
return false;
- if (id != other.id)
+ }
+ if (id != other.id) {
return false;
- if (recognitionModes != other.recognitionModes)
+ }
+ if (recognitionModes != other.recognitionModes) {
return false;
- if (coarseConfidenceLevel != other.coarseConfidenceLevel)
+ }
+ if (coarseConfidenceLevel != other.coarseConfidenceLevel) {
return false;
+ }
return true;
}
@@ -1715,7 +1790,7 @@
keyphraseExtras != null ? keyphraseExtras : new KeyphraseRecognitionExtra[0];
}
- public static final @android.annotation.NonNull Parcelable.Creator<KeyphraseRecognitionEvent> CREATOR
+ public static final @NonNull Parcelable.Creator<KeyphraseRecognitionEvent> CREATOR
= new Parcelable.Creator<KeyphraseRecognitionEvent>() {
public KeyphraseRecognitionEvent createFromParcel(Parcel in) {
return KeyphraseRecognitionEvent.fromParcelForKeyphrase(in);
diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
index eccbb40..75356d1 100644
--- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
@@ -41,7 +41,9 @@
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodSession;
-class IInputMethodSessionWrapper extends IInputMethodSession.Stub
+/** @hide */
+// TODO(b/215636776): move IInputMethodSessionWrapper to proper package
+public class IInputMethodSessionWrapper extends IInputMethodSession.Stub
implements HandlerCaller.Callback {
private static final String TAG = "InputMethodWrapper";
diff --git a/core/java/android/inputmethodservice/InkWindow.java b/core/java/android/inputmethodservice/InkWindow.java
index 83b053a..499634a 100644
--- a/core/java/android/inputmethodservice/InkWindow.java
+++ b/core/java/android/inputmethodservice/InkWindow.java
@@ -102,11 +102,4 @@
lp.token = token;
setAttributes(lp);
}
-
- /**
- * Returns {@code true} if Window was created and added to WM.
- */
- boolean isInitialized() {
- return mIsViewAdded;
- }
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index b6e1b1f..adf2759 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -578,6 +578,7 @@
private boolean mImeSurfaceScheduledForRemoval;
private ImsConfigurationTracker mConfigTracker = new ImsConfigurationTracker();
private boolean mDestroyed;
+ private boolean mOnPreparedStylusHwCalled;
/** Stylus handwriting Ink window. */
private InkWindow mInkWindow;
@@ -919,9 +920,10 @@
Log.d(TAG, "Input should have started before starting Stylus handwriting.");
return;
}
- if (!mInkWindow.isInitialized()) {
+ if (!mOnPreparedStylusHwCalled) {
// prepare hasn't been called by Stylus HOVER.
onPrepareStylusHandwriting();
+ mOnPreparedStylusHwCalled = true;
}
if (onStartStylusHandwriting()) {
mPrivOps.onStylusHandwritingReady(requestId);
@@ -976,6 +978,7 @@
public void initInkWindow() {
mInkWindow.initOnly();
onPrepareStylusHandwriting();
+ mOnPreparedStylusHwCalled = true;
}
/**
@@ -2354,7 +2357,7 @@
/**
* Called to prepare stylus handwriting.
- * The system calls this before the first {@link #onStartStylusHandwriting} request.
+ * The system calls this before the {@link #onStartStylusHandwriting} request.
*
* <p>Note: The system tries to call this as early as possible, when it detects that
* handwriting stylus input is imminent. However, that a subsequent call to
@@ -2438,6 +2441,7 @@
mInkWindow.hide(false /* remove */);
mPrivOps.finishStylusHandwriting(requestId);
+ mOnPreparedStylusHwCalled = false;
onFinishStylusHandwriting();
}
diff --git a/core/java/android/inputmethodservice/InputMethodServiceInternal.java b/core/java/android/inputmethodservice/InputMethodServiceInternal.java
index 7cd4ff6..09dbb2735 100644
--- a/core/java/android/inputmethodservice/InputMethodServiceInternal.java
+++ b/core/java/android/inputmethodservice/InputMethodServiceInternal.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Bundle;
import android.view.inputmethod.InputConnection;
@@ -31,8 +32,11 @@
* framework classes for internal use.
*
* <p>CAVEATS: {@link AbstractInputMethodService} does not support all the methods here.</p>
+ *
+ * @hide
*/
-interface InputMethodServiceInternal {
+// TODO(b/215636776): move InputMethodServiceInternal to proper package
+public interface InputMethodServiceInternal {
/**
* @return {@link Context} associated with the service.
*/
@@ -70,7 +74,8 @@
* closed for you after you return.
* @param args additional arguments to the dump request.
*/
- default void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
+ default void dump(@SuppressLint("UseParcelFileDescriptor") @NonNull FileDescriptor fd,
+ @NonNull PrintWriter fout, @NonNull String[] args) {
}
/**
@@ -81,6 +86,6 @@
* @param where {@code where} parameter to be passed.
* @param icProto {@code icProto} parameter to be passed.
*/
- default void triggerServiceDump(String where, @Nullable byte[] icProto) {
+ default void triggerServiceDump(@NonNull String where, @Nullable byte[] icProto) {
}
}
diff --git a/core/java/android/inputmethodservice/Keyboard.java b/core/java/android/inputmethodservice/Keyboard.java
index c85fcd9..59c9c50 100644
--- a/core/java/android/inputmethodservice/Keyboard.java
+++ b/core/java/android/inputmethodservice/Keyboard.java
@@ -217,6 +217,7 @@
rowEdgeFlags = a.getInt(com.android.internal.R.styleable.Keyboard_Row_rowEdgeFlags, 0);
mode = a.getResourceId(com.android.internal.R.styleable.Keyboard_Row_keyboardMode,
0);
+ a.recycle();
}
}
diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java
index b780b21..af63dd3 100644
--- a/core/java/android/inputmethodservice/KeyboardView.java
+++ b/core/java/android/inputmethodservice/KeyboardView.java
@@ -326,9 +326,11 @@
}
}
+ a.recycle();
a = mContext.obtainStyledAttributes(
com.android.internal.R.styleable.Theme);
mBackgroundDimAmount = a.getFloat(android.R.styleable.Theme_backgroundDimAmount, 0.5f);
+ a.recycle();
mPreviewPopup = new PopupWindow(context);
if (previewLayout != 0) {
diff --git a/core/java/android/inputmethodservice/RemoteInputConnection.java b/core/java/android/inputmethodservice/RemoteInputConnection.java
index 9ef2579..6b7815d 100644
--- a/core/java/android/inputmethodservice/RemoteInputConnection.java
+++ b/core/java/android/inputmethodservice/RemoteInputConnection.java
@@ -53,8 +53,11 @@
*
* <p>See also {@link IInputContext} for the actual {@link android.os.Binder} IPC protocols under
* the hood.</p>
+ *
+ * @hide
*/
-final class RemoteInputConnection implements InputConnection {
+// TODO(b/215636776): move RemoteInputConnection to proper package
+public final class RemoteInputConnection implements InputConnection {
private static final String TAG = "RemoteInputConnection";
private static final int MAX_WAIT_TIME_MILLIS = 2000;
@@ -95,7 +98,7 @@
@NonNull
private final CancellationGroup mCancellationGroup;
- RemoteInputConnection(
+ public RemoteInputConnection(
@NonNull WeakReference<InputMethodServiceInternal> inputMethodService,
IInputContext inputContext, @NonNull CancellationGroup cancellationGroup) {
mImsInternal = new InputMethodServiceInternalHolder(inputMethodService);
@@ -108,7 +111,7 @@
return mInvoker.isSameConnection(inputContext);
}
- RemoteInputConnection(@NonNull RemoteInputConnection original, int sessionId) {
+ public RemoteInputConnection(@NonNull RemoteInputConnection original, int sessionId) {
mImsInternal = original.mImsInternal;
mInvoker = original.mInvoker.cloneWithSessionId(sessionId);
mCancellationGroup = original.mCancellationGroup;
diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java
index 036607b..0fd3e03 100644
--- a/core/java/android/net/Ikev2VpnProfile.java
+++ b/core/java/android/net/Ikev2VpnProfile.java
@@ -159,8 +159,9 @@
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 @@
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 @@
* 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 @@
mIsBypassable,
mIsMetered,
mMaxMtu,
- mIsRestrictedToTestNetworks);
+ mIsRestrictedToTestNetworks,
+ mExcludeLocalRoutes,
+ mRequiresInternetValidation);
}
@Override
@@ -425,7 +428,8 @@
&& mIsMetered == other.mIsMetered
&& mMaxMtu == other.mMaxMtu
&& mIsRestrictedToTestNetworks == other.mIsRestrictedToTestNetworks
- && mExcludeLocalRoutes == other.mExcludeLocalRoutes;
+ && mExcludeLocalRoutes == other.mExcludeLocalRoutes
+ && mRequiresInternetValidation == other.mRequiresInternetValidation;
}
/**
@@ -439,7 +443,7 @@
@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 @@
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 @@
@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 @@
}
/**
+ * 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 @@
*/
@NonNull
@RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
- public Builder setExcludeLocalRoutes(boolean excludeLocalRoutes) {
+ public Builder setLocalRoutesExcluded(boolean excludeLocalRoutes) {
mExcludeLocalRoutes = excludeLocalRoutes;
return this;
}
@@ -1103,7 +1134,8 @@
mIsMetered,
mMaxMtu,
mIsRestrictedToTestNetworks,
- mExcludeLocalRoutes);
+ mExcludeLocalRoutes,
+ mRequiresInternetValidation);
}
}
}
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index d8f098e..18ec8f5 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -167,6 +167,8 @@
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;
@@ -174,6 +176,9 @@
public static final int FOREGROUND_THRESHOLD_STATE =
ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+ /** @hide */
+ public static final int TOP_THRESHOLD_STATE = ActivityManager.PROCESS_STATE_BOUND_TOP;
+
/**
* {@link Intent} extra that indicates which {@link NetworkTemplate} rule it
* applies to.
@@ -245,6 +250,20 @@
*/
public static final int ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS = 1 << 4;
/**
+ * Flag to indicate that app is exempt from certain network restrictions because of it being
+ * in the bound top or top procstate.
+ *
+ * @hide
+ */
+ public static final int ALLOWED_REASON_TOP = 1 << 5;
+ /**
+ * Flag to indicate that app is exempt from low power standby restrictions because of it being
+ * allowlisted.
+ *
+ * @hide
+ */
+ public static final int ALLOWED_REASON_LOW_POWER_STANDBY_ALLOWLIST = 1 << 6;
+ /**
* Flag to indicate that app is exempt from certain metered network restrictions because user
* explicitly exempted it.
*
@@ -750,6 +769,14 @@
|| (capability & ActivityManager.PROCESS_CAPABILITY_NETWORK) != 0;
}
+ /** @hide */
+ public static boolean isProcStateAllowedWhileInLowPowerStandby(@Nullable UidState uidState) {
+ if (uidState == null) {
+ return false;
+ }
+ return uidState.procState <= TOP_THRESHOLD_STATE;
+ }
+
/**
* Returns true if {@param procState} is considered foreground and as such will be allowed
* to access network when the device is in data saver mode. Otherwise, false.
diff --git a/core/java/android/net/PlatformVpnProfile.java b/core/java/android/net/PlatformVpnProfile.java
index 3c45799..c0fb4cf 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 @@
/** @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,12 +80,28 @@
return mType;
}
+ /**
+ * Returns whether the local traffic is exempted from the VPN.
+ */
+ public final boolean areLocalRoutesExcluded() {
+ return mExcludeLocalRoutes;
+ }
/**
- * Returns if the local traffic is exempted from the VPN.
+ * 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 getExcludeLocalRoutes() {
- return mExcludeLocalRoutes;
+ public final boolean getRequiresInternetValidation() {
+ return mRequiresInternetValidation;
}
/** Returns a type string describing the VPN profile type */
diff --git a/core/java/android/net/VpnManager.java b/core/java/android/net/VpnManager.java
index 9132791..779d931 100644
--- a/core/java/android/net/VpnManager.java
+++ b/core/java/android/net/VpnManager.java
@@ -24,6 +24,7 @@
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 @@
* 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 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}, 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";
/**
- * 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;
/**
+ * {@link #EXTRA_ERROR_CLASS} coding for a recoverable error.
+ *
* The stack experienced an error but will retry with exponential backoff, e.g. network timeout.
- *
- * @hide
*/
- 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.
+ * 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_TIMEOUT = 1;
+ public static final int ERROR_CODE_NETWORK_PROTOCOL_TIMEOUT = 1;
/**
- * An error code to indicate that the connection is refused.
+ * 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_CONNECT = 2;
+ public static final int ERROR_CODE_NETWORK_LOST = 2;
/**
- * An error code to indicate the connection was reset. (e.g. SocketException)
+ * 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_CONNECTION_RESET = 3;
-
- /**
- * An error code to indicate that there is an IOException.
- *
- * @hide
- */
- 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,
diff --git a/core/java/android/net/netstats/NetworkStatsDataMigrationUtils.java b/core/java/android/net/netstats/NetworkStatsDataMigrationUtils.java
index 9772bde..2dd3aaa1 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_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 @@
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 @@
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 @@
.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 @@
* 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/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index ad3de25..244335d 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -31,7 +31,7 @@
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Set;
-import java.util.function.Supplier;
+import java.util.function.Function;
/**
* A mapping from String keys to values of various types. In most cases, you
@@ -252,11 +252,10 @@
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 | BadParcelableException e) {
+ typeWarning("getPairValue()", /* value */ null, "String", e);
return null;
}
}
@@ -309,7 +308,7 @@
}
for (int i = 0, n = mMap.size(); i < n; i++) {
// Triggers deserialization of i-th item, if needed
- getValueAt(i);
+ getValueAt(i, /* clazz */ null);
}
}
}
@@ -324,8 +323,21 @@
* @hide
*/
final Object getValue(String key) {
+ return getValue(key, /* clazz */ null);
+ }
+
+ /**
+ * Returns the value for key {@code key} for expected return type {@param clazz} (or {@code
+ * null} for no type check).
+ *
+ * This call should always be made after {@link #unparcel()} or inside a lock after making sure
+ * {@code mMap} is not null.
+ *
+ * @hide
+ */
+ final <T> T getValue(String key, @Nullable Class<T> clazz) {
int i = mMap.indexOfKey(key);
- return (i >= 0) ? getValueAt(i) : null;
+ return (i >= 0) ? getValueAt(i, clazz) : null;
}
/**
@@ -336,11 +348,12 @@
*
* @hide
*/
- final Object getValueAt(int i) {
+ @SuppressWarnings("unchecked")
+ final <T> T getValueAt(int i, @Nullable Class<T> clazz) {
Object object = mMap.valueAt(i);
- if (object instanceof Supplier<?>) {
+ if (object instanceof Function<?, ?>) {
try {
- object = ((Supplier<?>) object).get();
+ object = ((Function<Class<?>, ?>) object).apply(clazz);
} catch (BadParcelableException e) {
if (sShouldDefuse) {
Log.w(TAG, "Failed to parse item " + mMap.keyAt(i) + ", returning null.", e);
@@ -351,7 +364,7 @@
}
mMap.setValueAt(i, object);
}
- return object;
+ return (clazz != null) ? clazz.cast(object) : (T) object;
}
private void initializeFromParcelLocked(@NonNull Parcel parcelledData, boolean recycleParcel,
@@ -528,7 +541,7 @@
} 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).
@@ -982,15 +995,19 @@
}
// 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,8 +1015,7 @@
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);
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 6dfa995..de1dc80 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -27,6 +27,8 @@
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.location.GnssSignalQuality;
import android.os.BatteryStatsManager.WifiState;
import android.os.BatteryStatsManager.WifiSupplState;
@@ -43,16 +45,16 @@
import android.util.Pair;
import android.util.Printer;
import android.util.SparseArray;
+import android.util.SparseDoubleArray;
import android.util.SparseIntArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.os.BatterySipper;
-import com.android.internal.os.BatteryStatsHelper;
import com.android.internal.os.BatteryUsageStatsProvider;
-import com.android.internal.os.PowerCalculator;
+
+import com.google.android.collect.Lists;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -65,7 +67,9 @@
import java.util.Comparator;
import java.util.Formatter;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
/**
@@ -3535,6 +3539,44 @@
}
}
+ /**
+ * Converts charge in mAh to string.
+ */
+ public static String formatCharge(double power) {
+ return formatValue(power);
+ }
+
+ /**
+ * Converts double to string, limiting small values to 3 significant figures.
+ */
+ private static String formatValue(double value) {
+ if (value == 0) return "0";
+
+ final String format;
+ if (value < .00001) {
+ format = "%.8f";
+ } else if (value < .0001) {
+ format = "%.7f";
+ } else if (value < .001) {
+ format = "%.6f";
+ } else if (value < .01) {
+ format = "%.5f";
+ } else if (value < .1) {
+ format = "%.4f";
+ } else if (value < 1) {
+ format = "%.3f";
+ } else if (value < 10) {
+ format = "%.2f";
+ } else if (value < 100) {
+ format = "%.1f";
+ } else {
+ format = "%.0f";
+ }
+
+ // Use English locale because this is never used in UI (only in checkin and dump).
+ return String.format(Locale.ENGLISH, format, value);
+ }
+
private static long roundUsToMs(long timeUs) {
return (timeUs + 500) / 1000;
}
@@ -4021,7 +4063,7 @@
sb.append(" ");
sb.append(controllerName);
sb.append(" Battery drain: ").append(
- PowerCalculator.formatCharge(powerDrainMaMs / MILLISECONDS_IN_HOUR));
+ formatCharge(powerDrainMaMs / MILLISECONDS_IN_HOUR));
sb.append("mAh");
pw.println(sb.toString());
}
@@ -4126,7 +4168,28 @@
* Temporary for settings.
*/
public final void dumpCheckinLocked(Context context, PrintWriter pw, int which, int reqUid) {
- dumpCheckinLocked(context, pw, which, reqUid, BatteryStatsHelper.checkWifiOnly(context));
+ dumpCheckinLocked(context, pw, which, reqUid, checkWifiOnly(context));
+ }
+
+ private static final String[] CHECKIN_POWER_COMPONENT_LABELS =
+ new String[BatteryConsumer.POWER_COMPONENT_COUNT];
+ static {
+ // Assign individually to avoid future mismatch of indices
+ CHECKIN_POWER_COMPONENT_LABELS[BatteryConsumer.POWER_COMPONENT_SCREEN] = "scrn";
+ CHECKIN_POWER_COMPONENT_LABELS[BatteryConsumer.POWER_COMPONENT_CPU] = "cpu";
+ CHECKIN_POWER_COMPONENT_LABELS[BatteryConsumer.POWER_COMPONENT_BLUETOOTH] = "blue";
+ CHECKIN_POWER_COMPONENT_LABELS[BatteryConsumer.POWER_COMPONENT_CAMERA] = "camera";
+ CHECKIN_POWER_COMPONENT_LABELS[BatteryConsumer.POWER_COMPONENT_AUDIO] = "audio";
+ CHECKIN_POWER_COMPONENT_LABELS[BatteryConsumer.POWER_COMPONENT_VIDEO] = "video";
+ CHECKIN_POWER_COMPONENT_LABELS[BatteryConsumer.POWER_COMPONENT_FLASHLIGHT] = "flashlight";
+ CHECKIN_POWER_COMPONENT_LABELS[BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO] = "cell";
+ CHECKIN_POWER_COMPONENT_LABELS[BatteryConsumer.POWER_COMPONENT_SENSORS] = "sensors";
+ CHECKIN_POWER_COMPONENT_LABELS[BatteryConsumer.POWER_COMPONENT_GNSS] = "gnss";
+ CHECKIN_POWER_COMPONENT_LABELS[BatteryConsumer.POWER_COMPONENT_WIFI] = "wifi";
+ CHECKIN_POWER_COMPONENT_LABELS[BatteryConsumer.POWER_COMPONENT_MEMORY] = "memory";
+ CHECKIN_POWER_COMPONENT_LABELS[BatteryConsumer.POWER_COMPONENT_PHONE] = "phone";
+ CHECKIN_POWER_COMPONENT_LABELS[BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY] = "ambi";
+ CHECKIN_POWER_COMPONENT_LABELS[BatteryConsumer.POWER_COMPONENT_IDLE] = "idle";
}
/**
@@ -4397,74 +4460,36 @@
}
}
- final BatteryStatsHelper helper = new BatteryStatsHelper(context, false, wifiOnly);
- helper.create(this);
- helper.refreshStats(which, UserHandle.USER_ALL);
- final List<BatterySipper> sippers = helper.getUsageList();
- if (sippers != null && sippers.size() > 0) {
- dumpLine(pw, 0 /* uid */, category, POWER_USE_SUMMARY_DATA,
- PowerCalculator.formatCharge(helper.getPowerProfile().getBatteryCapacity()),
- PowerCalculator.formatCharge(helper.getComputedPower()),
- PowerCalculator.formatCharge(helper.getMinDrainedPower()),
- PowerCalculator.formatCharge(helper.getMaxDrainedPower()));
- int uid = 0;
- for (int i=0; i<sippers.size(); i++) {
- final BatterySipper bs = sippers.get(i);
- String label;
- switch (bs.drainType) {
- case AMBIENT_DISPLAY:
- label = "ambi";
- break;
- case IDLE:
- label="idle";
- break;
- case CELL:
- label="cell";
- break;
- case PHONE:
- label="phone";
- break;
- case WIFI:
- label="wifi";
- break;
- case BLUETOOTH:
- label="blue";
- break;
- case SCREEN:
- label="scrn";
- break;
- case FLASHLIGHT:
- label="flashlight";
- break;
- case APP:
- uid = bs.uidObj.getUid();
- label = "uid";
- break;
- case USER:
- uid = UserHandle.getUid(bs.userId, 0);
- label = "user";
- break;
- case UNACCOUNTED:
- label = "unacc";
- break;
- case OVERCOUNTED:
- label = "over";
- break;
- case CAMERA:
- label = "camera";
- break;
- case MEMORY:
- label = "memory";
- break;
- default:
- label = "???";
- }
- dumpLine(pw, uid, category, POWER_USE_ITEM_DATA, label,
- PowerCalculator.formatCharge(bs.totalPowerMah),
- bs.shouldHide ? 1 : 0,
- PowerCalculator.formatCharge(bs.screenPowerMah),
- PowerCalculator.formatCharge(bs.proportionalSmearMah));
+ final BatteryUsageStats stats = getBatteryUsageStats(context);
+ dumpLine(pw, 0 /* uid */, category, POWER_USE_SUMMARY_DATA,
+ formatCharge(stats.getBatteryCapacity()),
+ formatCharge(stats.getConsumedPower()),
+ formatCharge(stats.getDischargedPowerRange().getLower()),
+ formatCharge(stats.getDischargedPowerRange().getUpper()));
+ final BatteryConsumer deviceConsumer = stats.getAggregateBatteryConsumer(
+ BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE);
+ for (@BatteryConsumer.PowerComponent int powerComponent = 0;
+ powerComponent < BatteryConsumer.POWER_COMPONENT_COUNT; powerComponent++) {
+ String label = CHECKIN_POWER_COMPONENT_LABELS[powerComponent];
+ if (label == null) {
+ label = "???";
}
+ dumpLine(pw, 0 /* uid */, category, POWER_USE_ITEM_DATA, label,
+ formatCharge(deviceConsumer.getConsumedPower(powerComponent)),
+ shouldHidePowerComponent(powerComponent) ? 1 : 0, "0", "0");
+ }
+
+ final ProportionalAttributionCalculator proportionalAttributionCalculator =
+ new ProportionalAttributionCalculator(context, stats);
+ final List<UidBatteryConsumer> uidBatteryConsumers = stats.getUidBatteryConsumers();
+ for (int i = 0; i < uidBatteryConsumers.size(); i++) {
+ UidBatteryConsumer consumer = uidBatteryConsumers.get(i);
+ dumpLine(pw, consumer.getUid(), category, POWER_USE_ITEM_DATA, "uid",
+ formatCharge(consumer.getConsumedPower()),
+ proportionalAttributionCalculator.isSystemBatteryConsumer(consumer) ? 1 : 0,
+ formatCharge(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN)),
+ formatCharge(
+ proportionalAttributionCalculator.getProportionalPowerMah(consumer)));
}
final long[] cpuFreqs = getCpuFreqs();
@@ -4897,11 +4922,11 @@
}
private void printmAh(PrintWriter printer, double power) {
- printer.print(PowerCalculator.formatCharge(power));
+ printer.print(formatCharge(power));
}
private void printmAh(StringBuilder sb, double power) {
- sb.append(PowerCalculator.formatCharge(power));
+ sb.append(formatCharge(power));
}
/**
@@ -4909,7 +4934,7 @@
*/
public final void dumpLocked(Context context, PrintWriter pw, String prefix, int which,
int reqUid) {
- dumpLocked(context, pw, prefix, which, reqUid, BatteryStatsHelper.checkWifiOnly(context));
+ dumpLocked(context, pw, prefix, which, reqUid, checkWifiOnly(context));
}
@SuppressWarnings("unused")
@@ -4948,7 +4973,7 @@
sb.setLength(0);
sb.append(prefix);
sb.append(" Estimated battery capacity: ");
- sb.append(PowerCalculator.formatCharge(estimatedBatteryCapacity));
+ sb.append(formatCharge(estimatedBatteryCapacity));
sb.append(" mAh");
pw.println(sb.toString());
}
@@ -4958,7 +4983,7 @@
sb.setLength(0);
sb.append(prefix);
sb.append(" Last learned battery capacity: ");
- sb.append(PowerCalculator.formatCharge(lastLearnedBatteryCapacity / 1000));
+ sb.append(formatCharge(lastLearnedBatteryCapacity / 1000));
sb.append(" mAh");
pw.println(sb.toString());
}
@@ -4967,7 +4992,7 @@
sb.setLength(0);
sb.append(prefix);
sb.append(" Min learned battery capacity: ");
- sb.append(PowerCalculator.formatCharge(minLearnedBatteryCapacity / 1000));
+ sb.append(formatCharge(minLearnedBatteryCapacity / 1000));
sb.append(" mAh");
pw.println(sb.toString());
}
@@ -4976,7 +5001,7 @@
sb.setLength(0);
sb.append(prefix);
sb.append(" Max learned battery capacity: ");
- sb.append(PowerCalculator.formatCharge(maxLearnedBatteryCapacity / 1000));
+ sb.append(formatCharge(maxLearnedBatteryCapacity / 1000));
sb.append(" mAh");
pw.println(sb.toString());
}
@@ -5040,7 +5065,7 @@
sb.setLength(0);
sb.append(prefix);
sb.append(" Discharge: ");
- sb.append(PowerCalculator.formatCharge(dischargeCount / 1000.0));
+ sb.append(formatCharge(dischargeCount / 1000.0));
sb.append(" mAh");
pw.println(sb.toString());
}
@@ -5050,7 +5075,7 @@
sb.setLength(0);
sb.append(prefix);
sb.append(" Screen off discharge: ");
- sb.append(PowerCalculator.formatCharge(dischargeScreenOffCount / 1000.0));
+ sb.append(formatCharge(dischargeScreenOffCount / 1000.0));
sb.append(" mAh");
pw.println(sb.toString());
}
@@ -5060,7 +5085,7 @@
sb.setLength(0);
sb.append(prefix);
sb.append(" Screen doze discharge: ");
- sb.append(PowerCalculator.formatCharge(dischargeScreenDozeCount / 1000.0));
+ sb.append(formatCharge(dischargeScreenDozeCount / 1000.0));
sb.append(" mAh");
pw.println(sb.toString());
}
@@ -5070,7 +5095,7 @@
sb.setLength(0);
sb.append(prefix);
sb.append(" Screen on discharge: ");
- sb.append(PowerCalculator.formatCharge(dischargeScreenOnCount / 1000.0));
+ sb.append(formatCharge(dischargeScreenOnCount / 1000.0));
sb.append(" mAh");
pw.println(sb.toString());
}
@@ -5080,7 +5105,7 @@
sb.setLength(0);
sb.append(prefix);
sb.append(" Device light doze discharge: ");
- sb.append(PowerCalculator.formatCharge(dischargeLightDozeCount / 1000.0));
+ sb.append(formatCharge(dischargeLightDozeCount / 1000.0));
sb.append(" mAh");
pw.println(sb.toString());
}
@@ -5090,7 +5115,7 @@
sb.setLength(0);
sb.append(prefix);
sb.append(" Device deep doze discharge: ");
- sb.append(PowerCalculator.formatCharge(dischargeDeepDozeCount / 1000.0));
+ sb.append(formatCharge(dischargeDeepDozeCount / 1000.0));
sb.append(" mAh");
pw.println(sb.toString());
}
@@ -5224,7 +5249,7 @@
for (int iu = 0; iu < NU; iu++) {
final Uid u = uidStats.valueAt(iu);
- final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelocks
+ final ArrayMap<String, ? extends Uid.Wakelock> wakelocks
= u.getWakelockStats();
for (int iw=wakelocks.size()-1; iw>=0; iw--) {
final Uid.Wakelock wl = wakelocks.valueAt(iw);
@@ -5633,34 +5658,38 @@
.build());
stats.dump(pw, prefix);
- final BatteryStatsHelper helper = new BatteryStatsHelper(context, false, wifiOnly);
- helper.create(this);
- helper.refreshStats(which, UserHandle.USER_ALL);
-
- final List<BatterySipper> sippers = helper.getMobilemsppList();
- if (sippers != null && sippers.size() > 0) {
- pw.print(prefix); pw.println(" Per-app mobile ms per packet:");
+ List<UidMobileRadioStats> uidMobileRadioStats =
+ getUidMobileRadioStats(stats.getUidBatteryConsumers());
+ if (uidMobileRadioStats.size() > 0) {
+ pw.print(prefix);
+ pw.println(" Per-app mobile ms per packet:");
long totalTime = 0;
- for (int i=0; i<sippers.size(); i++) {
- final BatterySipper bs = sippers.get(i);
+ for (int i = 0; i < uidMobileRadioStats.size(); i++) {
+ final UidMobileRadioStats mrs = uidMobileRadioStats.get(i);
sb.setLength(0);
- sb.append(prefix); sb.append(" Uid ");
- UserHandle.formatUid(sb, bs.uidObj.getUid());
+ sb.append(prefix);
+ sb.append(" Uid ");
+ UserHandle.formatUid(sb, mrs.uid);
sb.append(": ");
- sb.append(PowerCalculator.formatCharge(bs.mobilemspp));
- sb.append(" ("); sb.append(bs.mobileRxPackets+bs.mobileTxPackets);
- sb.append(" packets over "); formatTimeMsNoSpace(sb, bs.mobileActive);
- sb.append(") "); sb.append(bs.mobileActiveCount); sb.append("x");
- pw.println(sb.toString());
- totalTime += bs.mobileActive;
+ sb.append(formatValue(mrs.millisecondsPerPacket));
+ sb.append(" (");
+ sb.append(mrs.rxPackets + mrs.txPackets);
+ sb.append(" packets over ");
+ formatTimeMsNoSpace(sb, mrs.radioActiveMs);
+ sb.append(") ");
+ sb.append(mrs.radioActiveCount);
+ sb.append("x");
+ pw.println(sb);
+ totalTime += mrs.radioActiveMs;
}
sb.setLength(0);
sb.append(prefix);
sb.append(" TOTAL TIME: ");
formatTimeMs(sb, totalTime);
- sb.append("("); sb.append(formatRatioLocked(totalTime, whichBatteryRealtime));
+ sb.append("(");
+ sb.append(formatRatioLocked(totalTime, whichBatteryRealtime));
sb.append(")");
- pw.println(sb.toString());
+ pw.println(sb);
pw.println();
}
@@ -5680,13 +5709,13 @@
};
if (reqUid < 0) {
- final Map<String, ? extends BatteryStats.Timer> kernelWakelocks
+ final Map<String, ? extends Timer> kernelWakelocks
= getKernelWakelockStats();
if (kernelWakelocks.size() > 0) {
final ArrayList<TimerEntry> ktimers = new ArrayList<>();
- for (Map.Entry<String, ? extends BatteryStats.Timer> ent
+ for (Map.Entry<String, ? extends Timer> ent
: kernelWakelocks.entrySet()) {
- final BatteryStats.Timer timer = ent.getValue();
+ final Timer timer = ent.getValue();
final long totalTimeMillis = computeWakeLock(timer, rawRealtime, which);
if (totalTimeMillis > 0) {
ktimers.add(new TimerEntry(ent.getKey(), 0, timer, totalTimeMillis));
@@ -5871,8 +5900,7 @@
packets = 1;
}
sb.append(" @ ");
- sb.append(PowerCalculator.formatCharge(
- uidMobileActiveTime / 1000 / (double) packets));
+ sb.append(formatCharge(uidMobileActiveTime / 1000 / (double) packets));
sb.append(" mspp");
pw.println(sb.toString());
}
@@ -6080,7 +6108,7 @@
}
}
- final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelocks
+ final ArrayMap<String, ? extends Uid.Wakelock> wakelocks
= u.getWakelockStats();
long totalFullWakelock = 0, totalPartialWakelock = 0, totalWindowWakelock = 0;
long totalDrawWakelock = 0;
@@ -6308,7 +6336,7 @@
uidActivity |= printTimer(pw, sb, u.getAudioTurnedOnTimer(), rawRealtime, which,
prefix, "Audio");
- final SparseArray<? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats();
+ final SparseArray<? extends Uid.Sensor> sensors = u.getSensorStats();
final int NSE = sensors.size();
for (int ise=0; ise<NSE; ise++) {
final Uid.Sensor se = sensors.valueAt(ise);
@@ -6451,7 +6479,7 @@
}
}
- final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats
+ final ArrayMap<String, ? extends Uid.Proc> processStats
= u.getProcessStats();
for (int ipr=processStats.size()-1; ipr>=0; ipr--) {
final Uid.Proc ps = processStats.valueAt(ipr);
@@ -6525,7 +6553,7 @@
}
}
- final ArrayMap<String, ? extends BatteryStats.Uid.Pkg> packageStats
+ final ArrayMap<String, ? extends Uid.Pkg> packageStats
= u.getPackageStats();
for (int ipkg=packageStats.size()-1; ipkg>=0; ipkg--) {
pw.print(prefix); pw.print(" Apk "); pw.print(packageStats.keyAt(ipkg));
@@ -6542,7 +6570,7 @@
}
final ArrayMap<String, ? extends Uid.Pkg.Serv> serviceStats = ps.getServiceStats();
for (int isvc=serviceStats.size()-1; isvc>=0; isvc--) {
- final BatteryStats.Uid.Pkg.Serv ss = serviceStats.valueAt(isvc);
+ final Uid.Pkg.Serv ss = serviceStats.valueAt(isvc);
final long startTime = ss.getStartTime(batteryUptime, which);
final int starts = ss.getStarts(which);
final int launches = ss.getLaunches(which);
@@ -7625,21 +7653,20 @@
proto.write(BatteryStatsProto.END_PLATFORM_VERSION, getEndPlatformVersion());
if ((flags & DUMP_DAILY_ONLY) == 0) {
- final BatteryStatsHelper helper = new BatteryStatsHelper(context, false,
- (flags & DUMP_DEVICE_WIFI_ONLY) != 0);
- helper.create(this);
- helper.refreshStats(STATS_SINCE_CHARGED, UserHandle.USER_ALL);
-
- dumpProtoAppsLocked(proto, helper, apps);
- dumpProtoSystemLocked(proto, helper);
+ final BatteryUsageStats stats = getBatteryUsageStats(context);
+ ProportionalAttributionCalculator proportionalAttributionCalculator =
+ new ProportionalAttributionCalculator(context, stats);
+ dumpProtoAppsLocked(proto, stats, apps, proportionalAttributionCalculator);
+ dumpProtoSystemLocked(proto, stats);
}
proto.end(bToken);
proto.flush();
}
- private void dumpProtoAppsLocked(ProtoOutputStream proto, BatteryStatsHelper helper,
- List<ApplicationInfo> apps) {
+ private void dumpProtoAppsLocked(ProtoOutputStream proto, BatteryUsageStats stats,
+ List<ApplicationInfo> apps,
+ ProportionalAttributionCalculator proportionalAttributionCalculator) {
final int which = STATS_SINCE_CHARGED;
final long rawUptimeUs = SystemClock.uptimeMillis() * 1000;
final long rawRealtimeMs = SystemClock.elapsedRealtime();
@@ -7660,17 +7687,11 @@
}
}
- SparseArray<BatterySipper> uidToSipper = new SparseArray<>();
- final List<BatterySipper> sippers = helper.getUsageList();
- if (sippers != null) {
- for (int i = 0; i < sippers.size(); ++i) {
- final BatterySipper bs = sippers.get(i);
- if (bs.drainType != BatterySipper.DrainType.APP) {
- // Others are handled by dumpProtoSystemLocked()
- continue;
- }
- uidToSipper.put(bs.uidObj.getUid(), bs);
- }
+ SparseArray<UidBatteryConsumer> uidToConsumer = new SparseArray<>();
+ final List<UidBatteryConsumer> consumers = stats.getUidBatteryConsumers();
+ for (int i = consumers.size() - 1; i >= 0; --i) {
+ final UidBatteryConsumer bs = consumers.get(i);
+ uidToConsumer.put(bs.getUid(), bs);
}
SparseArray<? extends Uid> uidStats = getUidStats();
@@ -7936,14 +7957,16 @@
proto.end(nToken);
// Power use item (POWER_USE_ITEM_DATA)
- BatterySipper bs = uidToSipper.get(uid);
- if (bs != null) {
+ UidBatteryConsumer consumer = uidToConsumer.get(uid);
+ if (consumer != null) {
final long bsToken = proto.start(UidProto.POWER_USE_ITEM);
- proto.write(UidProto.PowerUseItem.COMPUTED_POWER_MAH, bs.totalPowerMah);
- proto.write(UidProto.PowerUseItem.SHOULD_HIDE, bs.shouldHide);
- proto.write(UidProto.PowerUseItem.SCREEN_POWER_MAH, bs.screenPowerMah);
+ proto.write(UidProto.PowerUseItem.COMPUTED_POWER_MAH, consumer.getConsumedPower());
+ proto.write(UidProto.PowerUseItem.SHOULD_HIDE,
+ proportionalAttributionCalculator.isSystemBatteryConsumer(consumer));
+ proto.write(UidProto.PowerUseItem.SCREEN_POWER_MAH,
+ consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN));
proto.write(UidProto.PowerUseItem.PROPORTIONAL_SMEAR_MAH,
- bs.proportionalSmearMah);
+ proportionalAttributionCalculator.getProportionalPowerMah(consumer));
proto.end(bsToken);
}
@@ -8189,7 +8212,7 @@
}
}
- private void dumpProtoSystemLocked(ProtoOutputStream proto, BatteryStatsHelper helper) {
+ private void dumpProtoSystemLocked(ProtoOutputStream proto, BatteryUsageStats stats) {
final long sToken = proto.start(BatteryStatsProto.SYSTEM);
final long rawUptimeUs = SystemClock.uptimeMillis() * 1000;
final long rawRealtimeMs = SystemClock.elapsedRealtime();
@@ -8433,77 +8456,65 @@
multicastWakeLockCountTotal);
proto.end(wmctToken);
- // Power use item (POWER_USE_ITEM_DATA)
- final List<BatterySipper> sippers = helper.getUsageList();
- if (sippers != null) {
- for (int i = 0; i < sippers.size(); ++i) {
- final BatterySipper bs = sippers.get(i);
- int n = SystemProto.PowerUseItem.UNKNOWN_SIPPER;
- int uid = 0;
- switch (bs.drainType) {
- case AMBIENT_DISPLAY:
- n = SystemProto.PowerUseItem.AMBIENT_DISPLAY;
- break;
- case IDLE:
- n = SystemProto.PowerUseItem.IDLE;
- break;
- case CELL:
- n = SystemProto.PowerUseItem.CELL;
- break;
- case PHONE:
- n = SystemProto.PowerUseItem.PHONE;
- break;
- case WIFI:
- n = SystemProto.PowerUseItem.WIFI;
- break;
- case BLUETOOTH:
- n = SystemProto.PowerUseItem.BLUETOOTH;
- break;
- case SCREEN:
- n = SystemProto.PowerUseItem.SCREEN;
- break;
- case FLASHLIGHT:
- n = SystemProto.PowerUseItem.FLASHLIGHT;
- break;
- case APP:
- // dumpProtoAppsLocked will handle this.
- continue;
- case USER:
- n = SystemProto.PowerUseItem.USER;
- uid = UserHandle.getUid(bs.userId, 0);
- break;
- case UNACCOUNTED:
- n = SystemProto.PowerUseItem.UNACCOUNTED;
- break;
- case OVERCOUNTED:
- n = SystemProto.PowerUseItem.OVERCOUNTED;
- break;
- case CAMERA:
- n = SystemProto.PowerUseItem.CAMERA;
- break;
- case MEMORY:
- n = SystemProto.PowerUseItem.MEMORY;
- break;
- }
- final long puiToken = proto.start(SystemProto.POWER_USE_ITEM);
- proto.write(SystemProto.PowerUseItem.NAME, n);
- proto.write(SystemProto.PowerUseItem.UID, uid);
- proto.write(SystemProto.PowerUseItem.COMPUTED_POWER_MAH, bs.totalPowerMah);
- proto.write(SystemProto.PowerUseItem.SHOULD_HIDE, bs.shouldHide);
- proto.write(SystemProto.PowerUseItem.SCREEN_POWER_MAH, bs.screenPowerMah);
- proto.write(SystemProto.PowerUseItem.PROPORTIONAL_SMEAR_MAH,
- bs.proportionalSmearMah);
- proto.end(puiToken);
+ final BatteryConsumer deviceConsumer = stats.getAggregateBatteryConsumer(
+ BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE);
+
+ for (int powerComponent = 0; powerComponent < BatteryConsumer.POWER_COMPONENT_COUNT;
+ powerComponent++) {
+ int n = SystemProto.PowerUseItem.UNKNOWN_SIPPER;
+ switch (powerComponent) {
+ case BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY:
+ n = SystemProto.PowerUseItem.AMBIENT_DISPLAY;
+ break;
+ case BatteryConsumer.POWER_COMPONENT_IDLE:
+ n = SystemProto.PowerUseItem.IDLE;
+ break;
+ case BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO:
+ n = SystemProto.PowerUseItem.CELL;
+ break;
+ case BatteryConsumer.POWER_COMPONENT_PHONE:
+ n = SystemProto.PowerUseItem.PHONE;
+ break;
+ case BatteryConsumer.POWER_COMPONENT_WIFI:
+ n = SystemProto.PowerUseItem.WIFI;
+ break;
+ case BatteryConsumer.POWER_COMPONENT_BLUETOOTH:
+ n = SystemProto.PowerUseItem.BLUETOOTH;
+ break;
+ case BatteryConsumer.POWER_COMPONENT_SCREEN:
+ n = SystemProto.PowerUseItem.SCREEN;
+ break;
+ case BatteryConsumer.POWER_COMPONENT_FLASHLIGHT:
+ n = SystemProto.PowerUseItem.FLASHLIGHT;
+ break;
+ case BatteryConsumer.POWER_COMPONENT_CAMERA:
+ n = SystemProto.PowerUseItem.CAMERA;
+ break;
+ case BatteryConsumer.POWER_COMPONENT_MEMORY:
+ n = SystemProto.PowerUseItem.MEMORY;
+ break;
}
+ final long puiToken = proto.start(SystemProto.POWER_USE_ITEM);
+ proto.write(SystemProto.PowerUseItem.NAME, n);
+ proto.write(SystemProto.PowerUseItem.UID, 0);
+ proto.write(SystemProto.PowerUseItem.COMPUTED_POWER_MAH,
+ deviceConsumer.getConsumedPower(powerComponent));
+ proto.write(SystemProto.PowerUseItem.SHOULD_HIDE,
+ shouldHidePowerComponent(powerComponent));
+ proto.write(SystemProto.PowerUseItem.SCREEN_POWER_MAH, 0);
+ proto.write(SystemProto.PowerUseItem.PROPORTIONAL_SMEAR_MAH, 0);
+ proto.end(puiToken);
}
// Power use summary (POWER_USE_SUMMARY_DATA)
final long pusToken = proto.start(SystemProto.POWER_USE_SUMMARY);
proto.write(SystemProto.PowerUseSummary.BATTERY_CAPACITY_MAH,
- helper.getPowerProfile().getBatteryCapacity());
- proto.write(SystemProto.PowerUseSummary.COMPUTED_POWER_MAH, helper.getComputedPower());
- proto.write(SystemProto.PowerUseSummary.MIN_DRAINED_POWER_MAH, helper.getMinDrainedPower());
- proto.write(SystemProto.PowerUseSummary.MAX_DRAINED_POWER_MAH, helper.getMaxDrainedPower());
+ stats.getBatteryCapacity());
+ proto.write(SystemProto.PowerUseSummary.COMPUTED_POWER_MAH, stats.getConsumedPower());
+ proto.write(SystemProto.PowerUseSummary.MIN_DRAINED_POWER_MAH,
+ stats.getDischargedPowerRange().getLower());
+ proto.write(SystemProto.PowerUseSummary.MAX_DRAINED_POWER_MAH,
+ stats.getDischargedPowerRange().getUpper());
proto.end(pusToken);
// RPM stats (RESOURCE_POWER_MANAGER_DATA)
@@ -8579,4 +8590,162 @@
proto.end(sToken);
}
+
+ /**
+ * Returns true if the device does not have data-capable telephony.
+ */
+ public static boolean checkWifiOnly(Context context) {
+ final TelephonyManager tm = context.getSystemService(TelephonyManager.class);
+ if (tm == null) {
+ return false;
+ }
+ return !tm.isDataCapable();
+ }
+
+ private BatteryUsageStats getBatteryUsageStats(Context context) {
+ final BatteryUsageStatsProvider provider = new BatteryUsageStatsProvider(context, this);
+ final BatteryUsageStatsQuery query =
+ new BatteryUsageStatsQuery.Builder().setMaxStatsAgeMs(0).build();
+ return provider.getBatteryUsageStats(query);
+ }
+
+ private boolean shouldHidePowerComponent(int powerComponent) {
+ return powerComponent == BatteryConsumer.POWER_COMPONENT_IDLE
+ || powerComponent == BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO
+ || powerComponent == BatteryConsumer.POWER_COMPONENT_SCREEN
+ || powerComponent == BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY;
+ }
+
+ private static class ProportionalAttributionCalculator {
+ private static final double SYSTEM_BATTERY_CONSUMER = -1;
+ private final PackageManager mPackageManager;
+ private final HashSet<String> mSystemAndServicePackages;
+ private final SparseDoubleArray mProportionalPowerMah;
+
+ ProportionalAttributionCalculator(Context context, BatteryUsageStats stats) {
+ mPackageManager = context.getPackageManager();
+ final Resources resources = context.getResources();
+ final String[] systemPackageArray = resources.getStringArray(
+ com.android.internal.R.array.config_batteryPackageTypeSystem);
+ final String[] servicePackageArray = resources.getStringArray(
+ com.android.internal.R.array.config_batteryPackageTypeService);
+ mSystemAndServicePackages =
+ new HashSet<>(systemPackageArray.length + servicePackageArray.length);
+ for (String packageName : systemPackageArray) {
+ mSystemAndServicePackages.add(packageName);
+ }
+ for (String packageName : servicePackageArray) {
+ mSystemAndServicePackages.add(packageName);
+ }
+
+ final List<UidBatteryConsumer> uidBatteryConsumers = stats.getUidBatteryConsumers();
+ mProportionalPowerMah = new SparseDoubleArray(uidBatteryConsumers.size());
+ double systemPowerMah = 0;
+ for (int i = uidBatteryConsumers.size() - 1; i >= 0; i--) {
+ UidBatteryConsumer consumer = uidBatteryConsumers.get(i);
+ final int uid = consumer.getUid();
+ if (isSystemUid(uid)) {
+ mProportionalPowerMah.put(uid, SYSTEM_BATTERY_CONSUMER);
+ systemPowerMah += consumer.getConsumedPower();
+ }
+ }
+
+ final double totalRemainingPower = stats.getConsumedPower() - systemPowerMah;
+ if (Math.abs(totalRemainingPower) > 1e-3) {
+ for (int i = uidBatteryConsumers.size() - 1; i >= 0; i--) {
+ UidBatteryConsumer consumer = uidBatteryConsumers.get(i);
+ final int uid = consumer.getUid();
+ if (mProportionalPowerMah.get(uid) != SYSTEM_BATTERY_CONSUMER) {
+ final double power = consumer.getConsumedPower();
+ mProportionalPowerMah.put(uid,
+ power + systemPowerMah * power / totalRemainingPower);
+ }
+ }
+ }
+ }
+
+ boolean isSystemBatteryConsumer(UidBatteryConsumer consumer) {
+ return mProportionalPowerMah.get(consumer.getUid()) < 0;
+ }
+
+ double getProportionalPowerMah(UidBatteryConsumer consumer) {
+ final double powerMah = mProportionalPowerMah.get(consumer.getUid());
+ return powerMah >= 0 ? powerMah : 0;
+ }
+
+ /**
+ * Check whether the UID is one of the system UIDs or a service UID
+ */
+ private boolean isSystemUid(int uid) {
+ if (uid >= Process.ROOT_UID && uid < Process.FIRST_APPLICATION_UID) {
+ return true;
+ }
+
+ final String[] packages = mPackageManager.getPackagesForUid(uid);
+ if (packages == null) {
+ return false;
+ }
+
+ for (String packageName : packages) {
+ if (mSystemAndServicePackages.contains(packageName)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+
+ private static class UidMobileRadioStats {
+ public final int uid;
+ public final long rxPackets;
+ public final long txPackets;
+ public final long radioActiveMs;
+ public final int radioActiveCount;
+ public final double millisecondsPerPacket;
+
+ private UidMobileRadioStats(int uid, long rxPackets, long txPackets, long radioActiveMs,
+ int radioActiveCount, double millisecondsPerPacket) {
+ this.uid = uid;
+ this.txPackets = txPackets;
+ this.rxPackets = rxPackets;
+ this.radioActiveMs = radioActiveMs;
+ this.radioActiveCount = radioActiveCount;
+ this.millisecondsPerPacket = millisecondsPerPacket;
+ }
+ }
+
+ private List<UidMobileRadioStats> getUidMobileRadioStats(
+ List<UidBatteryConsumer> uidBatteryConsumers) {
+ final SparseArray<? extends Uid> uidStats = getUidStats();
+ List<UidMobileRadioStats> uidMobileRadioStats = Lists.newArrayList();
+ for (int i = 0; i < uidBatteryConsumers.size(); i++) {
+ final UidBatteryConsumer consumer = uidBatteryConsumers.get(i);
+ if (consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO) == 0) {
+ continue;
+ }
+
+ final int uid = consumer.getUid();
+ final Uid u = uidStats.get(uid);
+ final long rxPackets = u.getNetworkActivityPackets(
+ BatteryStats.NETWORK_MOBILE_RX_DATA, STATS_SINCE_CHARGED);
+ final long txPackets = u.getNetworkActivityPackets(
+ BatteryStats.NETWORK_MOBILE_TX_DATA, STATS_SINCE_CHARGED);
+ if (rxPackets == 0 && txPackets == 0) {
+ continue;
+ }
+ final long radioActiveMs = u.getMobileRadioActiveTime(STATS_SINCE_CHARGED) / 1000;
+ final int radioActiveCount = u.getMobileRadioActiveCount(STATS_SINCE_CHARGED);
+ final double msPerPacket = (double) radioActiveMs / (rxPackets + txPackets);
+ if (msPerPacket == 0) {
+ continue;
+ }
+ uidMobileRadioStats.add(
+ new UidMobileRadioStats(uid, rxPackets, txPackets, radioActiveMs,
+ radioActiveCount, msPerPacket));
+ }
+ uidMobileRadioStats.sort(
+ (lhs, rhs) -> Double.compare(rhs.millisecondsPerPacket, lhs.millisecondsPerPacket));
+ return uidMobileRadioStats;
+ }
}
diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java
index d41a5fe..58f9336 100644
--- a/core/java/android/os/BatteryUsageStats.java
+++ b/core/java/android/os/BatteryUsageStats.java
@@ -597,20 +597,21 @@
dumpSortedBatteryConsumers(pw, prefix, getUidBatteryConsumers());
dumpSortedBatteryConsumers(pw, prefix, getUserBatteryConsumers());
+ pw.println();
}
private void printPowerComponent(PrintWriter pw, String prefix, String label,
double devicePowerMah, double appsPowerMah, int powerModel, long durationMs) {
StringBuilder sb = new StringBuilder();
sb.append(prefix).append(" ").append(label).append(": ")
- .append(PowerCalculator.formatCharge(devicePowerMah));
+ .append(BatteryStats.formatCharge(devicePowerMah));
if (powerModel != BatteryConsumer.POWER_MODEL_UNDEFINED
&& powerModel != BatteryConsumer.POWER_MODEL_POWER_PROFILE) {
sb.append(" [");
sb.append(BatteryConsumer.powerModelToString(powerModel));
sb.append("]");
}
- sb.append(" apps: ").append(PowerCalculator.formatCharge(appsPowerMah));
+ sb.append(" apps: ").append(BatteryStats.formatCharge(appsPowerMah));
if (durationMs != 0) {
sb.append(" duration: ");
BatteryStats.formatTimeMs(sb, durationMs);
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 9970641..1d39089 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -401,7 +401,12 @@
/**
* All known codenames starting from {@link VERSION_CODES.Q}.
*
- * <p>This includes in development codenames as well.
+ * <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
*/
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index b2bbfd6..2b13f20 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -16,6 +16,9 @@
package android.os;
+import static java.util.Objects.requireNonNull;
+
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.util.ArrayMap;
@@ -914,6 +917,33 @@
/**
* 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.
+ *
+ * <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 or {@code null} for performing no checks.
+ * @return a Parcelable value, or {@code null}
+ *
+ * @hide
+ */
+ @SuppressWarnings("unchecked")
+ @Nullable
+ public <T> T getParcelable(@Nullable String key, @NonNull Class<T> clazz) {
+ unparcel();
+ try {
+ return getValue(key, requireNonNull(clazz));
+ } catch (ClassCastException | BadParcelableException e) {
+ typeWarning(key, /* value */ null, "Parcelable", 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 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 0257408..3d12941 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -1333,7 +1333,7 @@
final Context context = AppGlobals.getInitialApplication();
final int uid = context.getApplicationInfo().uid;
// Isolated processes and Instant apps are never allowed to be in scoped storage
- if (Process.isIsolated(uid)) {
+ if (Process.isIsolated(uid) || Process.isSupplemental(uid)) {
return false;
}
diff --git a/core/java/android/os/FileUriExposedException.java b/core/java/android/os/FileUriExposedException.java
index e47abe2..a3af24d 100644
--- a/core/java/android/os/FileUriExposedException.java
+++ b/core/java/android/os/FileUriExposedException.java
@@ -35,7 +35,7 @@
* or higher. Applications targeting earlier SDK versions are allowed to share
* {@code file://} {@link android.net.Uri}, but it's strongly discouraged.
*
- * @see android.support.v4.content.FileProvider
+ * @see androidx.core.content.FileProvider
* @see Intent#FLAG_GRANT_READ_URI_PERMISSION
*/
public class FileUriExposedException extends RuntimeException {
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index fcce266..39ca596 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -107,9 +107,7 @@
void clearSeedAccountData(int userId);
boolean someUserHasSeedAccount(in String accountName, in String accountType);
boolean someUserHasAccount(in String accountName, in String accountType);
- boolean isProfile(int userId);
- boolean isManagedProfile(int userId);
- boolean isCloneProfile(int userId);
+ String getProfileType(int userId);
boolean isMediaSharedWithParent(int userId);
boolean isCredentialSharedWithParent(int userId);
boolean isDemoUser(int userId);
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 9998e12..ae92353 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -4319,18 +4319,19 @@
}
/**
- * 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 Function} for length-prefixed types that deserializes the object
+ * when {@link Function#apply} is called with the expected class of the return object (or {@code
+ * null} for no type check), for other types it will return the object itself.
*
- * <p>After calling {@link Supplier#get()} the parcel cursor will not change. Note that you
- * shouldn't recycle the parcel, not at least until all objects have been retrieved. No
+ * <p>After calling {@link Function#apply(Object)} 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 Function#apply} has been called on both and both objects returned are equal.
+ * <li>{@link Function#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.
@@ -4357,7 +4358,7 @@
}
- private static final class LazyValue implements Supplier<Object> {
+ private static final class LazyValue implements Function<Class<?>, Object> {
/**
* | 4B | 4B |
* mSource = Parcel{... | type | length | object | ...}
@@ -4389,7 +4390,7 @@
}
@Override
- public Object get() {
+ public Object apply(@Nullable Class<?> clazz) {
Parcel source = mSource;
if (source != null) {
synchronized (source) {
@@ -4398,7 +4399,7 @@
int restore = source.dataPosition();
try {
source.setDataPosition(mPosition);
- mObject = source.readValue(mLoader);
+ mObject = source.readValue(mLoader, clazz);
} finally {
source.setDataPosition(restore);
}
diff --git a/core/java/android/os/PowerComponents.java b/core/java/android/os/PowerComponents.java
index 48e1116..6051712 100644
--- a/core/java/android/os/PowerComponents.java
+++ b/core/java/android/os/PowerComponents.java
@@ -26,8 +26,6 @@
import android.util.TypedXmlSerializer;
import android.util.proto.ProtoOutputStream;
-import com.android.internal.os.PowerCalculator;
-
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -170,7 +168,7 @@
separator = " ";
sb.append(key.toShortString());
sb.append("=");
- sb.append(PowerCalculator.formatCharge(componentPower));
+ sb.append(BatteryStats.formatCharge(componentPower));
if (durationMs != 0) {
sb.append(" (");
@@ -194,7 +192,7 @@
separator = " ";
sb.append(getCustomPowerComponentName(customComponentId));
sb.append("=");
- sb.append(PowerCalculator.formatCharge(customComponentPower));
+ sb.append(BatteryStats.formatCharge(customComponentPower));
}
pw.print(sb);
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 2fe0622..17b5ec5 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -929,6 +929,7 @@
* @hide
*/
@SystemApi(client = MODULE_LIBRARIES)
+ @TestApi
public static final int toSupplementalUid(int uid) {
return uid + (FIRST_SUPPLEMENTAL_UID - FIRST_APPLICATION_UID);
}
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 70aaa5e..412a33a 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -942,7 +942,7 @@
* <p>Instead, apps should use {@code content://} Uris so the platform can extend
* temporary permission for the receiving app to access the resource.
*
- * @see android.support.v4.content.FileProvider
+ * @see androidx.core.content.FileProvider
* @see Intent#FLAG_GRANT_READ_URI_PERMISSION
*/
public @NonNull Builder detectFileUriExposure() {
diff --git a/core/java/android/os/UidBatteryConsumer.java b/core/java/android/os/UidBatteryConsumer.java
index 1a082d1..a1ff923 100644
--- a/core/java/android/os/UidBatteryConsumer.java
+++ b/core/java/android/os/UidBatteryConsumer.java
@@ -136,7 +136,7 @@
}
sb.append(" ").append(processStateToString(processState)).append(": ")
- .append(PowerCalculator.formatCharge(power));
+ .append(BatteryStats.formatCharge(power));
}
static UidBatteryConsumer create(BatteryConsumerData data) {
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 373179c..e56f214 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -98,8 +98,8 @@
/** The userId of the constructor param context. To be used instead of mContext.getUserId(). */
private final @UserIdInt int mUserId;
- private Boolean mIsManagedProfileCached;
- private Boolean mIsProfileCached;
+ /** The userType of UserHandle.myUserId(); empty string if not a profile; null until cached. */
+ private String mProfileTypeOfProcessUser = null;
/**
* User type representing a {@link UserHandle#USER_SYSTEM system} user that is a human user.
@@ -2276,7 +2276,7 @@
* {@link UserManager#USER_TYPE_PROFILE_MANAGED managed profile}.
* @hide
*/
- public static boolean isUserTypeManagedProfile(String userType) {
+ public static boolean isUserTypeManagedProfile(@Nullable String userType) {
return USER_TYPE_PROFILE_MANAGED.equals(userType);
}
@@ -2284,7 +2284,7 @@
* Returns whether the user type is a {@link UserManager#USER_TYPE_FULL_GUEST guest user}.
* @hide
*/
- public static boolean isUserTypeGuest(String userType) {
+ public static boolean isUserTypeGuest(@Nullable String userType) {
return USER_TYPE_FULL_GUEST.equals(userType);
}
@@ -2293,7 +2293,7 @@
* {@link UserManager#USER_TYPE_FULL_RESTRICTED restricted user}.
* @hide
*/
- public static boolean isUserTypeRestricted(String userType) {
+ public static boolean isUserTypeRestricted(@Nullable String userType) {
return USER_TYPE_FULL_RESTRICTED.equals(userType);
}
@@ -2301,7 +2301,7 @@
* Returns whether the user type is a {@link UserManager#USER_TYPE_FULL_DEMO demo user}.
* @hide
*/
- public static boolean isUserTypeDemo(String userType) {
+ public static boolean isUserTypeDemo(@Nullable String userType) {
return USER_TYPE_FULL_DEMO.equals(userType);
}
@@ -2309,7 +2309,7 @@
* Returns whether the user type is a {@link UserManager#USER_TYPE_PROFILE_CLONE clone user}.
* @hide
*/
- public static boolean isUserTypeCloneProfile(String userType) {
+ public static boolean isUserTypeCloneProfile(@Nullable String userType) {
return USER_TYPE_PROFILE_CLONE.equals(userType);
}
@@ -2509,12 +2509,12 @@
}
/**
- * Checks if the calling context user is running in a profile.
+ * Checks if the calling context user is running in a profile. A profile is a user that
+ * typically has its own separate data but shares its UI with some parent user. For example, a
+ * {@link #isManagedProfile() managed profile} is a type of profile.
*
* @return whether the caller is in a profile.
- * @hide
*/
- @SystemApi
@UserHandleAware(
requiresAnyOfPermissionsIfNotCallerProfileGroup = {
android.Manifest.permission.MANAGE_USERS,
@@ -2525,25 +2525,50 @@
}
private boolean isProfile(@UserIdInt int userId) {
- if (userId == mUserId) {
+ final String profileType = getProfileType(userId);
+ return profileType != null && !profileType.equals("");
+ }
+
+ /**
+ * Returns the user type of the context user if it is a profile.
+ *
+ * This is a more specific form of {@link #getUserType()} with relaxed permission requirements.
+ *
+ * @return the user type of the context user if it is a {@link #isProfile() profile},
+ * an empty string if it is not a profile,
+ * or null if the user doesn't exist.
+ */
+ @UserHandleAware(
+ requiresAnyOfPermissionsIfNotCallerProfileGroup = {
+ android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.QUERY_USERS,
+ android.Manifest.permission.INTERACT_ACROSS_USERS})
+ private @Nullable String getProfileType() {
+ return getProfileType(mUserId);
+ }
+
+ /** @see #getProfileType() */
+ private @Nullable String getProfileType(@UserIdInt int userId) {
+ // First, the typical case (i.e. the *process* user, not necessarily the context user).
+ // This cache cannot be become invalidated since it's about the calling process itself.
+ if (userId == UserHandle.myUserId()) {
// No need for synchronization. Once it becomes non-null, it'll be non-null forever.
// Worst case we might end up calling the AIDL method multiple times but that's fine.
- if (mIsProfileCached != null) {
- return mIsProfileCached;
+ if (mProfileTypeOfProcessUser != null) {
+ return mProfileTypeOfProcessUser;
}
try {
- mIsProfileCached = mService.isProfile(mUserId);
- return mIsProfileCached;
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
- } else {
- try {
- return mService.isProfile(userId);
+ final String profileType = mService.getProfileType(userId);
+ if (profileType != null) {
+ return mProfileTypeOfProcessUser = profileType.intern();
+ }
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
}
+
+ // The userId is not for the process's user. Use a slower cache that handles invalidation.
+ return mProfileTypeCache.query(userId);
}
/**
@@ -2577,50 +2602,26 @@
android.Manifest.permission.QUERY_USERS,
android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true)
public boolean isManagedProfile(@UserIdInt int userId) {
- if (userId == mUserId) {
- // No need for synchronization. Once it becomes non-null, it'll be non-null forever.
- // Worst case we might end up calling the AIDL method multiple times but that's fine.
- if (mIsManagedProfileCached != null) {
- return mIsManagedProfileCached;
- }
- try {
- mIsManagedProfileCached = mService.isManagedProfile(mUserId);
- return mIsManagedProfileCached;
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
- } else {
- try {
- return mService.isManagedProfile(userId);
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
- }
+ return isUserTypeManagedProfile(getProfileType(userId));
}
/**
* Checks if the context user is a clone profile.
*
- * <p>Requires {@link android.Manifest.permission#MANAGE_USERS} or
- * {@link android.Manifest.permission#INTERACT_ACROSS_USERS} permission, otherwise the caller
- * must be in the same profile group of the user.
- *
* @return whether the context user is a clone profile.
*
* @see android.os.UserManager#USER_TYPE_PROFILE_CLONE
* @hide
*/
@SystemApi
- @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
- Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true)
- @UserHandleAware
+ @UserHandleAware(
+ requiresAnyOfPermissionsIfNotCallerProfileGroup = {
+ android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.QUERY_USERS,
+ android.Manifest.permission.INTERACT_ACROSS_USERS})
@SuppressAutoDoc
public boolean isCloneProfile() {
- try {
- return mService.isCloneProfile(mUserId);
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
+ return isUserTypeCloneProfile(getProfileType());
}
/**
@@ -4840,15 +4841,16 @@
* @param overrideDevicePolicy when {@code true}, user is removed even if the caller has
* the {@link #DISALLOW_REMOVE_USER} or {@link #DISALLOW_REMOVE_MANAGED_PROFILE} restriction
*
- * @return the result code {@link #REMOVE_RESULT_REMOVED}, {@link #REMOVE_RESULT_DEFERRED},
- * {@link #REMOVE_RESULT_ALREADY_BEING_REMOVED}, or {@link #REMOVE_RESULT_ERROR}.
+ * @return the {@link RemoveResult} code: {@link #REMOVE_RESULT_REMOVED},
+ * {@link #REMOVE_RESULT_DEFERRED}, {@link #REMOVE_RESULT_ALREADY_BEING_REMOVED}, or
+ * {@link #REMOVE_RESULT_ERROR}.
*
* @hide
*/
@SystemApi
@RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
Manifest.permission.CREATE_USERS})
- public int removeUserWhenPossible(@NonNull UserHandle user,
+ public @RemoveResult int removeUserWhenPossible(@NonNull UserHandle user,
boolean overrideDevicePolicy) {
try {
return mService.removeUserWhenPossible(user.getIdentifier(), overrideDevicePolicy);
@@ -5247,6 +5249,33 @@
}
}
+ /* Cache key for anything that assumes that userIds cannot be re-used without rebooting. */
+ private static final String CACHE_KEY_STATIC_USER_PROPERTIES = "cache_key.static_user_props";
+
+ private final PropertyInvalidatedCache<Integer, String> mProfileTypeCache =
+ new PropertyInvalidatedCache<Integer, String>(32, CACHE_KEY_STATIC_USER_PROPERTIES) {
+ @Override
+ public String recompute(Integer query) {
+ try {
+ // Will be null (and not cached) if invalid user; otherwise cache the type.
+ String profileType = mService.getProfileType(query);
+ if (profileType != null) profileType = profileType.intern();
+ return profileType;
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+ @Override
+ public boolean bypass(Integer query) {
+ return query < 0;
+ }
+ };
+
+ /** {@hide} */
+ public static final void invalidateStaticUserProperties() {
+ PropertyInvalidatedCache.invalidateCache(CACHE_KEY_STATIC_USER_PROPERTIES);
+ }
+
/**
* @hide
* User that enforces a restriction.
diff --git a/core/java/android/os/image/IDynamicSystemService.aidl b/core/java/android/os/image/IDynamicSystemService.aidl
index a5a40ad..4e69952 100644
--- a/core/java/android/os/image/IDynamicSystemService.aidl
+++ b/core/java/android/os/image/IDynamicSystemService.aidl
@@ -26,6 +26,7 @@
* @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 @@
* @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 @@
*
* @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 @@
*
* @return GsiProgress
*/
+ @EnforcePermission("MANAGE_DYNAMIC_SYSTEM")
GsiProgress getInstallationProgress();
/**
@@ -66,21 +71,25 @@
*
* @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 @@
*
* @return true if the call succeeds
*/
+ @EnforcePermission("MANAGE_DYNAMIC_SYSTEM")
boolean remove();
/**
@@ -97,6 +107,7 @@
*
* @return true if the call succeeds
*/
+ @EnforcePermission("MANAGE_DYNAMIC_SYSTEM")
boolean setEnable(boolean enable, boolean oneShot);
/**
@@ -106,6 +117,7 @@
* @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 @@
* @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 @@
* @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/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index 0eb21e1..722cdbc 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -203,4 +203,6 @@
void notifyAppIoResumed(in String volumeUuid, int uid, int tid, int reason) = 93;
int getExternalStorageMountMode(int uid, in String packageName) = 94;
boolean isAppIoBlocked(in String volumeUuid, int uid, int tid, int reason) = 95;
+ void setCloudMediaProvider(in String authority) = 96;
+ String getCloudMediaProvider() = 97;
}
\ No newline at end of file
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 052bc6a..4e1337f 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1331,8 +1331,10 @@
/**
* Return the list of shared/external storage volumes currently available to
- * the calling user and the user it shares media with
- * CDD link : https://source.android.com/compatibility/12/android-12-cdd#95_multi-user_support
+ * the calling user and the user it shares media with. Please refer to
+ * <a href="https://source.android.com/compatibility/12/android-12-cdd#95_multi-user_support">
+ * multi-user support</a> for more details.
+ *
* <p>
* This is similar to {@link StorageManager#getStorageVolumes()} except that the result also
* includes the volumes belonging to any user it shares media with
@@ -3000,6 +3002,35 @@
}
}
+ /**
+ * Notify the system of the current cloud media provider.
+ *
+ * This can only be called by the {@link android.service.storage.ExternalStorageService}
+ * holding the {@link android.Manifest.permission#WRITE_MEDIA_STORAGE} permission.
+ *
+ * @param authority the authority of the content provider
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public void setCloudMediaProvider(@Nullable String authority) {
+ try {
+ mStorageManager.setCloudMediaProvider(authority);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** @hide */
+ @TestApi
+ @Nullable
+ public String getCloudMediaProvider() {
+ try {
+ return mStorageManager.getCloudMediaProvider();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
private final Object mFuseAppLoopLock = new Object();
@GuardedBy("mFuseAppLoopLock")
diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java
index 8928a42..059bd84 100644
--- a/core/java/android/os/storage/StorageManagerInternal.java
+++ b/core/java/android/os/storage/StorageManagerInternal.java
@@ -114,7 +114,6 @@
*/
public abstract void prepareAppDataAfterInstall(@NonNull String packageName, int uid);
-
/**
* Return true if uid is external storage service.
*/
@@ -151,4 +150,23 @@
* it's ok to access and modify CE directories on volumes for this user.
*/
public abstract boolean isCeStoragePrepared(@UserIdInt int userId);
+
+ /**
+ * A listener for changes to the cloud provider.
+ */
+ public interface CloudProviderChangeListener {
+ /**
+ * Triggered when the cloud provider changes. A {@code null} value means there's currently
+ * no cloud provider.
+ */
+ void onCloudProviderChanged(int userId, @Nullable String authority);
+ }
+
+ /**
+ * Register a {@link CloudProviderChangeListener} to be notified when a cloud media provider
+ * changes. The listener will be called after registration with any currently set cloud media
+ * providers.
+ */
+ public abstract void registerCloudProviderChangeListener(
+ @NonNull CloudProviderChangeListener listener);
}
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index 12fa0dd..fc7ac11 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -16,6 +16,12 @@
package android.permission;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
import static android.os.Build.VERSION_CODES.S;
import android.Manifest;
@@ -107,6 +113,16 @@
public static final int PERMISSION_HARD_DENIED = 2;
/**
+ * The set of flags that indicate that a permission state has been explicitly set
+ *
+ * @hide
+ */
+ public static final int EXPLICIT_SET_FLAGS = FLAG_PERMISSION_USER_SET
+ | FLAG_PERMISSION_USER_FIXED | FLAG_PERMISSION_POLICY_FIXED
+ | FLAG_PERMISSION_SYSTEM_FIXED | FLAG_PERMISSION_GRANTED_BY_DEFAULT
+ | FLAG_PERMISSION_GRANTED_BY_ROLE;
+
+ /**
* Activity action: Launch UI to review permission decisions.
* <p>
* <strong>Important:</strong>You must protect the activity that handles this action with the
@@ -1447,6 +1463,7 @@
* @hide
*/
@TestApi
+ @RequiresPermission(Manifest.permission.REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL)
public void revokePostNotificationPermissionWithoutKillForTest(@NonNull String packageName,
int userId) {
try {
diff --git a/core/java/android/preference/PreferenceFragment.java b/core/java/android/preference/PreferenceFragment.java
index 22399f5..bbee48b 100644
--- a/core/java/android/preference/PreferenceFragment.java
+++ b/core/java/android/preference/PreferenceFragment.java
@@ -142,7 +142,7 @@
* switch to a new fragment.
*
* @deprecated Use {@link
- * android.support.v7.preference.PreferenceFragmentCompat.OnPreferenceStartFragmentCallback}
+ * androidx.preference.PreferenceFragmentCompat.OnPreferenceStartFragmentCallback}
*/
@Deprecated
public interface OnPreferenceStartFragmentCallback {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index bf94ab5..ea20ed4 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4501,6 +4501,13 @@
public static final String SCREEN_OFF_TIMEOUT = "screen_off_timeout";
/**
+ * The amount of time in milliseconds before the device goes to sleep or begins to dream
+ * after a period of inactivity while it is docked.
+ * @hide
+ */
+ public static final String SCREEN_OFF_TIMEOUT_DOCKED = "screen_off_timeout_docked";
+
+ /**
* The screen backlight brightness between 0 and 255.
*/
@Readable
@@ -10314,6 +10321,34 @@
"nearby_fast_pair_settings_devices_component";
/**
+ * Current provider of the component for requesting ambient context consent.
+ * Default value in @string/config_defaultAmbientContextConsentComponent.
+ * No VALIDATOR as this setting will not be backed up.
+ * @hide
+ */
+ public static final String AMBIENT_CONTEXT_CONSENT_COMPONENT =
+ "ambient_context_consent_component";
+
+ /**
+ * Current provider of the intent extra key for the caller's package name while
+ * requesting ambient context consent.
+ * No VALIDATOR as this setting will not be backed up.
+ * @hide
+ */
+ public static final String AMBIENT_CONTEXT_PACKAGE_NAME_EXTRA_KEY =
+ "ambient_context_package_name_key";
+
+ /**
+ * Current provider of the intent extra key for the event code int array while
+ * requesting ambient context consent.
+ * Default value in @string/config_ambientContextEventArrayExtraKey.
+ * No VALIDATOR as this setting will not be backed up.
+ * @hide
+ */
+ public static final String AMBIENT_CONTEXT_EVENT_ARRAY_EXTRA_KEY =
+ "ambient_context_event_array_key";
+
+ /**
* Controls whether aware is enabled.
* @hide
*/
@@ -10674,6 +10709,19 @@
"hdmi_cec_set_menu_language_denylist";
/**
+ * Whether the Taskbar Education is about to be shown or is currently showing.
+ *
+ * <p>1 if true, 0 or unset otherwise.
+ *
+ * <p>This setting is used to inform other components that the Taskbar Education is
+ * currently showing, which can prevent them from showing something else to the user.
+ *
+ * @hide
+ */
+ public static final String LAUNCHER_TASKBAR_EDUCATION_SHOWING =
+ "launcher_taskbar_education_showing";
+
+ /**
* These entries are considered common between the personal and the managed profile,
* since the managed profile doesn't get to change them.
*/
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 3ff0161..5ff9263 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -2216,651 +2216,6 @@
}
/**
- * Columns for the "rcs_*" tables used by {@link android.telephony.ims.RcsMessageStore} classes.
- *
- * @hide - not meant for public use
- */
- public interface RcsColumns {
- // TODO(sahinc): Turn this to true once the schema finalizes, so that people can update
- // their messaging databases. NOTE: move the switch/case update in MmsSmsDatabaseHelper to
- // the latest version of the database before turning this flag to true.
- boolean IS_RCS_TABLE_SCHEMA_CODE_COMPLETE = false;
-
- /**
- * The authority for the content provider
- */
- String AUTHORITY = "rcs";
-
- /**
- * The URI to start building upon to use {@link com.android.providers.telephony.RcsProvider}
- */
- Uri CONTENT_AND_AUTHORITY = Uri.parse("content://" + AUTHORITY);
-
- /**
- * The value to be used whenever a transaction that expects an integer to be returned
- * failed.
- */
- int TRANSACTION_FAILED = Integer.MIN_VALUE;
-
- /**
- * The value that denotes a timestamp was not set before (e.g. a message that is not
- * delivered yet will not have a DELIVERED_TIMESTAMP)
- */
- long TIMESTAMP_NOT_SET = 0;
-
- /**
- * The table that {@link android.telephony.ims.RcsThread} gets persisted to
- */
- interface RcsThreadColumns {
- /**
- * The path that should be used for referring to
- * {@link android.telephony.ims.RcsThread}s in
- * {@link com.android.providers.telephony.RcsProvider} URIs.
- */
- String RCS_THREAD_URI_PART = "thread";
-
- /**
- * The URI to query or modify {@link android.telephony.ims.RcsThread} via the content
- * provider.
- */
- Uri RCS_THREAD_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY, RCS_THREAD_URI_PART);
-
- /**
- * The unique identifier of an {@link android.telephony.ims.RcsThread}
- */
- String RCS_THREAD_ID_COLUMN = "rcs_thread_id";
- }
-
- /**
- * The table that {@link android.telephony.ims.Rcs1To1Thread} gets persisted to
- */
- interface Rcs1To1ThreadColumns extends RcsThreadColumns {
- /**
- * The path that should be used for referring to
- * {@link android.telephony.ims.Rcs1To1Thread}s in
- * {@link com.android.providers.telephony.RcsProvider} URIs.
- */
- String RCS_1_TO_1_THREAD_URI_PART = "p2p_thread";
-
- /**
- * The URI to query or modify {@link android.telephony.ims.Rcs1To1Thread}s via the
- * content provider. Can also insert to this URI to create a new 1-to-1 thread. When
- * performing an insert, ensure that the provided content values contain the other
- * participant's ID under the key
- * {@link RcsParticipantColumns.RCS_PARTICIPANT_ID_COLUMN}
- */
- Uri RCS_1_TO_1_THREAD_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
- RCS_1_TO_1_THREAD_URI_PART);
-
- /**
- * The SMS/MMS thread to fallback to in case of an RCS outage
- */
- String FALLBACK_THREAD_ID_COLUMN = "rcs_fallback_thread_id";
- }
-
- /**
- * The table that {@link android.telephony.ims.RcsGroupThread} gets persisted to
- */
- interface RcsGroupThreadColumns extends RcsThreadColumns {
- /**
- * The path that should be used for referring to
- * {@link android.telephony.ims.RcsGroupThread}s in
- * {@link com.android.providers.telephony.RcsProvider} URIs.
- */
- String RCS_GROUP_THREAD_URI_PART = "group_thread";
-
- /**
- * The URI to query or modify {@link android.telephony.ims.RcsGroupThread}s via the
- * content provider
- */
- Uri RCS_GROUP_THREAD_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
- RCS_GROUP_THREAD_URI_PART);
-
- /**
- * The owner/admin of the {@link android.telephony.ims.RcsGroupThread}
- */
- String OWNER_PARTICIPANT_COLUMN = "owner_participant";
-
- /**
- * The user visible name of the group
- */
- String GROUP_NAME_COLUMN = "group_name";
-
- /**
- * The user visible icon of the group
- */
- String GROUP_ICON_COLUMN = "group_icon";
-
- /**
- * The RCS conference URI for this group
- */
- String CONFERENCE_URI_COLUMN = "conference_uri";
- }
-
- /**
- * The view that enables polling from all types of RCS threads at once
- */
- interface RcsUnifiedThreadColumns extends RcsThreadColumns, Rcs1To1ThreadColumns,
- RcsGroupThreadColumns {
- /**
- * The type of this {@link android.telephony.ims.RcsThread}
- */
- String THREAD_TYPE_COLUMN = "thread_type";
-
- /**
- * Integer returned as a result from a database query that denotes the thread is 1 to 1
- */
- int THREAD_TYPE_1_TO_1 = 0;
-
- /**
- * Integer returned as a result from a database query that denotes the thread is 1 to 1
- */
- int THREAD_TYPE_GROUP = 1;
- }
-
- /**
- * The table that {@link android.telephony.ims.RcsParticipant} gets persisted to
- */
- interface RcsParticipantColumns {
- /**
- * The path that should be used for referring to
- * {@link android.telephony.ims.RcsParticipant}s in
- * {@link com.android.providers.telephony.RcsProvider} URIs.
- */
- String RCS_PARTICIPANT_URI_PART = "participant";
-
- /**
- * The URI to query or modify {@link android.telephony.ims.RcsParticipant}s via the
- * content provider
- */
- Uri RCS_PARTICIPANT_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
- RCS_PARTICIPANT_URI_PART);
-
- /**
- * The unique identifier of the entry in the database
- */
- String RCS_PARTICIPANT_ID_COLUMN = "rcs_participant_id";
-
- /**
- * A foreign key on canonical_address table, also used by SMS/MMS
- */
- String CANONICAL_ADDRESS_ID_COLUMN = "canonical_address_id";
-
- /**
- * The user visible RCS alias for this participant.
- */
- String RCS_ALIAS_COLUMN = "rcs_alias";
- }
-
- /**
- * Additional constants to enable access to {@link android.telephony.ims.RcsParticipant}
- * related data
- */
- interface RcsParticipantHelpers extends RcsParticipantColumns {
- /**
- * The view that unifies "rcs_participant" and "canonical_addresses" tables for easy
- * access to participant address.
- */
- String RCS_PARTICIPANT_WITH_ADDRESS_VIEW = "rcs_participant_with_address_view";
-
- /**
- * The view that unifies "rcs_participant", "canonical_addresses" and
- * "rcs_thread_participant" junction table to get full information on participants that
- * contribute to threads.
- */
- String RCS_PARTICIPANT_WITH_THREAD_VIEW = "rcs_participant_with_thread_view";
- }
-
- /**
- * The table that {@link android.telephony.ims.RcsMessage} gets persisted to
- */
- interface RcsMessageColumns {
- /**
- * Denotes the type of this message (i.e.
- * {@link android.telephony.ims.RcsIncomingMessage} or
- * {@link android.telephony.ims.RcsOutgoingMessage}
- */
- String MESSAGE_TYPE_COLUMN = "rcs_message_type";
-
- /**
- * The unique identifier for the message in the database - i.e. the primary key.
- */
- String MESSAGE_ID_COLUMN = "rcs_message_row_id";
-
- /**
- * The globally unique RCS identifier for the message. Please see 4.4.5.2 - GSMA
- * RCC.53 (RCS Device API 1.6 Specification)
- */
- String GLOBAL_ID_COLUMN = "rcs_message_global_id";
-
- /**
- * The subscription where this message was sent from/to.
- */
- String SUB_ID_COLUMN = "sub_id";
-
- /**
- * The sending status of the message.
- * @see android.telephony.ims.RcsMessage.RcsMessageStatus
- */
- String STATUS_COLUMN = "status";
-
- /**
- * The creation timestamp of the message.
- */
- String ORIGINATION_TIMESTAMP_COLUMN = "origination_timestamp";
-
- /**
- * The text content of the message.
- */
- String MESSAGE_TEXT_COLUMN = "rcs_text";
-
- /**
- * The latitude content of the message, if it contains a location.
- */
- String LATITUDE_COLUMN = "latitude";
-
- /**
- * The longitude content of the message, if it contains a location.
- */
- String LONGITUDE_COLUMN = "longitude";
- }
-
- /**
- * The table that additional information of {@link android.telephony.ims.RcsIncomingMessage}
- * gets persisted to.
- */
- interface RcsIncomingMessageColumns extends RcsMessageColumns {
- /**
- The path that should be used for referring to
- * {@link android.telephony.ims.RcsIncomingMessage}s in
- * {@link com.android.providers.telephony.RcsProvider} URIs.
- */
- String INCOMING_MESSAGE_URI_PART = "incoming_message";
-
- /**
- * The URI to query incoming messages through
- * {@link com.android.providers.telephony.RcsProvider}
- */
- Uri INCOMING_MESSAGE_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
- INCOMING_MESSAGE_URI_PART);
-
- /**
- * The ID of the {@link android.telephony.ims.RcsParticipant} that sent this message
- */
- String SENDER_PARTICIPANT_ID_COLUMN = "sender_participant";
-
- /**
- * The timestamp of arrival for this message.
- */
- String ARRIVAL_TIMESTAMP_COLUMN = "arrival_timestamp";
-
- /**
- * The time when the recipient has read this message.
- */
- String SEEN_TIMESTAMP_COLUMN = "seen_timestamp";
- }
-
- /**
- * The table that additional information of {@link android.telephony.ims.RcsOutgoingMessage}
- * gets persisted to.
- */
- interface RcsOutgoingMessageColumns extends RcsMessageColumns {
- /**
- * The path that should be used for referring to
- * {@link android.telephony.ims.RcsOutgoingMessage}s in
- * {@link com.android.providers.telephony.RcsProvider} URIs.
- */
- String OUTGOING_MESSAGE_URI_PART = "outgoing_message";
-
- /**
- * The URI to query or modify {@link android.telephony.ims.RcsOutgoingMessage}s via the
- * content provider
- */
- Uri OUTGOING_MESSAGE_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
- OUTGOING_MESSAGE_URI_PART);
- }
-
- /**
- * The delivery information of an {@link android.telephony.ims.RcsOutgoingMessage}
- */
- interface RcsMessageDeliveryColumns extends RcsOutgoingMessageColumns {
- /**
- * The path that should be used for referring to
- * {@link android.telephony.ims.RcsOutgoingMessageDelivery}s in
- * {@link com.android.providers.telephony.RcsProvider} URIs.
- */
- String DELIVERY_URI_PART = "delivery";
-
- /**
- * The timestamp of delivery of this message.
- */
- String DELIVERED_TIMESTAMP_COLUMN = "delivered_timestamp";
-
- /**
- * The time when the recipient has read this message.
- */
- String SEEN_TIMESTAMP_COLUMN = "seen_timestamp";
- }
-
- /**
- * The views that allow querying {@link android.telephony.ims.RcsIncomingMessage} and
- * {@link android.telephony.ims.RcsOutgoingMessage} at the same time.
- */
- interface RcsUnifiedMessageColumns extends RcsIncomingMessageColumns,
- RcsOutgoingMessageColumns {
- /**
- * The path that is used to query all {@link android.telephony.ims.RcsMessage} in
- * {@link com.android.providers.telephony.RcsProvider} URIs.
- */
- String UNIFIED_MESSAGE_URI_PART = "message";
-
- /**
- * The URI to query all types of {@link android.telephony.ims.RcsMessage}s
- */
- Uri UNIFIED_MESSAGE_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
- UNIFIED_MESSAGE_URI_PART);
-
- /**
- * The name of the view that unites rcs_message and rcs_incoming_message tables.
- */
- String UNIFIED_INCOMING_MESSAGE_VIEW = "unified_incoming_message_view";
-
- /**
- * The name of the view that unites rcs_message and rcs_outgoing_message tables.
- */
- String UNIFIED_OUTGOING_MESSAGE_VIEW = "unified_outgoing_message_view";
-
- /**
- * The column that shows from which table the message entry came from.
- */
- String MESSAGE_TYPE_COLUMN = "message_type";
-
- /**
- * Integer returned as a result from a database query that denotes that the message is
- * an incoming message
- */
- int MESSAGE_TYPE_INCOMING = 1;
-
- /**
- * Integer returned as a result from a database query that denotes that the message is
- * an outgoing message
- */
- int MESSAGE_TYPE_OUTGOING = 0;
- }
-
- /**
- * The table that {@link android.telephony.ims.RcsFileTransferPart} gets persisted to.
- */
- interface RcsFileTransferColumns {
- /**
- * The path that should be used for referring to
- * {@link android.telephony.ims.RcsFileTransferPart}s in
- * {@link com.android.providers.telephony.RcsProvider} URIs.
- */
- String FILE_TRANSFER_URI_PART = "file_transfer";
-
- /**
- * The URI to query or modify {@link android.telephony.ims.RcsFileTransferPart}s via the
- * content provider
- */
- Uri FILE_TRANSFER_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
- FILE_TRANSFER_URI_PART);
-
- /**
- * The globally unique file transfer ID for this RCS file transfer.
- */
- String FILE_TRANSFER_ID_COLUMN = "rcs_file_transfer_id";
-
- /**
- * The RCS session ID for this file transfer. The ID is implementation dependent but
- * should be unique.
- */
- String SESSION_ID_COLUMN = "session_id";
-
- /**
- * The URI that points to the content of this file transfer
- */
- String CONTENT_URI_COLUMN = "content_uri";
-
- /**
- * The file type of this file transfer in bytes. The validity of types is not enforced
- * in {@link android.telephony.ims.RcsMessageStore} APIs.
- */
- String CONTENT_TYPE_COLUMN = "content_type";
-
- /**
- * The size of the file transfer in bytes.
- */
- String FILE_SIZE_COLUMN = "file_size";
-
- /**
- * Number of bytes that was successfully transmitted for this file transfer
- */
- String SUCCESSFULLY_TRANSFERRED_BYTES = "transfer_offset";
-
- /**
- * The status of this file transfer
- * @see android.telephony.ims.RcsFileTransferPart.RcsFileTransferStatus
- */
- String TRANSFER_STATUS_COLUMN = "transfer_status";
-
- /**
- * The on-screen width of the file transfer, if it contains multi-media
- */
- String WIDTH_COLUMN = "width";
-
- /**
- * The on-screen height of the file transfer, if it contains multi-media
- */
- String HEIGHT_COLUMN = "height";
-
- /**
- * The duration of the content in milliseconds if this file transfer contains
- * multi-media
- */
- String DURATION_MILLIS_COLUMN = "duration";
-
- /**
- * The URI to the preview of the content of this file transfer
- */
- String PREVIEW_URI_COLUMN = "preview_uri";
-
- /**
- * The type of the preview of the content of this file transfer. The validity of types
- * is not enforced in {@link android.telephony.ims.RcsMessageStore} APIs.
- */
- String PREVIEW_TYPE_COLUMN = "preview_type";
- }
-
- /**
- * The table that holds the information for
- * {@link android.telephony.ims.RcsGroupThreadEvent} and its subclasses.
- */
- interface RcsThreadEventColumns {
- /**
- * The string used in the {@link com.android.providers.telephony.RcsProvider} URI to
- * refer to participant joined events (example URI:
- * {@code content://rcs/group_thread/3/participant_joined_event})
- */
- String PARTICIPANT_JOINED_URI_PART = "participant_joined_event";
-
- /**
- * The string used in the {@link com.android.providers.telephony.RcsProvider} URI to
- * refer to participant left events. (example URI:
- * {@code content://rcs/group_thread/3/participant_left_event/4})
- */
- String PARTICIPANT_LEFT_URI_PART = "participant_left_event";
-
- /**
- * The string used in the {@link com.android.providers.telephony.RcsProvider} URI to
- * refer to name changed events. (example URI:
- * {@code content://rcs/group_thread/3/name_changed_event})
- */
- String NAME_CHANGED_URI_PART = "name_changed_event";
-
- /**
- * The string used in the {@link com.android.providers.telephony.RcsProvider} URI to
- * refer to icon changed events. (example URI:
- * {@code content://rcs/group_thread/3/icon_changed_event})
- */
- String ICON_CHANGED_URI_PART = "icon_changed_event";
-
- /**
- * The unique ID of this event in the database, i.e. the primary key
- */
- String EVENT_ID_COLUMN = "event_id";
-
- /**
- * The type of this event
- *
- * @see RcsEventTypes
- */
- String EVENT_TYPE_COLUMN = "event_type";
-
- /**
- * The timestamp in milliseconds of when this event happened
- */
- String TIMESTAMP_COLUMN = "origination_timestamp";
-
- /**
- * The participant that generated this event
- */
- String SOURCE_PARTICIPANT_ID_COLUMN = "source_participant";
-
- /**
- * The receiving participant of this event if this was an
- * {@link android.telephony.ims.RcsGroupThreadParticipantJoinedEvent} or
- * {@link android.telephony.ims.RcsGroupThreadParticipantLeftEvent}
- */
- String DESTINATION_PARTICIPANT_ID_COLUMN = "destination_participant";
-
- /**
- * The URI for the new icon of the group thread if this was an
- * {@link android.telephony.ims.RcsGroupThreadIconChangedEvent}
- */
- String NEW_ICON_URI_COLUMN = "new_icon_uri";
-
- /**
- * The URI for the new name of the group thread if this was an
- * {@link android.telephony.ims.RcsGroupThreadNameChangedEvent}
- */
- String NEW_NAME_COLUMN = "new_name";
- }
-
- /**
- * The table that {@link android.telephony.ims.RcsParticipantAliasChangedEvent} gets
- * persisted to
- */
- interface RcsParticipantEventColumns {
- /**
- * The path that should be used for referring to
- * {@link android.telephony.ims.RcsParticipantAliasChangedEvent}s in
- * {@link com.android.providers.telephony.RcsProvider} URIs.
- */
- String ALIAS_CHANGE_EVENT_URI_PART = "alias_change_event";
-
- /**
- * The new alias of the participant
- */
- String NEW_ALIAS_COLUMN = "new_alias";
- }
-
- /**
- * These values are used in {@link com.android.providers.telephony.RcsProvider} to determine
- * what kind of event is present in the storage.
- */
- interface RcsEventTypes {
- /**
- * Integer constant that is stored in the
- * {@link com.android.providers.telephony.RcsProvider} database that denotes the event
- * is of type {@link android.telephony.ims.RcsParticipantAliasChangedEvent}
- */
- int PARTICIPANT_ALIAS_CHANGED_EVENT_TYPE = 1;
-
- /**
- * Integer constant that is stored in the
- * {@link com.android.providers.telephony.RcsProvider} database that denotes the event
- * is of type {@link android.telephony.ims.RcsGroupThreadParticipantJoinedEvent}
- */
- int PARTICIPANT_JOINED_EVENT_TYPE = 2;
-
- /**
- * Integer constant that is stored in the
- * {@link com.android.providers.telephony.RcsProvider} database that denotes the event
- * is of type {@link android.telephony.ims.RcsGroupThreadParticipantLeftEvent}
- */
- int PARTICIPANT_LEFT_EVENT_TYPE = 4;
-
- /**
- * Integer constant that is stored in the
- * {@link com.android.providers.telephony.RcsProvider} database that denotes the event
- * is of type {@link android.telephony.ims.RcsGroupThreadIconChangedEvent}
- */
- int ICON_CHANGED_EVENT_TYPE = 8;
-
- /**
- * Integer constant that is stored in the
- * {@link com.android.providers.telephony.RcsProvider} database that denotes the event
- * is of type {@link android.telephony.ims.RcsGroupThreadNameChangedEvent}
- */
- int NAME_CHANGED_EVENT_TYPE = 16;
- }
-
- /**
- * The view that allows unified querying across all events
- */
- interface RcsUnifiedEventHelper extends RcsParticipantEventColumns, RcsThreadEventColumns {
- /**
- * The path that should be used for referring to
- * {@link android.telephony.ims.RcsEvent}s in
- * {@link com.android.providers.telephony.RcsProvider} URIs.
- */
- String RCS_EVENT_QUERY_URI_PATH = "event";
-
- /**
- * The URI to query {@link android.telephony.ims.RcsEvent}s via the content provider.
- */
- Uri RCS_EVENT_QUERY_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
- RCS_EVENT_QUERY_URI_PATH);
- }
-
- /**
- * Allows RCS specific canonical address handling.
- */
- interface RcsCanonicalAddressHelper {
- /**
- * Returns the canonical address ID for a canonical address, if now row exists, this
- * will add a row and return its ID. This helper works against the same table used by
- * the SMS and MMS threads, but is accessible only by the phone process for use by RCS
- * message storage.
- *
- * @throws IllegalArgumentException if unable to retrieve or create the canonical
- * address entry.
- */
- static long getOrCreateCanonicalAddressId(
- ContentResolver contentResolver, String canonicalAddress) {
-
- Uri.Builder uriBuilder = CONTENT_AND_AUTHORITY.buildUpon();
- uriBuilder.appendPath("canonical-address");
- uriBuilder.appendQueryParameter("address", canonicalAddress);
- Uri uri = uriBuilder.build();
-
- try (Cursor cursor = contentResolver.query(uri, null, null, null)) {
- if (cursor != null && cursor.moveToFirst()) {
- return cursor.getLong(cursor.getColumnIndex(CanonicalAddressesColumns._ID));
- } else {
- Rlog.e(TAG, "getOrCreateCanonicalAddressId returned no rows");
- }
- }
-
- Rlog.e(TAG, "getOrCreateCanonicalAddressId failed");
- throw new IllegalArgumentException(
- "Unable to find or allocate a canonical address ID");
- }
- }
- }
-
- /**
* Contains all MMS messages.
*/
public static final class Mms implements BaseMmsColumns {
diff --git a/core/java/android/app/ambientcontext/AmbientContextEventResponse.aidl b/core/java/android/service/ambientcontext/AmbientContextDetectionResult.aidl
similarity index 80%
rename from core/java/android/app/ambientcontext/AmbientContextEventResponse.aidl
rename to core/java/android/service/ambientcontext/AmbientContextDetectionResult.aidl
index 4dc6466..4bb29b2 100644
--- a/core/java/android/app/ambientcontext/AmbientContextEventResponse.aidl
+++ b/core/java/android/service/ambientcontext/AmbientContextDetectionResult.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 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,6 @@
* limitations under the License.
*/
-package android.app.ambientcontext;
+package android.service.ambientcontext;
-parcelable AmbientContextEventResponse;
\ No newline at end of file
+parcelable AmbientContextDetectionResult;
\ No newline at end of file
diff --git a/core/java/android/service/ambientcontext/AmbientContextDetectionResult.java b/core/java/android/service/ambientcontext/AmbientContextDetectionResult.java
new file mode 100644
index 0000000..227194e
--- /dev/null
+++ b/core/java/android/service/ambientcontext/AmbientContextDetectionResult.java
@@ -0,0 +1,180 @@
+/*
+ * 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.service.ambientcontext;
+
+import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.app.ambientcontext.AmbientContextEvent;
+import android.os.Parcelable;
+
+import com.android.internal.util.AnnotationValidations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a {@code AmbientContextEvent} detection result reported by the detection service.
+ *
+ * @hide
+ */
+@SystemApi
+public final class AmbientContextDetectionResult implements Parcelable {
+
+ /**
+ * The bundle key for this class of object, used in {@code RemoteCallback#sendResult}.
+ *
+ * @hide
+ */
+ public static final String RESULT_RESPONSE_BUNDLE_KEY =
+ "android.app.ambientcontext.AmbientContextDetectionResultBundleKey";
+ @NonNull private final List<AmbientContextEvent> mEvents;
+ @NonNull private final String mPackageName;
+
+ AmbientContextDetectionResult(
+ @NonNull List<AmbientContextEvent> events,
+ @NonNull String packageName) {
+ this.mEvents = events;
+ AnnotationValidations.validate(NonNull.class, null, mEvents);
+ this.mPackageName = packageName;
+ AnnotationValidations.validate(NonNull.class, null, mPackageName);
+ }
+
+ /**
+ * A list of detected event.
+ */
+ @SuppressLint("ConcreteCollection")
+ public @NonNull List<AmbientContextEvent> getEvents() {
+ return mEvents;
+ }
+
+ /**
+ * The package to deliver the response to.
+ */
+ public @NonNull String getPackageName() {
+ return mPackageName;
+ }
+
+ @Override
+ public String toString() {
+ return "AmbientContextEventResponse { "
+ + "events = " + mEvents + ", " + "packageName = " + mPackageName + " }";
+ }
+
+ @Override
+ public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+ byte flg = 0;
+ dest.writeByte(flg);
+ dest.writeParcelableList(mEvents, flags);
+ dest.writeString(mPackageName);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ AmbientContextDetectionResult(@NonNull android.os.Parcel in) {
+ byte flg = in.readByte();
+ ArrayList<AmbientContextEvent> events = new ArrayList<>();
+ in.readParcelableList(events, AmbientContextEvent.class.getClassLoader(),
+ AmbientContextEvent.class);
+ String packageName = in.readString();
+
+ this.mEvents = events;
+ AnnotationValidations.validate(
+ NonNull.class, null, mEvents);
+ this.mPackageName = packageName;
+ AnnotationValidations.validate(
+ NonNull.class, null, mPackageName);
+ }
+
+ public static final @NonNull Creator<AmbientContextDetectionResult> CREATOR =
+ new Creator<AmbientContextDetectionResult>() {
+ @Override
+ public AmbientContextDetectionResult[] newArray(int size) {
+ return new AmbientContextDetectionResult[size];
+ }
+
+ @Override
+ public AmbientContextDetectionResult createFromParcel(@NonNull android.os.Parcel in) {
+ return new AmbientContextDetectionResult(in);
+ }
+ };
+
+ /**
+ * A builder for {@link AmbientContextDetectionResult}
+ */
+ @SuppressWarnings("WeakerAccess")
+ public static final class Builder {
+ private @NonNull ArrayList<AmbientContextEvent> mEvents;
+ private @NonNull String mPackageName;
+ private long mBuilderFieldsSet = 0L;
+
+ public Builder() {
+ }
+
+ /**
+ * Adds an event to the builder.
+ */
+ public @NonNull Builder addEvent(@NonNull AmbientContextEvent value) {
+ checkNotUsed();
+ if (mEvents == null) {
+ mBuilderFieldsSet |= 0x1;
+ mEvents = new ArrayList<>();
+ }
+ mEvents.add(value);
+ return this;
+ }
+
+ /**
+ * The package to deliver the response to.
+ */
+ public @NonNull Builder setPackageName(@NonNull String value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x2;
+ mPackageName = value;
+ return this;
+ }
+
+ /** Builds the instance. This builder should not be touched after calling this! */
+ public @NonNull AmbientContextDetectionResult build() {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x4; // Mark builder used
+
+ if ((mBuilderFieldsSet & 0x1) == 0) {
+ mEvents = new ArrayList<>();
+ }
+ if ((mBuilderFieldsSet & 0x2) == 0) {
+ mPackageName = "";
+ }
+ AmbientContextDetectionResult o = new AmbientContextDetectionResult(
+ mEvents,
+ mPackageName);
+ return o;
+ }
+
+ private void checkNotUsed() {
+ if ((mBuilderFieldsSet & 0x4) != 0) {
+ throw new IllegalStateException(
+ "This Builder should not be reused. Use a new Builder instance instead");
+ }
+ }
+ }
+}
diff --git a/core/java/android/service/ambientcontext/AmbientContextDetectionService.java b/core/java/android/service/ambientcontext/AmbientContextDetectionService.java
index dccfe36..6224aa1 100644
--- a/core/java/android/service/ambientcontext/AmbientContextDetectionService.java
+++ b/core/java/android/service/ambientcontext/AmbientContextDetectionService.java
@@ -16,13 +16,13 @@
package android.service.ambientcontext;
+import android.annotation.BinderThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.app.Service;
import android.app.ambientcontext.AmbientContextEvent;
import android.app.ambientcontext.AmbientContextEventRequest;
-import android.app.ambientcontext.AmbientContextEventResponse;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
@@ -64,15 +64,6 @@
public static final String SERVICE_INTERFACE =
"android.service.ambientcontext.AmbientContextDetectionService";
- /**
- * The key for the bundle the parameter of {@code RemoteCallback#sendResult}. Implementation
- * should set bundle result with this key.
- *
- * @hide
- */
- public static final String RESPONSE_BUNDLE_KEY =
- "android.service.ambientcontext.EventResponseKey";
-
@Nullable
@Override
public final IBinder onBind(@NonNull Intent intent) {
@@ -82,19 +73,30 @@
@Override
public void startDetection(
@NonNull AmbientContextEventRequest request, String packageName,
- RemoteCallback callback) {
+ RemoteCallback detectionResultCallback, RemoteCallback statusCallback) {
Objects.requireNonNull(request);
- Objects.requireNonNull(callback);
- Consumer<AmbientContextEventResponse> consumer =
- response -> {
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(detectionResultCallback);
+ Objects.requireNonNull(statusCallback);
+ Consumer<AmbientContextDetectionResult> detectionResultConsumer =
+ result -> {
Bundle bundle = new Bundle();
bundle.putParcelable(
- AmbientContextDetectionService.RESPONSE_BUNDLE_KEY,
- response);
- callback.sendResult(bundle);
+ AmbientContextDetectionResult.RESULT_RESPONSE_BUNDLE_KEY,
+ result);
+ detectionResultCallback.sendResult(bundle);
+ };
+ Consumer<AmbientContextDetectionServiceStatus> statusConsumer =
+ status -> {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(
+ AmbientContextDetectionServiceStatus
+ .STATUS_RESPONSE_BUNDLE_KEY,
+ status);
+ statusCallback.sendResult(bundle);
};
AmbientContextDetectionService.this.onStartDetection(
- request, packageName, consumer);
+ request, packageName, detectionResultConsumer, statusConsumer);
Slog.d(TAG, "startDetection " + request);
}
@@ -104,29 +106,52 @@
Objects.requireNonNull(packageName);
AmbientContextDetectionService.this.onStopDetection(packageName);
}
+
+ /** {@inheritDoc} */
+ @Override
+ public void queryServiceStatus(
+ @AmbientContextEvent.EventCode int[] eventTypes,
+ String packageName,
+ RemoteCallback callback) {
+ Objects.requireNonNull(eventTypes);
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(callback);
+ Consumer<AmbientContextDetectionServiceStatus> consumer =
+ response -> {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(
+ AmbientContextDetectionServiceStatus
+ .STATUS_RESPONSE_BUNDLE_KEY,
+ response);
+ callback.sendResult(bundle);
+ };
+ AmbientContextDetectionService.this.onQueryServiceStatus(
+ eventTypes, packageName, consumer);
+ }
};
}
return null;
}
/**
- * Starts detection and provides detected events to the consumer. The ongoing detection will
- * keep running, until onStopDetection is called. If there were previously requested
+ * Starts detection and provides detected events to the statusConsumer. The ongoing detection
+ * will keep running, until onStopDetection is called. If there were previously requested
* detection from the same package, the previous request will be replaced with the new request.
* The implementation should keep track of whether the user consented each requested
- * AmbientContextEvent for the app. If not consented, the response should set status
- * STATUS_ACCESS_DENIED and include an action PendingIntent for the app to redirect the user
- * to the consent screen.
+ * AmbientContextEvent for the app. If not consented, the statusConsumer should get a response
+ * with STATUS_ACCESS_DENIED.
*
- * @param request The request with events to detect, optional detection window and other
- * options.
+ * @param request The request with events to detect.
* @param packageName the requesting app's package name
- * @param consumer the consumer for the detected event
+ * @param detectionResultConsumer the consumer for the detected event
+ * @param statusConsumer the consumer for the service status.
*/
+ @BinderThread
public abstract void onStartDetection(
@NonNull AmbientContextEventRequest request,
@NonNull String packageName,
- @NonNull Consumer<AmbientContextEventResponse> consumer);
+ @NonNull Consumer<AmbientContextDetectionResult> detectionResultConsumer,
+ @NonNull Consumer<AmbientContextDetectionServiceStatus> statusConsumer);
/**
* Stops detection of the events. Events that are not being detected will be ignored.
@@ -134,4 +159,19 @@
* @param packageName stops detection for the given package.
*/
public abstract void onStopDetection(@NonNull String packageName);
+
+ /**
+ * Called when a query for the detection status occurs. The implementation should check
+ * the detection status of the requested events for the package, and provide results in a
+ * {@link AmbientContextDetectionServiceStatus} for the consumer.
+ *
+ * @param eventTypes The events to check for status.
+ * @param packageName the requesting app's package name
+ * @param consumer the consumer for the query results
+ */
+ @BinderThread
+ public abstract void onQueryServiceStatus(
+ @NonNull int[] eventTypes,
+ @NonNull String packageName,
+ @NonNull Consumer<AmbientContextDetectionServiceStatus> consumer);
}
diff --git a/core/java/android/app/ambientcontext/AmbientContextEventResponse.aidl b/core/java/android/service/ambientcontext/AmbientContextDetectionServiceStatus.aidl
similarity index 79%
copy from core/java/android/app/ambientcontext/AmbientContextEventResponse.aidl
copy to core/java/android/service/ambientcontext/AmbientContextDetectionServiceStatus.aidl
index 4dc6466..979cf7b 100644
--- a/core/java/android/app/ambientcontext/AmbientContextEventResponse.aidl
+++ b/core/java/android/service/ambientcontext/AmbientContextDetectionServiceStatus.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 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,6 @@
* limitations under the License.
*/
-package android.app.ambientcontext;
+package android.service.ambientcontext;
-parcelable AmbientContextEventResponse;
\ No newline at end of file
+parcelable AmbientContextDetectionServiceStatus;
\ No newline at end of file
diff --git a/core/java/android/service/ambientcontext/AmbientContextDetectionServiceStatus.java b/core/java/android/service/ambientcontext/AmbientContextDetectionServiceStatus.java
new file mode 100644
index 0000000..3e92f39
--- /dev/null
+++ b/core/java/android/service/ambientcontext/AmbientContextDetectionServiceStatus.java
@@ -0,0 +1,171 @@
+/*
+ * 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.service.ambientcontext;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.app.ambientcontext.AmbientContextManager;
+import android.app.ambientcontext.AmbientContextManager.StatusCode;
+import android.os.Parcelable;
+
+import com.android.internal.util.AnnotationValidations;
+
+/**
+ * Represents a status for the {@code AmbientContextDetectionService}.
+ *
+ * @hide
+ */
+@SystemApi
+public final class AmbientContextDetectionServiceStatus implements Parcelable {
+ /**
+ * The bundle key for this class of object, used in {@code RemoteCallback#sendResult}.
+ *
+ * @hide
+ */
+ public static final String STATUS_RESPONSE_BUNDLE_KEY =
+ "android.app.ambientcontext.AmbientContextServiceStatusBundleKey";
+
+ @StatusCode private final int mStatusCode;
+ @NonNull private final String mPackageName;
+
+ AmbientContextDetectionServiceStatus(
+ @StatusCode int statusCode,
+ @NonNull String packageName) {
+ this.mStatusCode = statusCode;
+ AnnotationValidations.validate(StatusCode.class, null, mStatusCode);
+ this.mPackageName = packageName;
+ }
+
+ /**
+ * The status of the service.
+ */
+ public @StatusCode int getStatusCode() {
+ return mStatusCode;
+ }
+
+ /**
+ * The package to deliver the response to.
+ */
+ public @NonNull String getPackageName() {
+ return mPackageName;
+ }
+
+ @Override
+ public String toString() {
+ return "AmbientContextDetectionServiceStatus { " + "statusCode = " + mStatusCode + ", "
+ + "packageName = " + mPackageName + " }";
+ }
+
+ @Override
+ public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+ byte flg = 0;
+ dest.writeByte(flg);
+ dest.writeInt(mStatusCode);
+ dest.writeString(mPackageName);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ AmbientContextDetectionServiceStatus(@NonNull android.os.Parcel in) {
+ byte flg = in.readByte();
+ int statusCode = in.readInt();
+ String packageName = in.readString();
+
+ this.mStatusCode = statusCode;
+ AnnotationValidations.validate(
+ StatusCode.class, null, mStatusCode);
+ this.mPackageName = packageName;
+ AnnotationValidations.validate(
+ NonNull.class, null, mPackageName);
+ }
+
+ public static final @NonNull Creator<AmbientContextDetectionServiceStatus> CREATOR =
+ new Creator<AmbientContextDetectionServiceStatus>() {
+ @Override
+ public AmbientContextDetectionServiceStatus[] newArray(int size) {
+ return new AmbientContextDetectionServiceStatus[size];
+ }
+
+ @Override
+ public AmbientContextDetectionServiceStatus createFromParcel(
+ @NonNull android.os.Parcel in) {
+ return new AmbientContextDetectionServiceStatus(in);
+ }
+ };
+
+ /**
+ * A builder for {@link AmbientContextDetectionServiceStatus}
+ */
+ @SuppressWarnings("WeakerAccess")
+ public static final class Builder {
+ private @StatusCode int mStatusCode;
+ private @NonNull String mPackageName;
+ private long mBuilderFieldsSet = 0L;
+
+ public Builder() {
+ }
+
+ /**
+ * Sets the status of the service.
+ */
+ public @NonNull Builder setStatusCode(@StatusCode int value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x1;
+ mStatusCode = value;
+ return this;
+ }
+
+ /**
+ * The package to deliver the response to.
+ */
+ public @NonNull Builder setPackageName(@NonNull String value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x2;
+ mPackageName = value;
+ return this;
+ }
+
+ /** Builds the instance. This builder should not be touched after calling this! */
+ public @NonNull AmbientContextDetectionServiceStatus build() {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x4; // Mark builder used
+
+ if ((mBuilderFieldsSet & 0x1) == 0) {
+ mStatusCode = AmbientContextManager.STATUS_UNKNOWN;
+ }
+ if ((mBuilderFieldsSet & 0x2) == 0) {
+ mPackageName = "";
+ }
+ AmbientContextDetectionServiceStatus o = new AmbientContextDetectionServiceStatus(
+ mStatusCode,
+ mPackageName);
+ return o;
+ }
+
+ private void checkNotUsed() {
+ if ((mBuilderFieldsSet & 0x4) != 0) {
+ throw new IllegalStateException(
+ "This Builder should not be reused. Use a new Builder instance instead");
+ }
+ }
+ }
+}
diff --git a/core/java/android/service/ambientcontext/IAmbientContextDetectionService.aidl b/core/java/android/service/ambientcontext/IAmbientContextDetectionService.aidl
index 1c6e25e..50c89c0 100644
--- a/core/java/android/service/ambientcontext/IAmbientContextDetectionService.aidl
+++ b/core/java/android/service/ambientcontext/IAmbientContextDetectionService.aidl
@@ -26,6 +26,8 @@
*/
oneway interface IAmbientContextDetectionService {
void startDetection(in AmbientContextEventRequest request, in String packageName,
- in RemoteCallback callback);
+ in RemoteCallback detectionResultCallback, in RemoteCallback statusCallback);
void stopDetection(in String packageName);
+ void queryServiceStatus(in int[] eventTypes, in String packageName,
+ in RemoteCallback callback);
}
\ No newline at end of file
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index bb1f393..3459172 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -31,6 +31,11 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
@@ -39,9 +44,11 @@
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.util.AttributeSet;
import android.util.Log;
import android.util.MathUtils;
import android.util.Slog;
+import android.util.Xml;
import android.view.ActionMode;
import android.view.Display;
import android.view.KeyEvent;
@@ -57,9 +64,14 @@
import android.view.WindowManager.LayoutParams;
import android.view.accessibility.AccessibilityEvent;
+import com.android.internal.R;
import com.android.internal.util.DumpUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
import java.io.FileDescriptor;
+import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.function.Consumer;
@@ -159,8 +171,9 @@
* </pre>
*/
public class DreamService extends Service implements Window.Callback {
- private final String mTag =
- DreamService.class.getSimpleName() + "[" + getClass().getSimpleName() + "]";
+ private static final String TAG = DreamService.class.getSimpleName();
+ private final String mTag = TAG + "[" + getClass().getSimpleName() + "]";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
/**
* The name of the dream manager service.
@@ -191,6 +204,11 @@
public static final String DREAM_META_DATA = "android.service.dream";
/**
+ * Name of the root tag under which a Dream defines its metadata in an XML file.
+ */
+ private static final String DREAM_META_DATA_ROOT_TAG = "dream";
+
+ /**
* Extra containing a boolean for whether to show complications on the overlay.
* @hide
*/
@@ -239,13 +257,16 @@
mRequests = new ArrayDeque<>();
}
- public void bind(Context context, @Nullable ComponentName overlayService) {
+ public void bind(Context context, @Nullable ComponentName overlayService,
+ ComponentName dreamService) {
if (overlayService == null) {
return;
}
final Intent overlayIntent = new Intent();
overlayIntent.setComponent(overlayService);
+ overlayIntent.putExtra(EXTRA_SHOW_COMPLICATIONS,
+ fetchShouldShowComplications(context, dreamService));
context.bindService(overlayIntent,
this, Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE);
@@ -967,7 +988,8 @@
// Connect to the overlay service if present.
if (!mWindowless) {
- mOverlayConnection.bind(this, intent.getParcelableExtra(EXTRA_DREAM_OVERLAY_COMPONENT));
+ mOverlayConnection.bind(this, intent.getParcelableExtra(EXTRA_DREAM_OVERLAY_COMPONENT),
+ new ComponentName(this, getClass()));
}
return mDreamServiceWrapper;
@@ -1081,6 +1103,86 @@
// end public api
/**
+ * Parses and returns metadata of the dream service indicated by the service info. Returns null
+ * if metadata cannot be found.
+ *
+ * Note that {@link ServiceInfo} must be fetched with {@link PackageManager#GET_META_DATA} flag.
+ *
+ * @hide
+ */
+ @Nullable
+ public static DreamMetadata getDreamMetadata(Context context, ServiceInfo serviceInfo) {
+ final PackageManager pm = context.getPackageManager();
+
+ final TypedArray rawMetadata = readMetadata(pm, serviceInfo);
+ if (rawMetadata == null) return null;
+
+ final DreamMetadata metadata = new DreamMetadata(
+ convertToComponentName(rawMetadata.getString(
+ com.android.internal.R.styleable.Dream_settingsActivity), serviceInfo),
+ rawMetadata.getDrawable(
+ com.android.internal.R.styleable.Dream_previewImage),
+ rawMetadata.getBoolean(R.styleable.Dream_showClockAndComplications,
+ DEFAULT_SHOW_COMPLICATIONS));
+ rawMetadata.recycle();
+ return metadata;
+ }
+
+ /**
+ * Returns the raw XML metadata fetched from the {@link ServiceInfo}.
+ *
+ * Returns <code>null</code> if the {@link ServiceInfo} doesn't contain valid dream metadata.
+ */
+ @Nullable
+ private static TypedArray readMetadata(PackageManager pm, ServiceInfo serviceInfo) {
+ if (serviceInfo == null || serviceInfo.metaData == null) {
+ return null;
+ }
+
+ try (XmlResourceParser parser =
+ serviceInfo.loadXmlMetaData(pm, DreamService.DREAM_META_DATA)) {
+ if (parser == null) {
+ if (DEBUG) Log.w(TAG, "No " + DreamService.DREAM_META_DATA + " metadata");
+ return null;
+ }
+
+ final AttributeSet attrs = Xml.asAttributeSet(parser);
+ while (true) {
+ final int type = parser.next();
+ if (type == XmlPullParser.END_DOCUMENT || type == XmlPullParser.START_TAG) {
+ break;
+ }
+ }
+
+ if (!parser.getName().equals(DREAM_META_DATA_ROOT_TAG)) {
+ if (DEBUG) {
+ Log.w(TAG, "Metadata does not start with " + DREAM_META_DATA_ROOT_TAG + " tag");
+ }
+ return null;
+ }
+
+ return pm.getResourcesForApplication(serviceInfo.applicationInfo).obtainAttributes(
+ attrs, com.android.internal.R.styleable.Dream);
+ } catch (PackageManager.NameNotFoundException | IOException | XmlPullParserException e) {
+ if (DEBUG) Log.e(TAG, "Error parsing: " + serviceInfo.packageName, e);
+ return null;
+ }
+ }
+
+ private static ComponentName convertToComponentName(String flattenedString,
+ ServiceInfo serviceInfo) {
+ if (flattenedString == null) {
+ return null;
+ }
+
+ if (!flattenedString.contains("/")) {
+ return new ComponentName(serviceInfo.packageName, flattenedString);
+ }
+
+ return ComponentName.unflattenFromString(flattenedString);
+ }
+
+ /**
* Called by DreamController.stopDream() when the Dream is about to be unbound and destroyed.
*
* Must run on mHandler.
@@ -1242,6 +1344,30 @@
return (oldFlags&~mask) | (flags&mask);
}
+ /**
+ * Fetches metadata of the dream indicated by the {@link ComponentName}, and returns whether
+ * the dream should show complications on the overlay. If not defined, returns
+ * {@link DreamService#DEFAULT_SHOW_COMPLICATIONS}.
+ */
+ private static boolean fetchShouldShowComplications(Context context,
+ ComponentName componentName) {
+ final PackageManager pm = context.getPackageManager();
+
+ try {
+ final ServiceInfo si = pm.getServiceInfo(componentName,
+ PackageManager.ComponentInfoFlags.of(PackageManager.GET_META_DATA));
+ final DreamMetadata metadata = getDreamMetadata(context, si);
+
+ if (metadata != null) {
+ return metadata.showComplications;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ if (DEBUG) Log.w(TAG, "cannot find component " + componentName.flattenToShortString());
+ }
+
+ return DEFAULT_SHOW_COMPLICATIONS;
+ }
+
@Override
protected void dump(final FileDescriptor fd, PrintWriter pw, final String[] args) {
DumpUtils.dumpAsync(mHandler, (pw1, prefix) -> dumpOnHandler(fd, pw1, args), pw, "", 1000);
@@ -1302,4 +1428,27 @@
onWindowCreated(a.getWindow());
}
}
+
+ /**
+ * Represents metadata defined in {@link android.R.styleable#Dream <dream>}.
+ *
+ * @hide
+ */
+ public static final class DreamMetadata {
+ @Nullable
+ public final ComponentName settingsActivity;
+
+ @Nullable
+ public final Drawable previewImage;
+
+ @NonNull
+ public final boolean showComplications;
+
+ DreamMetadata(ComponentName settingsActivity, Drawable previewImage,
+ boolean showComplications) {
+ this.settingsActivity = settingsActivity;
+ this.previewImage = previewImage;
+ this.showComplications = showComplications;
+ }
+ }
}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index ae39d3d..b9e60a1 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -256,6 +256,8 @@
public static final int REASON_CHANNEL_REMOVED = 20;
/** Notification was canceled due to the app's storage being cleared */
public static final int REASON_CLEAR_DATA = 21;
+ /** Notification was canceled due to an assistant adjustment update. */
+ public static final int REASON_ASSISTANT_CANCEL = 22;
/**
* @hide
@@ -279,7 +281,10 @@
REASON_UNAUTOBUNDLED,
REASON_CHANNEL_BANNED,
REASON_SNOOZED,
- REASON_TIMEOUT
+ REASON_TIMEOUT,
+ REASON_CHANNEL_REMOVED,
+ REASON_CLEAR_DATA,
+ REASON_ASSISTANT_CANCEL,
})
public @interface NotificationCancelReason{};
diff --git a/core/java/android/service/voice/AbstractHotwordDetector.java b/core/java/android/service/voice/AbstractHotwordDetector.java
index 1922607..01d5638 100644
--- a/core/java/android/service/voice/AbstractHotwordDetector.java
+++ b/core/java/android/service/voice/AbstractHotwordDetector.java
@@ -18,6 +18,7 @@
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityThread;
@@ -34,6 +35,9 @@
import com.android.internal.app.IHotwordRecognitionStatusCallback;
import com.android.internal.app.IVoiceInteractionManagerService;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Consumer;
+
/** Base implementation of {@link HotwordDetector}. */
abstract class AbstractHotwordDetector implements HotwordDetector {
private static final String TAG = AbstractHotwordDetector.class.getSimpleName();
@@ -45,6 +49,8 @@
private final Handler mHandler;
private final HotwordDetector.Callback mCallback;
private final int mDetectorType;
+ private Consumer<AbstractHotwordDetector> mOnDestroyListener;
+ private final AtomicBoolean mIsDetectorActive;
AbstractHotwordDetector(
IVoiceInteractionManagerService managerService,
@@ -55,6 +61,7 @@
mHandler = new Handler(Looper.getMainLooper());
mCallback = callback;
mDetectorType = detectorType;
+ mIsDetectorActive = new AtomicBoolean(true);
}
/**
@@ -70,6 +77,7 @@
if (DEBUG) {
Slog.i(TAG, "#recognizeHotword");
}
+ throwIfDetectorIsNoLongerActive();
// TODO: consider closing existing session.
@@ -106,6 +114,7 @@
if (DEBUG) {
Slog.d(TAG, "updateState()");
}
+ throwIfDetectorIsNoLongerActive();
synchronized (mLock) {
updateStateLocked(options, sharedMemory, null /* callback */, mDetectorType);
}
@@ -126,6 +135,35 @@
}
}
+ void registerOnDestroyListener(Consumer<AbstractHotwordDetector> onDestroyListener) {
+ synchronized (mLock) {
+ if (mOnDestroyListener != null) {
+ throw new IllegalStateException("only one destroy listener can be registered");
+ }
+ mOnDestroyListener = onDestroyListener;
+ }
+ }
+
+ @CallSuper
+ @Override
+ public void destroy() {
+ if (!mIsDetectorActive.get()) {
+ return;
+ }
+ mIsDetectorActive.set(false);
+ synchronized (mLock) {
+ mOnDestroyListener.accept(this);
+ }
+ }
+
+ protected void throwIfDetectorIsNoLongerActive() {
+ if (!mIsDetectorActive.get()) {
+ Slog.e(TAG, "attempting to use a destroyed detector which is no longer active");
+ throw new IllegalStateException(
+ "attempting to use a destroyed detector which is no longer active");
+ }
+ }
+
private static class BinderCallback
extends IMicrophoneHotwordDetectionVoiceInteractionCallback.Stub {
private final Handler mHandler;
@@ -146,7 +184,10 @@
mHandler.sendMessage(obtainMessage(
HotwordDetector.Callback::onDetected,
mCallback,
- new AlwaysOnHotwordDetector.EventPayload(audioFormat, hotwordDetectedResult)));
+ new AlwaysOnHotwordDetector.EventPayload.Builder()
+ .setCaptureAudioFormat(audioFormat)
+ .setHotwordDetectedResult(hotwordDetectedResult)
+ .build()));
}
}
}
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index c9daf52..bec5d1b 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -23,6 +23,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.app.ActivityThread;
@@ -59,6 +60,9 @@
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
import java.util.Locale;
/**
@@ -336,7 +340,39 @@
* Additional payload for {@link Callback#onDetected}.
*/
public static class EventPayload {
- private final boolean mTriggerAvailable;
+
+ /**
+ * Flags for describing the data format provided in the event payload.
+ *
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"DATA_FORMAT_"}, value = {
+ DATA_FORMAT_RAW,
+ DATA_FORMAT_TRIGGER_AUDIO,
+ })
+ public @interface DataFormat {
+ }
+
+ /**
+ * Data format is not strictly defined by the framework, and the
+ * {@link android.hardware.soundtrigger.SoundTriggerModule} voice engine may populate this
+ * field in any format.
+ */
+ public static final int DATA_FORMAT_RAW = 0;
+
+ /**
+ * Data format is defined as trigger audio.
+ *
+ * <p>When this format is used, {@link #getCaptureAudioFormat()} can be used to understand
+ * further the audio format for reading the data.
+ *
+ * @see AlwaysOnHotwordDetector#RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO
+ */
+ public static final int DATA_FORMAT_TRIGGER_AUDIO = 1;
+
+ @DataFormat
+ private final int mDataFormat;
// Indicates if {@code captureSession} can be used to continue capturing more audio
// from the DSP hardware.
private final boolean mCaptureAvailable;
@@ -348,40 +384,24 @@
private final byte[] mData;
private final HotwordDetectedResult mHotwordDetectedResult;
private final ParcelFileDescriptor mAudioStream;
+ private final List<KeyphraseRecognitionExtra> mKephraseExtras;
- EventPayload(boolean triggerAvailable, boolean captureAvailable,
- AudioFormat audioFormat, int captureSession, byte[] data) {
- this(triggerAvailable, captureAvailable, audioFormat, captureSession, data, null,
- null);
- }
-
- EventPayload(boolean triggerAvailable, boolean captureAvailable,
- AudioFormat audioFormat, int captureSession, byte[] data,
- HotwordDetectedResult hotwordDetectedResult) {
- this(triggerAvailable, captureAvailable, audioFormat, captureSession, data,
- hotwordDetectedResult, null);
- }
-
- EventPayload(AudioFormat audioFormat, HotwordDetectedResult hotwordDetectedResult) {
- this(false, false, audioFormat, -1, null, hotwordDetectedResult, null);
- }
-
- EventPayload(AudioFormat audioFormat,
- HotwordDetectedResult hotwordDetectedResult,
- ParcelFileDescriptor audioStream) {
- this(false, false, audioFormat, -1, null, hotwordDetectedResult, audioStream);
- }
-
- private EventPayload(boolean triggerAvailable, boolean captureAvailable,
- AudioFormat audioFormat, int captureSession, byte[] data,
- HotwordDetectedResult hotwordDetectedResult, ParcelFileDescriptor audioStream) {
- mTriggerAvailable = triggerAvailable;
+ private EventPayload(boolean captureAvailable,
+ @Nullable AudioFormat audioFormat,
+ int captureSession,
+ @DataFormat int dataFormat,
+ @Nullable byte[] data,
+ @Nullable HotwordDetectedResult hotwordDetectedResult,
+ @Nullable ParcelFileDescriptor audioStream,
+ @NonNull List<KeyphraseRecognitionExtra> keyphraseExtras) {
mCaptureAvailable = captureAvailable;
mCaptureSession = captureSession;
mAudioFormat = audioFormat;
+ mDataFormat = dataFormat;
mData = data;
mHotwordDetectedResult = hotwordDetectedResult;
mAudioStream = audioStream;
+ mKephraseExtras = keyphraseExtras;
}
/**
@@ -400,10 +420,12 @@
* {@link #getCaptureAudioFormat()}.
*
* @see AlwaysOnHotwordDetector#RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO
+ * @deprecated Use {@link #getData()} instead.
*/
+ @Deprecated
@Nullable
public byte[] getTriggerAudio() {
- if (mTriggerAvailable) {
+ if (mDataFormat == DATA_FORMAT_TRIGGER_AUDIO) {
return mData;
} else {
return null;
@@ -411,6 +433,36 @@
}
/**
+ * Conveys the format of the additional data that is triggered with the keyphrase event.
+ *
+ * @see AlwaysOnHotwordDetector#RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO
+ * @see DataFormat
+ */
+ @DataFormat
+ public int getDataFormat() {
+ return mDataFormat;
+ }
+
+ /**
+ * Gets additional raw data that is triggered with the keyphrase event.
+ *
+ * <p>A {@link android.hardware.soundtrigger.SoundTriggerModule} may populate this
+ * field with opaque data for use by system applications who know about voice
+ * engine internals. Data may be null if the field is not populated by the
+ * {@link android.hardware.soundtrigger.SoundTriggerModule}.
+ *
+ * <p>If {@link #getDataFormat()} is {@link #DATA_FORMAT_TRIGGER_AUDIO}, then the
+ * entirety of this buffer is expected to be of the format from
+ * {@link #getCaptureAudioFormat()}.
+ *
+ * @see AlwaysOnHotwordDetector#RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO
+ */
+ @Nullable
+ public byte[] getData() {
+ return mData;
+ }
+
+ /**
* Gets the session ID to start a capture from the DSP.
* This may be null if streaming capture isn't possible.
* If non-null, the format of the audio that can be captured can be
@@ -464,6 +516,166 @@
public ParcelFileDescriptor getAudioStream() {
return mAudioStream;
}
+
+ /**
+ * Returns the keyphrases recognized by the voice engine with additional confidence
+ * information
+ *
+ * @return List of keyphrase extras describing additional data for each keyphrase the voice
+ * engine triggered on for this event. The ordering of the list is preserved based on what
+ * the ordering provided by {@link android.hardware.soundtrigger.SoundTriggerModule}.
+ */
+ @NonNull
+ public List<KeyphraseRecognitionExtra> getKeyphraseRecognitionExtras() {
+ return mKephraseExtras;
+ }
+
+ /**
+ * Builder class for {@link EventPayload} objects
+ *
+ * @hide
+ */
+ @TestApi
+ public static final class Builder {
+ private boolean mCaptureAvailable = false;
+ private int mCaptureSession = -1;
+ private AudioFormat mAudioFormat = null;
+ @DataFormat
+ private int mDataFormat = DATA_FORMAT_RAW;
+ private byte[] mData = null;
+ private HotwordDetectedResult mHotwordDetectedResult = null;
+ private ParcelFileDescriptor mAudioStream = null;
+ private List<KeyphraseRecognitionExtra> mKeyphraseExtras = Collections.emptyList();
+
+ public Builder() {}
+
+ Builder(SoundTrigger.KeyphraseRecognitionEvent keyphraseRecognitionEvent) {
+ setCaptureAvailable(keyphraseRecognitionEvent.isCaptureAvailable());
+ setCaptureSession(keyphraseRecognitionEvent.getCaptureSession());
+ if (keyphraseRecognitionEvent.getCaptureFormat() != null) {
+ setCaptureAudioFormat(keyphraseRecognitionEvent.getCaptureFormat());
+ }
+ setDataFormat((keyphraseRecognitionEvent.triggerInData) ? DATA_FORMAT_TRIGGER_AUDIO
+ : DATA_FORMAT_RAW);
+ if (keyphraseRecognitionEvent.getData() != null) {
+ setData(keyphraseRecognitionEvent.getData());
+ }
+ if (keyphraseRecognitionEvent.keyphraseExtras != null) {
+ setKeyphraseRecognitionExtras(
+ Arrays.asList(keyphraseRecognitionEvent.keyphraseExtras));
+ }
+ }
+
+ /**
+ * Indicates if {@code captureSession} can be used to continue capturing more audio from
+ * the DSP hardware.
+ */
+ @SuppressLint("MissingGetterMatchingBuilder")
+ @NonNull
+ public Builder setCaptureAvailable(boolean captureAvailable) {
+ mCaptureAvailable = captureAvailable;
+ return this;
+ }
+
+ /**
+ * Sets the session ID to start a capture from the DSP.
+ */
+ @SuppressLint("MissingGetterMatchingBuilder")
+ @NonNull
+ public Builder setCaptureSession(int captureSession) {
+ mCaptureSession = captureSession;
+ return this;
+ }
+
+ /**
+ * Sets the format of the audio obtained using {@link #getTriggerAudio()}.
+ */
+ @NonNull
+ public Builder setCaptureAudioFormat(@NonNull AudioFormat audioFormat) {
+ mAudioFormat = audioFormat;
+ return this;
+ }
+
+ /**
+ * Conveys the format of the additional data that is triggered with the keyphrase event.
+ *
+ * @see AlwaysOnHotwordDetector#RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO
+ * @see DataFormat
+ */
+ @NonNull
+ public Builder setDataFormat(@DataFormat int dataFormat) {
+ mDataFormat = dataFormat;
+ return this;
+ }
+
+ /**
+ * Sets additional raw data that is triggered with the keyphrase event.
+ *
+ * <p>A {@link android.hardware.soundtrigger.SoundTriggerModule} may populate this
+ * field with opaque data for use by system applications who know about voice
+ * engine internals. Data may be null if the field is not populated by the
+ * {@link android.hardware.soundtrigger.SoundTriggerModule}.
+ *
+ * <p>If {@link #getDataFormat()} is {@link #DATA_FORMAT_TRIGGER_AUDIO}, then the
+ * entirety of this
+ * buffer is expected to be of the format from {@link #getCaptureAudioFormat()}.
+ *
+ * @see AlwaysOnHotwordDetector#RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO
+ */
+ @NonNull
+ public Builder setData(@NonNull byte[] data) {
+ mData = data;
+ return this;
+ }
+
+ /**
+ * Sets {@link HotwordDetectedResult} associated with the hotword event, passed from
+ * {@link HotwordDetectionService}.
+ */
+ @NonNull
+ public Builder setHotwordDetectedResult(
+ @NonNull HotwordDetectedResult hotwordDetectedResult) {
+ mHotwordDetectedResult = hotwordDetectedResult;
+ return this;
+ }
+
+ /**
+ * Sets a stream with bytes corresponding to the open audio stream with hotword data.
+ *
+ * <p>This data represents an audio stream in the format returned by
+ * {@link #getCaptureAudioFormat}.
+ *
+ * <p>Clients are expected to start consuming the stream within 1 second of receiving
+ * the
+ * event.
+ */
+ @NonNull
+ public Builder setAudioStream(@NonNull ParcelFileDescriptor audioStream) {
+ mAudioStream = audioStream;
+ return this;
+ }
+
+ /**
+ * Sets the keyphrases recognized by the voice engine with additional confidence
+ * information
+ */
+ @NonNull
+ public Builder setKeyphraseRecognitionExtras(
+ @NonNull List<KeyphraseRecognitionExtra> keyphraseRecognitionExtras) {
+ mKeyphraseExtras = keyphraseRecognitionExtras;
+ return this;
+ }
+
+ /**
+ * Builds an {@link EventPayload} instance
+ */
+ @NonNull
+ public EventPayload build() {
+ return new EventPayload(mCaptureAvailable, mAudioFormat, mCaptureSession,
+ mDataFormat, mData, mHotwordDetectedResult, mAudioStream,
+ mKeyphraseExtras);
+ }
+ }
}
/**
@@ -993,11 +1205,14 @@
/**
* Invalidates this hotword detector so that any future calls to this result
* in an IllegalStateException.
- *
- * @hide
*/
- void invalidate() {
+ @Override
+ public void destroy() {
synchronized (mLock) {
+ if (mAvailability == STATE_KEYPHRASE_ENROLLED) {
+ stopRecognition();
+ }
+
mAvailability = STATE_INVALID;
notifyStateChangedLocked();
@@ -1009,6 +1224,7 @@
}
}
}
+ super.destroy();
}
/**
@@ -1171,8 +1387,9 @@
Slog.i(TAG, "onDetected");
}
Message.obtain(mHandler, MSG_HOTWORD_DETECTED,
- new EventPayload(event.triggerInData, event.captureAvailable,
- event.captureFormat, event.captureSession, event.data, result))
+ new EventPayload.Builder(event)
+ .setHotwordDetectedResult(result)
+ .build())
.sendToTarget();
}
@Override
diff --git a/core/java/android/service/voice/HotwordDetectionService.java b/core/java/android/service/voice/HotwordDetectionService.java
index e3bb589..dfe0f54 100644
--- a/core/java/android/service/voice/HotwordDetectionService.java
+++ b/core/java/android/service/voice/HotwordDetectionService.java
@@ -140,9 +140,7 @@
Log.d(TAG, "#detectFromDspSource");
}
HotwordDetectionService.this.onDetect(
- new AlwaysOnHotwordDetector.EventPayload(
- event.triggerInData, event.captureAvailable,
- event.captureFormat, event.captureSession, event.data),
+ new AlwaysOnHotwordDetector.EventPayload.Builder(event).build(),
timeoutMillis,
new Callback(callback));
}
diff --git a/core/java/android/service/voice/HotwordDetector.java b/core/java/android/service/voice/HotwordDetector.java
index 969ec22..96fd8bb 100644
--- a/core/java/android/service/voice/HotwordDetector.java
+++ b/core/java/android/service/voice/HotwordDetector.java
@@ -119,6 +119,17 @@
void updateState(@Nullable PersistableBundle options, @Nullable SharedMemory sharedMemory);
/**
+ * Invalidates this hotword detector so that any future calls to this result
+ * in an {@link IllegalStateException}.
+ *
+ * <p>If there are no other {@link HotwordDetector} instances linked to the
+ * {@link HotwordDetectionService}, the service will be shutdown.
+ */
+ default void destroy() {
+ throw new UnsupportedOperationException("Not implemented. Must override in a subclass.");
+ }
+
+ /**
* @hide
*/
static String detectorTypeToString(int detectorType) {
diff --git a/core/java/android/service/voice/SoftwareHotwordDetector.java b/core/java/android/service/voice/SoftwareHotwordDetector.java
index 512a654..2d662ea 100644
--- a/core/java/android/service/voice/SoftwareHotwordDetector.java
+++ b/core/java/android/service/voice/SoftwareHotwordDetector.java
@@ -77,7 +77,7 @@
if (DEBUG) {
Slog.i(TAG, "#startRecognition");
}
-
+ throwIfDetectorIsNoLongerActive();
maybeCloseExistingSession();
try {
@@ -100,6 +100,7 @@
if (DEBUG) {
Slog.i(TAG, "#stopRecognition");
}
+ throwIfDetectorIsNoLongerActive();
try {
mManagerService.stopListeningFromMic();
@@ -110,6 +111,19 @@
return true;
}
+ @Override
+ public void destroy() {
+ stopRecognition();
+ maybeCloseExistingSession();
+
+ try {
+ mManagerService.shutdownHotwordDetectionService();
+ } catch (RemoteException ex) {
+ ex.rethrowFromSystemServer();
+ }
+ super.destroy();
+ }
+
private void maybeCloseExistingSession() {
// TODO: needs to be synchronized.
// TODO: implement this
@@ -135,8 +149,11 @@
mHandler.sendMessage(obtainMessage(
HotwordDetector.Callback::onDetected,
mCallback,
- new AlwaysOnHotwordDetector.EventPayload(
- audioFormat, hotwordDetectedResult, audioStream)));
+ new AlwaysOnHotwordDetector.EventPayload.Builder()
+ .setCaptureAudioFormat(audioFormat)
+ .setAudioStream(audioStream)
+ .setHotwordDetectedResult(hotwordDetectedResult)
+ .build()));
}
}
diff --git a/core/java/android/service/voice/VoiceInteractionManagerInternal.java b/core/java/android/service/voice/VoiceInteractionManagerInternal.java
index c806409..b20dccc 100644
--- a/core/java/android/service/voice/VoiceInteractionManagerInternal.java
+++ b/core/java/android/service/voice/VoiceInteractionManagerInternal.java
@@ -50,6 +50,13 @@
public abstract boolean hasActiveSession(String packageName);
/**
+ * Returns the package name of the active session.
+ *
+ * @param callingVoiceInteractor the voice interactor binder from the calling VoiceInteractor.
+ */
+ public abstract String getVoiceInteractorPackageName(IBinder callingVoiceInteractor);
+
+ /**
* Gets the identity of the currently active HotwordDetectionService.
*
* @see HotwordDetectionServiceIdentity
@@ -82,4 +89,4 @@
return mOwnerUid;
}
}
-}
\ No newline at end of file
+}
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index f52c9ff..bf0cfbe 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -271,7 +271,7 @@
// It's still guaranteed to have been stopped.
// This helps with cases where the voice interaction implementation is changed
// by the user.
- safelyShutdownHotwordDetector();
+ safelyShutdownAllHotwordDetectors();
}
/**
@@ -380,11 +380,13 @@
}
synchronized (mLock) {
// Allow only one concurrent recognition via the APIs.
- safelyShutdownHotwordDetector();
+ safelyShutdownAllHotwordDetectors();
mHotwordDetector = new AlwaysOnHotwordDetector(keyphrase, locale, callback,
mKeyphraseEnrollmentInfo, mSystemService,
getApplicationContext().getApplicationInfo().targetSdkVersion,
supportHotwordDetectionService, options, sharedMemory);
+ mHotwordDetector.registerOnDestroyListener((detector) -> onDspHotwordDetectorDestroyed(
+ (AlwaysOnHotwordDetector) detector));
}
return mHotwordDetector;
}
@@ -433,10 +435,13 @@
}
synchronized (mLock) {
// Allow only one concurrent recognition via the APIs.
- safelyShutdownHotwordDetector();
+ safelyShutdownAllHotwordDetectors();
mSoftwareHotwordDetector =
new SoftwareHotwordDetector(
mSystemService, null, options, sharedMemory, callback);
+ mSoftwareHotwordDetector.registerOnDestroyListener(
+ (detector) -> onMicrophoneHotwordDetectorDestroyed(
+ (SoftwareHotwordDetector) detector));
}
return mSoftwareHotwordDetector;
}
@@ -482,51 +487,36 @@
return mKeyphraseEnrollmentInfo.getKeyphraseMetadata(keyphrase, locale) != null;
}
- private void safelyShutdownHotwordDetector() {
+ private void safelyShutdownAllHotwordDetectors() {
synchronized (mLock) {
- shutdownDspHotwordDetectorLocked();
- shutdownMicrophoneHotwordDetectorLocked();
+ if (mHotwordDetector != null) {
+ try {
+ mHotwordDetector.destroy();
+ } catch (Exception ex) {
+ Log.i(TAG, "exception destroying AlwaysOnHotwordDetector", ex);
+ }
+ }
+
+ if (mSoftwareHotwordDetector != null) {
+ try {
+ mSoftwareHotwordDetector.destroy();
+ } catch (Exception ex) {
+ Log.i(TAG, "exception destroying SoftwareHotwordDetector", ex);
+ }
+ }
}
}
- private void shutdownDspHotwordDetectorLocked() {
- if (mHotwordDetector == null) {
- return;
+ private void onDspHotwordDetectorDestroyed(@NonNull AlwaysOnHotwordDetector detector) {
+ synchronized (mLock) {
+ mHotwordDetector = null;
}
-
- try {
- mHotwordDetector.stopRecognition();
- } catch (Exception ex) {
- // Ignore.
- }
-
- try {
- mHotwordDetector.invalidate();
- } catch (Exception ex) {
- // Ignore.
- }
-
- mHotwordDetector = null;
}
- private void shutdownMicrophoneHotwordDetectorLocked() {
- if (mSoftwareHotwordDetector == null) {
- return;
+ private void onMicrophoneHotwordDetectorDestroyed(@NonNull SoftwareHotwordDetector detector) {
+ synchronized (mLock) {
+ mSoftwareHotwordDetector = null;
}
-
- try {
- mSoftwareHotwordDetector.stopRecognition();
- } catch (Exception ex) {
- // Ignore.
- }
-
- try {
- mSystemService.shutdownHotwordDetectionService();
- } catch (Exception ex) {
- // Ignore.
- }
-
- mSoftwareHotwordDetector = null;
}
/**
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index c91851a..a2938a8 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -26,6 +26,8 @@
import static android.view.View.SYSTEM_UI_FLAG_VISIBLE;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.FloatRange;
import android.annotation.NonNull;
@@ -890,8 +892,6 @@
* @param dimAmount Float amount between [0.0, 1.0] to dim the wallpaper.
*/
private void updateWallpaperDimming(float dimAmount) {
- mPreviousWallpaperDimAmount = mWallpaperDimAmount;
-
// Custom dim amount cannot be less than the default dim amount.
mWallpaperDimAmount = Math.max(mDefaultDimAmount, dimAmount);
// If dim amount is 0f (additional dimming is removed), then the wallpaper should dim
@@ -909,15 +909,15 @@
SurfaceControl.Transaction surfaceControlTransaction = new SurfaceControl.Transaction();
// TODO: apply the dimming to preview as well once surface transparency works in
// preview mode.
- if (!isPreview() && mShouldDim) {
+ if ((!isPreview() && mShouldDim)
+ || mPreviousWallpaperDimAmount != mWallpaperDimAmount) {
Log.v(TAG, "Setting wallpaper dimming: " + mWallpaperDimAmount);
// Animate dimming to gradually change the wallpaper alpha from the previous
// dim amount to the new amount only if the dim amount changed.
ValueAnimator animator = ValueAnimator.ofFloat(
mPreviousWallpaperDimAmount, mWallpaperDimAmount);
- animator.setDuration(mPreviousWallpaperDimAmount == mWallpaperDimAmount
- ? 0 : DIMMING_ANIMATION_DURATION_MS);
+ animator.setDuration(DIMMING_ANIMATION_DURATION_MS);
animator.addUpdateListener((ValueAnimator va) -> {
final float dimValue = (float) va.getAnimatedValue();
if (mBbqSurfaceControl != null) {
@@ -925,11 +925,19 @@
.setAlpha(mBbqSurfaceControl, 1 - dimValue).apply();
}
});
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ updateSurface(false, false, true);
+ }
+ });
animator.start();
} else {
Log.v(TAG, "Setting wallpaper dimming: " + 0);
surfaceControlTransaction.setAlpha(mBbqSurfaceControl, 1.0f).apply();
}
+
+ mPreviousWallpaperDimAmount = mWallpaperDimAmount;
}
/**
@@ -1332,6 +1340,7 @@
resetWindowPages();
mSession.finishDrawing(mWindow, null /* postDrawTransaction */);
processLocalColors(mPendingXOffset, mPendingXOffsetStep);
+ notifyColorsChanged();
}
reposition();
reportEngineShown(shouldWaitForEngineShown());
diff --git a/core/java/android/speech/RecognitionSupport.java b/core/java/android/speech/RecognitionSupport.java
index 3a86d0b..43c8e1b 100644
--- a/core/java/android/speech/RecognitionSupport.java
+++ b/core/java/android/speech/RecognitionSupport.java
@@ -36,13 +36,16 @@
/** Support for this request is ready for use on this device for the returned languages. */
@NonNull
+ @DataClass.PluralOf("installedLanguage")
private List<String> mInstalledLanguages = null;
/** Support for this request is scheduled for download for the returned languages. */
+ @DataClass.PluralOf("pendingLanguage")
@NonNull private List<String> mPendingLanguages = null;
/** These languages are supported but need to be downloaded before use. */
@NonNull
+ @DataClass.PluralOf("supportedLanguage")
private List<String> mSupportedLanguages = null;
@@ -231,10 +234,7 @@
/** @see #setInstalledLanguages */
@DataClass.Generated.Member
- public @NonNull Builder addInstalledLanguages(@NonNull String value) {
- // You can refine this method's name by providing item's singular name, e.g.:
- // @DataClass.PluralOf("item")) mItems = ...
-
+ public @NonNull Builder addInstalledLanguage(@NonNull String value) {
if (mInstalledLanguages == null) setInstalledLanguages(new java.util.ArrayList<>());
mInstalledLanguages.add(value);
return this;
@@ -253,10 +253,7 @@
/** @see #setPendingLanguages */
@DataClass.Generated.Member
- public @NonNull Builder addPendingLanguages(@NonNull String value) {
- // You can refine this method's name by providing item's singular name, e.g.:
- // @DataClass.PluralOf("item")) mItems = ...
-
+ public @NonNull Builder addPendingLanguage(@NonNull String value) {
if (mPendingLanguages == null) setPendingLanguages(new java.util.ArrayList<>());
mPendingLanguages.add(value);
return this;
@@ -275,10 +272,7 @@
/** @see #setSupportedLanguages */
@DataClass.Generated.Member
- public @NonNull Builder addSupportedLanguages(@NonNull String value) {
- // You can refine this method's name by providing item's singular name, e.g.:
- // @DataClass.PluralOf("item")) mItems = ...
-
+ public @NonNull Builder addSupportedLanguage(@NonNull String value) {
if (mSupportedLanguages == null) setSupportedLanguages(new java.util.ArrayList<>());
mSupportedLanguages.add(value);
return this;
@@ -314,10 +308,10 @@
}
@DataClass.Generated(
- time = 1639158640137L,
+ time = 1644582623366L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/speech/RecognitionSupport.java",
- inputSignatures = "private @android.annotation.NonNull java.util.List<java.lang.String> mInstalledLanguages\nprivate @android.annotation.NonNull java.util.List<java.lang.String> mPendingLanguages\nprivate @android.annotation.NonNull java.util.List<java.lang.String> mSupportedLanguages\nclass RecognitionSupport extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
+ inputSignatures = "private @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"installedLanguage\") java.util.List<java.lang.String> mInstalledLanguages\nprivate @com.android.internal.util.DataClass.PluralOf(\"pendingLanguage\") @android.annotation.NonNull java.util.List<java.lang.String> mPendingLanguages\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"supportedLanguage\") java.util.List<java.lang.String> mSupportedLanguages\nclass RecognitionSupport extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java
index 502558e..e075c05 100644
--- a/core/java/android/speech/SpeechRecognizer.java
+++ b/core/java/android/speech/SpeechRecognizer.java
@@ -496,6 +496,17 @@
Objects.requireNonNull(recognizerIntent, "intent must not be null");
Objects.requireNonNull(supportListener, "listener must not be null");
+ if (DBG) {
+ Slog.i(TAG, "#checkRecognitionSupport called");
+ if (mService == null) {
+ Slog.i(TAG, "Connection is not established yet");
+ }
+ }
+
+ if (mService == null) {
+ // First time connection: first establish a connection, then dispatch.
+ connectToSystemService();
+ }
putMessage(Message.obtain(mHandler, MSG_CHECK_RECOGNITION_SUPPORT,
Pair.create(recognizerIntent, supportListener)));
}
@@ -510,7 +521,17 @@
*/
public void triggerModelDownload(@NonNull Intent recognizerIntent) {
Objects.requireNonNull(recognizerIntent, "intent must not be null");
- putMessage(Message.obtain(mHandler, MSG_TRIGGER_MODEL_DOWNLOAD));
+ if (DBG) {
+ Slog.i(TAG, "#triggerModelDownload called");
+ if (mService == null) {
+ Slog.i(TAG, "Connection is not established yet");
+ }
+ }
+ if (mService == null) {
+ // First time connection: first establish a connection, then dispatch.
+ connectToSystemService();
+ }
+ putMessage(Message.obtain(mHandler, MSG_TRIGGER_MODEL_DOWNLOAD, recognizerIntent));
}
/**
@@ -625,7 +646,6 @@
}
try {
mService.triggerModelDownload(recognizerIntent);
- if (DBG) Log.d(TAG, "service download support command succeeded");
} catch (final RemoteException e) {
Log.e(TAG, "downloadModel() failed", e);
mListener.onError(ERROR_CLIENT);
@@ -705,6 +725,9 @@
}
private synchronized boolean maybeInitializeManagerService() {
+ if (DBG) {
+ Log.i(TAG, "#maybeInitializeManagerService found = " + mManagerService);
+ }
if (mManagerService != null) {
return true;
}
@@ -712,8 +735,13 @@
mManagerService = IRecognitionServiceManager.Stub.asInterface(
ServiceManager.getService(Context.SPEECH_RECOGNITION_SERVICE));
- if (mManagerService == null && mListener != null) {
- mListener.onError(ERROR_CLIENT);
+ if (DBG) {
+ Log.i(TAG, "#maybeInitializeManagerService instantiated =" + mManagerService);
+ }
+ if (mManagerService == null) {
+ if (mListener != null) {
+ mListener.onError(ERROR_CLIENT);
+ }
return false;
}
return true;
diff --git a/core/java/android/text/BidiFormatter.java b/core/java/android/text/BidiFormatter.java
index 422d347..dfa172d 100644
--- a/core/java/android/text/BidiFormatter.java
+++ b/core/java/android/text/BidiFormatter.java
@@ -31,7 +31,7 @@
* directionality of the text can be either estimated or passed in when known.
*
* <p>To support versions lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2},
- * you can use the support library's {@link android.support.v4.text.BidiFormatter} class.
+ * you can use the support library's {@link androidx.core.text.BidiFormatter} class.
*
* <p>These APIs provides the following functionality:
* <p>
diff --git a/core/java/android/text/TextDirectionHeuristics.java b/core/java/android/text/TextDirectionHeuristics.java
index 354c15f..85260f4 100644
--- a/core/java/android/text/TextDirectionHeuristics.java
+++ b/core/java/android/text/TextDirectionHeuristics.java
@@ -28,7 +28,7 @@
* provided in the {@link android.view.View} class for {@link android.view.View#setTextDirection
* setTextDirection()}, such as {@link android.view.View#TEXT_DIRECTION_RTL}.
* <p>To support versions lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2},
- * you can use the support library's {@link android.support.v4.text.TextDirectionHeuristicsCompat}
+ * you can use the support library's {@link androidx.core.text.TextDirectionHeuristicsCompat}
* class.
*
*/
diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java
index 4a48832..ad044af 100644
--- a/core/java/android/text/style/SuggestionSpan.java
+++ b/core/java/android/text/style/SuggestionSpan.java
@@ -217,6 +217,7 @@
com.android.internal.R.styleable.SuggestionSpan_textUnderlineThickness, 0);
mMisspelledUnderlineColor = typedArray.getColor(
com.android.internal.R.styleable.SuggestionSpan_textUnderlineColor, Color.BLACK);
+ typedArray.recycle();
defStyleAttr = com.android.internal.R.attr.textAppearanceGrammarErrorSuggestion;
typedArray = context.obtainStyledAttributes(
@@ -225,6 +226,7 @@
com.android.internal.R.styleable.SuggestionSpan_textUnderlineThickness, 0);
mGrammarErrorUnderlineColor = typedArray.getColor(
com.android.internal.R.styleable.SuggestionSpan_textUnderlineColor, Color.BLACK);
+ typedArray.recycle();
defStyleAttr = com.android.internal.R.attr.textAppearanceEasyCorrectSuggestion;
typedArray = context.obtainStyledAttributes(
@@ -233,6 +235,7 @@
com.android.internal.R.styleable.SuggestionSpan_textUnderlineThickness, 0);
mEasyCorrectUnderlineColor = typedArray.getColor(
com.android.internal.R.styleable.SuggestionSpan_textUnderlineColor, Color.BLACK);
+ typedArray.recycle();
defStyleAttr = com.android.internal.R.attr.textAppearanceAutoCorrectionSuggestion;
typedArray = context.obtainStyledAttributes(
@@ -241,6 +244,7 @@
com.android.internal.R.styleable.SuggestionSpan_textUnderlineThickness, 0);
mAutoCorrectionUnderlineColor = typedArray.getColor(
com.android.internal.R.styleable.SuggestionSpan_textUnderlineColor, Color.BLACK);
+ typedArray.recycle();
}
public SuggestionSpan(Parcel src) {
diff --git a/core/java/android/tracing/OWNERS b/core/java/android/tracing/OWNERS
index f5de4eb..7d1b48b 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/DumpableContainer.java b/core/java/android/util/DumpableContainer.java
index 04d19dc..e7b2acd 100644
--- a/core/java/android/util/DumpableContainer.java
+++ b/core/java/android/util/DumpableContainer.java
@@ -37,4 +37,15 @@
* @return {@code true} if the dumpable was added, {@code false} if the call was ignored.
*/
boolean addDumpable(@NonNull Dumpable dumpable);
+
+ /**
+ * Removes the given {@link Dumpable dumpable} from the container.
+ *
+ * @param dumpable dumpable to be removed.
+ *
+ * @return {@code true} if the dumpable was removed, {@code false} if it was not previously
+ * {@link #addDumpable(Dumpable) added} with the same identify (object reference) and
+ * {@link Dumpable#getDumpableName() name}.
+ */
+ boolean removeDumpable(@NonNull Dumpable dumpable);
}
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 96a1fc6..048b94f 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -60,6 +60,13 @@
public static final String SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS =
"settings_enable_monitor_phantom_procs";
+ /**
+ * Support dark theme activation at Bedtime.
+ * @hide
+ */
+ public static final String SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME =
+ "settings_app_allow_dark_theme_activation_at_bedtime";
+
private static final Map<String, String> DEFAULT_FLAGS;
static {
@@ -82,8 +89,9 @@
DEFAULT_FLAGS.put(SETTINGS_ENABLE_SECURITY_HUB, "true");
DEFAULT_FLAGS.put(SETTINGS_SUPPORT_LARGE_SCREEN, "true");
DEFAULT_FLAGS.put("settings_search_always_expand", "false");
- DEFAULT_FLAGS.put(SETTINGS_APP_LANGUAGE_SELECTION, "false");
+ DEFAULT_FLAGS.put(SETTINGS_APP_LANGUAGE_SELECTION, "true");
DEFAULT_FLAGS.put(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS, "true");
+ DEFAULT_FLAGS.put(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME, "false");
}
private static final Set<String> PERSISTENT_FLAGS;
@@ -92,6 +100,7 @@
PERSISTENT_FLAGS.add(SETTINGS_APP_LANGUAGE_SELECTION);
PERSISTENT_FLAGS.add(SETTINGS_SUPPORT_LARGE_SCREEN);
PERSISTENT_FLAGS.add(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS);
+ PERSISTENT_FLAGS.add(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME);
}
/**
diff --git a/core/java/android/util/OWNERS b/core/java/android/util/OWNERS
index c199b96..28c078e 100644
--- a/core/java/android/util/OWNERS
+++ b/core/java/android/util/OWNERS
@@ -1,3 +1,4 @@
+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
diff --git a/core/java/android/util/RotationUtils.java b/core/java/android/util/RotationUtils.java
index 0ac2c9c..cebdbf6 100644
--- a/core/java/android/util/RotationUtils.java
+++ b/core/java/android/util/RotationUtils.java
@@ -24,8 +24,10 @@
import android.annotation.Dimension;
import android.graphics.Insets;
import android.graphics.Matrix;
+import android.graphics.Point;
import android.graphics.Rect;
import android.view.Surface.Rotation;
+import android.view.SurfaceControl;
/**
* A class containing utility methods related to rotation.
@@ -121,13 +123,64 @@
/** @return the rotation needed to rotate from oldRotation to newRotation. */
@Rotation
- public static int deltaRotation(int oldRotation, int newRotation) {
+ public static int deltaRotation(@Rotation int oldRotation, @Rotation int newRotation) {
int delta = newRotation - oldRotation;
if (delta < 0) delta += 4;
return delta;
}
/**
+ * Rotates a surface CCW around the origin (eg. a 90-degree rotation will result in the
+ * bottom-left being at the origin). Use {@link #rotatePoint} to transform the top-left
+ * corner appropriately.
+ */
+ public static void rotateSurface(SurfaceControl.Transaction t, SurfaceControl sc,
+ @Rotation int rotation) {
+ // Note: the matrix values look inverted, but they aren't because our coordinate-space
+ // is actually left-handed.
+ // Note: setMatrix expects values in column-major order.
+ switch (rotation) {
+ case ROTATION_0:
+ t.setMatrix(sc, 1.f, 0.f, 0.f, 1.f);
+ break;
+ case ROTATION_90:
+ t.setMatrix(sc, 0.f, -1.f, 1.f, 0.f);
+ break;
+ case ROTATION_180:
+ t.setMatrix(sc, -1.f, 0.f, 0.f, -1.f);
+ break;
+ case ROTATION_270:
+ t.setMatrix(sc, 0.f, 1.f, -1.f, 0.f);
+ break;
+ }
+ }
+
+ /**
+ * Rotates a point CCW within a rectangle of size parentW x parentH with top/left at the
+ * origin as if the point is stuck to the rectangle. The rectangle is transformed such that
+ * it's top/left remains at the origin after the rotation.
+ */
+ public static void rotatePoint(Point inOutPoint, @Rotation int rotation,
+ int parentW, int parentH) {
+ int origX = inOutPoint.x;
+ switch (rotation) {
+ case ROTATION_0:
+ return;
+ case ROTATION_90:
+ inOutPoint.x = inOutPoint.y;
+ inOutPoint.y = parentW - origX;
+ return;
+ case ROTATION_180:
+ inOutPoint.x = parentW - inOutPoint.x;
+ inOutPoint.y = parentH - inOutPoint.y;
+ return;
+ case ROTATION_270:
+ inOutPoint.x = parentH - inOutPoint.y;
+ inOutPoint.y = origX;
+ }
+ }
+
+ /**
* Sets a matrix such that given a rotation, it transforms physical display
* coordinates to that rotation's logical coordinates.
*
diff --git a/core/java/android/util/Slog.java b/core/java/android/util/Slog.java
index 117d75e..3aeecca 100644
--- a/core/java/android/util/Slog.java
+++ b/core/java/android/util/Slog.java
@@ -16,6 +16,9 @@
package android.util;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
@@ -24,118 +27,265 @@
*
* <p>Should be used by system components. Use {@code adb logcat --buffer=system} to fetch the logs.
*
+ * @see Log
* @hide
*/
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public final class Slog {
private Slog() {
}
+ /**
+ * Logs {@code msg} at {@link Log#VERBOSE} level.
+ *
+ * @param tag identifies the source of a log message. It usually represents system service,
+ * e.g. {@code PackageManager}.
+ * @param msg the message to log.
+ *
+ * @see Log#v(String, String)
+ */
@UnsupportedAppUsage
- public static int v(String tag, String msg) {
+ public static int v(@Nullable String tag, @NonNull String msg) {
return Log.println_native(Log.LOG_ID_SYSTEM, Log.VERBOSE, tag, msg);
}
- public static int v(String tag, String msg, Throwable tr) {
+ /**
+ * Logs {@code msg} at {@link Log#VERBOSE} level, attaching stack trace of the {@code tr} to
+ * the end of the log statement.
+ *
+ * @param tag identifies the source of a log message. It usually represents system service,
+ * e.g. {@code PackageManager}.
+ * @param msg the message to log.
+ * @param tr an exception to log.
+ *
+ * @see Log#v(String, String, Throwable)
+ */
+ public static int v(@Nullable String tag, @NonNull String msg, @Nullable Throwable tr) {
return Log.println_native(Log.LOG_ID_SYSTEM, Log.VERBOSE, tag,
msg + '\n' + Log.getStackTraceString(tr));
}
+ /**
+ * Logs {@code msg} at {@link Log#DEBUG} level.
+ *
+ * @param tag identifies the source of a log message. It usually represents system service,
+ * e.g. {@code PackageManager}.
+ * @param msg the message to log.
+ *
+ * @see Log#d(String, String)
+ */
@UnsupportedAppUsage
- public static int d(String tag, String msg) {
+ public static int d(@Nullable String tag, @NonNull String msg) {
return Log.println_native(Log.LOG_ID_SYSTEM, Log.DEBUG, tag, msg);
}
+ /**
+ * Logs {@code msg} at {@link Log#DEBUG} level, attaching stack trace of the {@code tr} to
+ * the end of the log statement.
+ *
+ * @param tag identifies the source of a log message. It usually represents system service,
+ * e.g. {@code PackageManager}.
+ * @param msg the message to log.
+ * @param tr an exception to log.
+ *
+ * @see Log#d(String, String, Throwable)
+ */
@UnsupportedAppUsage
- public static int d(String tag, String msg, Throwable tr) {
+ public static int d(@Nullable String tag, @NonNull String msg, @Nullable Throwable tr) {
return Log.println_native(Log.LOG_ID_SYSTEM, Log.DEBUG, tag,
msg + '\n' + Log.getStackTraceString(tr));
}
+ /**
+ * Logs {@code msg} at {@link Log#INFO} level.
+ *
+ * @param tag identifies the source of a log message. It usually represents system service,
+ * e.g. {@code PackageManager}.
+ * @param msg the message to log.
+ *
+ * @see Log#i(String, String)
+ */
@UnsupportedAppUsage
- public static int i(String tag, String msg) {
+ public static int i(@Nullable String tag, @NonNull String msg) {
return Log.println_native(Log.LOG_ID_SYSTEM, Log.INFO, tag, msg);
}
- public static int i(String tag, String msg, Throwable tr) {
+ /**
+ * Logs {@code msg} at {@link Log#INFO} level, attaching stack trace of the {@code tr} to
+ * the end of the log statement.
+ *
+ * @param tag identifies the source of a log message. It usually represents system service,
+ * e.g. {@code PackageManager}.
+ * @param msg the message to log.
+ * @param tr an exception to log.
+ *
+ * @see Log#i(String, String, Throwable)
+ */
+ public static int i(@Nullable String tag, @NonNull String msg, @Nullable Throwable tr) {
return Log.println_native(Log.LOG_ID_SYSTEM, Log.INFO, tag,
msg + '\n' + Log.getStackTraceString(tr));
}
+ /**
+ * Logs {@code msg} at {@link Log#WARN} level.
+ *
+ * @param tag identifies the source of a log message. It usually represents system service,
+ * e.g. {@code PackageManager}.
+ * @param msg the message to log.
+ *
+ * @see Log#w(String, String)
+ */
@UnsupportedAppUsage
- public static int w(String tag, String msg) {
+ public static int w(@Nullable String tag, @NonNull String msg) {
return Log.println_native(Log.LOG_ID_SYSTEM, Log.WARN, tag, msg);
}
+ /**
+ * Logs {@code msg} at {@link Log#WARN} level, attaching stack trace of the {@code tr} to
+ * the end of the log statement.
+ *
+ * @param tag identifies the source of a log message. It usually represents system service,
+ * e.g. {@code PackageManager}.
+ * @param msg the message to log.
+ * @param tr an exception to log.
+ *
+ * @see Log#w(String, String, Throwable)
+ */
@UnsupportedAppUsage
- public static int w(String tag, String msg, Throwable tr) {
+ public static int w(@Nullable String tag, @NonNull String msg, @Nullable Throwable tr) {
return Log.println_native(Log.LOG_ID_SYSTEM, Log.WARN, tag,
msg + '\n' + Log.getStackTraceString(tr));
}
- public static int w(String tag, Throwable tr) {
+ /**
+ * Logs stack trace of {@code tr} at {@link Log#WARN} level.
+ *
+ * @param tag identifies the source of a log message. It usually represents system service,
+ * e.g. {@code PackageManager}.
+ * @param tr an exception to log.
+ *
+ * @see Log#w(String, Throwable)
+ */
+ public static int w(@Nullable String tag, @Nullable Throwable tr) {
return Log.println_native(Log.LOG_ID_SYSTEM, Log.WARN, tag, Log.getStackTraceString(tr));
}
+ /**
+ * Logs {@code msg} at {@link Log#ERROR} level.
+ *
+ * @param tag identifies the source of a log message. It usually represents system service,
+ * e.g. {@code PackageManager}.
+ * @param msg the message to log.
+ *
+ * @see Log#e(String, String)
+ */
@UnsupportedAppUsage
- public static int e(String tag, String msg) {
+ public static int e(@Nullable String tag, @NonNull String msg) {
return Log.println_native(Log.LOG_ID_SYSTEM, Log.ERROR, tag, msg);
}
+ /**
+ * Logs {@code msg} at {@link Log#ERROR} level, attaching stack trace of the {@code tr} to
+ * the end of the log statement.
+ *
+ * @param tag identifies the source of a log message. It usually represents system service,
+ * e.g. {@code PackageManager}.
+ * @param msg the message to log.
+ * @param tr an exception to log.
+ *
+ * @see Log#e(String, String, Throwable)
+ */
@UnsupportedAppUsage
- public static int e(String tag, String msg, Throwable tr) {
+ public static int e(@Nullable String tag, @NonNull String msg, @Nullable Throwable tr) {
return Log.println_native(Log.LOG_ID_SYSTEM, Log.ERROR, tag,
msg + '\n' + Log.getStackTraceString(tr));
}
/**
- * Like {@link Log#wtf(String, String)}, but will never cause the caller to crash, and
- * will always be handled asynchronously. Primarily for use by coding running within
- * the system process.
+ * Logs a condition that should never happen.
+ *
+ * <p>
+ * Similar to {@link Log#wtf(String, String)}, but will never cause the caller to crash, and
+ * will always be handled asynchronously. Primarily to be used by the system server.
+ *
+ * @param tag identifies the source of a log message. It usually represents system service,
+ * e.g. {@code PackageManager}.
+ * @param msg the message to log.
+ *
+ * @see Log#wtf(String, String)
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static int wtf(String tag, String msg) {
+ public static int wtf(@Nullable String tag, @NonNull String msg) {
return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, null, false, true);
}
/**
- * Like {@link #wtf(String, String)}, but does not output anything to the log.
+ * Similar to {@link #wtf(String, String)}, but does not output anything to the log.
*/
- public static void wtfQuiet(String tag, String msg) {
+ public static void wtfQuiet(@Nullable String tag, @NonNull String msg) {
Log.wtfQuiet(Log.LOG_ID_SYSTEM, tag, msg, true);
}
/**
- * Like {@link Log#wtfStack(String, String)}, but will never cause the caller to crash, and
- * will always be handled asynchronously. Primarily for use by coding running within
- * the system process.
+ * Logs a condition that should never happen, attaching the full call stack to the log.
+ *
+ * <p>
+ * Similar to {@link Log#wtfStack(String, String)}, but will never cause the caller to crash,
+ * and will always be handled asynchronously. Primarily to be used by the system server.
+ *
+ * @param tag identifies the source of a log message. It usually represents system service,
+ * e.g. {@code PackageManager}.
+ * @param msg the message to log.
+ *
+ * @see Log#wtfStack(String, String)
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- public static int wtfStack(String tag, String msg) {
+ public static int wtfStack(@Nullable String tag, @NonNull String msg) {
return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, null, true, true);
}
/**
- * Like {@link Log#wtf(String, Throwable)}, but will never cause the caller to crash,
- * and will always be handled asynchronously. Primarily for use by coding running within
- * the system process.
+ * Logs a condition that should never happen, attaching stack trace of the {@code tr} to the
+ * end of the log statement.
+ *
+ * <p>
+ * Similar to {@link Log#wtf(String, Throwable)}, but will never cause the caller to crash,
+ * and will always be handled asynchronously. Primarily to be used by the system server.
+ *
+ * @param tag identifies the source of a log message. It usually represents system service,
+ * e.g. {@code PackageManager}.
+ * @param tr an exception to log.
+ *
+ * @see Log#wtf(String, Throwable)
*/
- public static int wtf(String tag, Throwable tr) {
+ public static int wtf(@Nullable String tag, @Nullable Throwable tr) {
return Log.wtf(Log.LOG_ID_SYSTEM, tag, tr.getMessage(), tr, false, true);
}
/**
- * Like {@link Log#wtf(String, String, Throwable)}, but will never cause the caller to crash,
- * and will always be handled asynchronously. Primarily for use by coding running within
- * the system process.
+ * Logs a condition that should never happen, attaching stack trace of the {@code tr} to the
+ * end of the log statement.
+ *
+ * <p>
+ * Similar to {@link Log#wtf(String, String, Throwable)}, but will never cause the caller to
+ * crash, and will always be handled asynchronously. Primarily to be used by the system server.
+ *
+ * @param tag identifies the source of a log message. It usually represents system service,
+ * e.g. {@code PackageManager}.
+ * @param msg the message to log.
+ * @param tr an exception to log.
+ *
+ * @see Log#wtf(String, String, Throwable)
*/
@UnsupportedAppUsage
- public static int wtf(String tag, String msg, Throwable tr) {
+ public static int wtf(@Nullable String tag, @NonNull String msg, @Nullable Throwable tr) {
return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, tr, false, true);
}
+ /** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static int println(int priority, String tag, String msg) {
+ public static int println(@Log.Level int priority, @Nullable String tag, @NonNull String msg) {
return Log.println_native(Log.LOG_ID_SYSTEM, priority, tag, msg);
}
}
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index de56d3a..43c07c8 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -52,9 +52,10 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.SomeArgs;
+import java.util.ArrayDeque;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -348,6 +349,11 @@
View requestedView = null;
AccessibilityNodeInfo requestedNode = null;
+ boolean interruptPrefetch =
+ ((flags & AccessibilityNodeInfo.FLAG_PREFETCH_UNINTERRUPTIBLE) == 0);
+
+ ArrayList<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList;
+ infos.clear();
try {
if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null) {
return;
@@ -357,27 +363,46 @@
if (requestedView != null && isShown(requestedView)) {
requestedNode = populateAccessibilityNodeInfoForView(
requestedView, arguments, virtualDescendantId);
+ mPrefetcher.mInterruptPrefetch = interruptPrefetch;
+ mPrefetcher.mFetchFlags = flags & AccessibilityNodeInfo.FLAG_PREFETCH_MASK;
+
+ if (!interruptPrefetch) {
+ infos.add(requestedNode);
+ mPrefetcher.prefetchAccessibilityNodeInfos(requestedView,
+ requestedNode == null ? null : new AccessibilityNodeInfo(requestedNode),
+ infos);
+ mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
+ }
}
} finally {
- updateInfoForViewportAndReturnFindNodeResult(
- requestedNode == null ? null : AccessibilityNodeInfo.obtain(requestedNode),
- callback, interactionId, spec, interactiveRegion);
+ if (!interruptPrefetch) {
+ // Return found node and prefetched nodes in one IPC.
+ updateInfosForViewportAndReturnFindNodeResult(infos, callback, interactionId, spec,
+ interactiveRegion);
+
+ final SatisfiedFindAccessibilityNodeByAccessibilityIdRequest satisfiedRequest =
+ getSatisfiedRequestInPrefetch(requestedNode == null ? null : requestedNode,
+ infos, flags);
+ if (satisfiedRequest != null) {
+ returnFindNodeResult(satisfiedRequest);
+ }
+ return;
+ } else {
+ // Return found node.
+ updateInfoForViewportAndReturnFindNodeResult(
+ requestedNode == null ? null : new AccessibilityNodeInfo(requestedNode),
+ callback, interactionId, spec, interactiveRegion);
+ }
}
- ArrayList<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList;
- infos.clear();
mPrefetcher.prefetchAccessibilityNodeInfos(requestedView,
- requestedNode == null ? null : AccessibilityNodeInfo.obtain(requestedNode),
- virtualDescendantId, flags, infos);
+ requestedNode == null ? null : new AccessibilityNodeInfo(requestedNode), infos);
mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
updateInfosForViewPort(infos, spec, interactiveRegion);
final SatisfiedFindAccessibilityNodeByAccessibilityIdRequest satisfiedRequest =
- getSatisfiedRequestInPrefetch(
- requestedNode == null ? null : requestedNode, infos, flags);
+ getSatisfiedRequestInPrefetch(requestedNode == null ? null : requestedNode, infos,
+ flags);
- if (satisfiedRequest != null && satisfiedRequest.mSatisfiedRequestNode != requestedNode) {
- infos.remove(satisfiedRequest.mSatisfiedRequestNode);
- }
-
+ // Return prefetch result separately.
returnPrefetchResult(interactionId, infos, callback);
if (satisfiedRequest != null) {
@@ -1077,6 +1102,11 @@
}
}
mPendingFindNodeByIdMessages.clear();
+ // Remove node from prefetched infos.
+ if (satisfiedRequest != null && satisfiedRequest.mSatisfiedRequestNode
+ != requestedNode) {
+ infos.remove(satisfiedRequest.mSatisfiedRequestNode);
+ }
return satisfiedRequest;
}
}
@@ -1149,45 +1179,76 @@
*/
private class AccessibilityNodePrefetcher {
- private static final int MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE = 50;
-
private final ArrayList<View> mTempViewList = new ArrayList<View>();
+ private boolean mInterruptPrefetch;
+ private int mFetchFlags;
public void prefetchAccessibilityNodeInfos(View view, AccessibilityNodeInfo root,
- int virtualViewId, int fetchFlags, List<AccessibilityNodeInfo> outInfos) {
+ List<AccessibilityNodeInfo> outInfos) {
if (root == null) {
return;
}
AccessibilityNodeProvider provider = view.getAccessibilityNodeProvider();
+ final boolean prefetchPredecessors =
+ isFlagSet(AccessibilityNodeInfo.FLAG_PREFETCH_ANCESTORS);
if (provider == null) {
- if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) {
+ if (prefetchPredecessors) {
prefetchPredecessorsOfRealNode(view, outInfos);
}
- if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS) != 0) {
- prefetchSiblingsOfRealNode(view, outInfos);
+ if (isFlagSet(AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS)) {
+ prefetchSiblingsOfRealNode(view, outInfos, prefetchPredecessors);
}
- if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS) != 0) {
+ if (isFlagSet(AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS_HYBRID)) {
prefetchDescendantsOfRealNode(view, outInfos);
}
} else {
- if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) {
+ if (prefetchPredecessors) {
prefetchPredecessorsOfVirtualNode(root, view, provider, outInfos);
}
- if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS) != 0) {
- prefetchSiblingsOfVirtualNode(root, view, provider, outInfos);
+ if (isFlagSet(AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS)) {
+ prefetchSiblingsOfVirtualNode(root, view, provider, outInfos,
+ prefetchPredecessors);
}
- if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS) != 0) {
+ if (isFlagSet(AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS_HYBRID)) {
prefetchDescendantsOfVirtualNode(root, provider, outInfos);
}
}
+ if (isFlagSet(AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS_DEPTH_FIRST)
+ || isFlagSet(AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS_BREADTH_FIRST)) {
+ if (shouldStopPrefetching(outInfos)) {
+ return;
+ }
+ PrefetchDeque<DequeNode> deque = new PrefetchDeque<>(
+ mFetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS_MASK,
+ outInfos);
+ addChildrenOfRoot(view, root, provider, deque);
+ deque.performTraversalAndPrefetch();
+ }
if (ENFORCE_NODE_TREE_CONSISTENT) {
enforceNodeTreeConsistent(root, outInfos);
}
}
- private boolean shouldStopPrefetching(List prefetchededInfos) {
- return mHandler.hasUserInteractiveMessagesWaiting()
- || prefetchededInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE;
+ private void addChildrenOfRoot(View root, AccessibilityNodeInfo rootInfo,
+ AccessibilityNodeProvider rootProvider, PrefetchDeque deque) {
+ DequeNode rootDequeNode;
+ if (rootProvider == null) {
+ rootDequeNode = new ViewNode(root);
+ } else {
+ rootDequeNode = new VirtualNode(
+ AccessibilityNodeProvider.HOST_VIEW_ID, rootProvider);
+ }
+ rootDequeNode.addChildren(rootInfo, deque);
+ }
+
+ private boolean isFlagSet(@AccessibilityNodeInfo.PrefetchingStrategy int strategy) {
+ return (mFetchFlags & strategy) != 0;
+ }
+
+ public boolean shouldStopPrefetching(List prefetchedInfos) {
+ return ((mHandler.hasUserInteractiveMessagesWaiting() && mInterruptPrefetch)
+ || prefetchedInfos.size()
+ >= AccessibilityNodeInfo.MAX_NUMBER_OF_PREFETCHED_NODES);
}
private void enforceNodeTreeConsistent(
@@ -1283,7 +1344,7 @@
}
private void prefetchSiblingsOfRealNode(View current,
- List<AccessibilityNodeInfo> outInfos) {
+ List<AccessibilityNodeInfo> outInfos, boolean predecessorsPrefetched) {
if (shouldStopPrefetching(outInfos)) {
return;
}
@@ -1293,6 +1354,13 @@
ArrayList<View> children = mTempViewList;
children.clear();
try {
+ if (!predecessorsPrefetched) {
+ AccessibilityNodeInfo parentInfo =
+ ((ViewGroup) parent).createAccessibilityNodeInfo();
+ if (parentInfo != null) {
+ outInfos.add(parentInfo);
+ }
+ }
parentGroup.addChildrenForAccessibility(children);
final int childCount = children.size();
for (int i = 0; i < childCount; i++) {
@@ -1304,7 +1372,7 @@
&& isShown(child)) {
AccessibilityNodeInfo info = null;
AccessibilityNodeProvider provider =
- child.getAccessibilityNodeProvider();
+ child.getAccessibilityNodeProvider();
if (provider == null) {
info = child.createAccessibilityNodeInfo();
} else {
@@ -1327,8 +1395,8 @@
if (shouldStopPrefetching(outInfos) || !(root instanceof ViewGroup)) {
return;
}
- HashMap<View, AccessibilityNodeInfo> addedChildren =
- new HashMap<View, AccessibilityNodeInfo>();
+ LinkedHashMap<View, AccessibilityNodeInfo> addedChildren =
+ new LinkedHashMap<View, AccessibilityNodeInfo>();
ArrayList<View> children = mTempViewList;
children.clear();
try {
@@ -1414,17 +1482,21 @@
}
private void prefetchSiblingsOfVirtualNode(AccessibilityNodeInfo current, View providerHost,
- AccessibilityNodeProvider provider, List<AccessibilityNodeInfo> outInfos) {
+ AccessibilityNodeProvider provider, List<AccessibilityNodeInfo> outInfos,
+ boolean predecessorsPrefetched) {
final long parentNodeId = current.getParentNodeId();
final int parentAccessibilityViewId =
- AccessibilityNodeInfo.getAccessibilityViewId(parentNodeId);
+ AccessibilityNodeInfo.getAccessibilityViewId(parentNodeId);
final int parentVirtualDescendantId =
- AccessibilityNodeInfo.getVirtualDescendantId(parentNodeId);
+ AccessibilityNodeInfo.getVirtualDescendantId(parentNodeId);
if (parentVirtualDescendantId != AccessibilityNodeProvider.HOST_VIEW_ID
|| parentAccessibilityViewId == providerHost.getAccessibilityViewId()) {
final AccessibilityNodeInfo parent =
provider.createAccessibilityNodeInfo(parentVirtualDescendantId);
if (parent != null) {
+ if (!predecessorsPrefetched) {
+ outInfos.add(parent);
+ }
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
if (shouldStopPrefetching(outInfos)) {
@@ -1443,7 +1515,7 @@
}
}
} else {
- prefetchSiblingsOfRealNode(providerHost, outInfos);
+ prefetchSiblingsOfRealNode(providerHost, outInfos, predecessorsPrefetched);
}
}
@@ -1626,4 +1698,159 @@
mSatisfiedRequestInteractionId = satisfiedRequestInteractionId;
}
}
+
+ private class PrefetchDeque<E extends DequeNode>
+ extends ArrayDeque<E> {
+ int mStrategy;
+ List<AccessibilityNodeInfo> mPrefetchOutput;
+
+ PrefetchDeque(int strategy, List<AccessibilityNodeInfo> output) {
+ mStrategy = strategy;
+ mPrefetchOutput = output;
+ }
+
+ /** Performs depth-first or breadth-first traversal.
+ *
+ * For depth-first search, we iterate through the children in backwards order and push them
+ * to the stack before taking from the head. For breadth-first search, we iterate through
+ * the children in order and push them to the stack before taking from the tail.
+ *
+ * Depth-first search: 0 has children 0, 1, 2, 4. 1 has children 5 and 6.
+ * Head Tail
+ * 1 2 3 4 -> pop: 1 -> 5 6 2 3 4
+ *
+ * Breadth-first search
+ * Head Tail
+ * 4 3 2 1 -> remove last: 1 -> 6 5 3 2
+ *
+ **/
+ void performTraversalAndPrefetch() {
+ try {
+ while (!isEmpty()) {
+ E child = getNext();
+ AccessibilityNodeInfo childInfo = child.getA11yNodeInfo();
+ if (childInfo != null) {
+ mPrefetchOutput.add(childInfo);
+ }
+ if (mPrefetcher.shouldStopPrefetching(mPrefetchOutput)) {
+ return;
+ }
+ // Add children to deque.
+ child.addChildren(childInfo, this);
+ }
+ } finally {
+ clear();
+ }
+ }
+
+ E getNext() {
+ if (isStack()) {
+ return pop();
+ }
+ return removeLast();
+ }
+
+ boolean isStack() {
+ return (mStrategy & AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS_DEPTH_FIRST) != 0;
+ }
+ }
+
+ interface DequeNode {
+ AccessibilityNodeInfo getA11yNodeInfo();
+ void addChildren(AccessibilityNodeInfo virtualRoot, PrefetchDeque deque);
+ }
+
+ private class ViewNode implements DequeNode {
+ View mView;
+ private final ArrayList<View> mTempViewList = new ArrayList<>();
+
+ ViewNode(View view) {
+ mView = view;
+ }
+
+ @Override
+ public AccessibilityNodeInfo getA11yNodeInfo() {
+ if (mView == null) {
+ return null;
+ }
+ return mView.createAccessibilityNodeInfo();
+ }
+
+ @Override
+ public void addChildren(AccessibilityNodeInfo virtualRoot, PrefetchDeque deque) {
+ if (mView == null) {
+ return;
+ }
+ if (!(mView instanceof ViewGroup)) {
+ return;
+ }
+ ArrayList<View> children = mTempViewList;
+ children.clear();
+ try {
+ mView.addChildrenForAccessibility(children);
+ final int childCount = children.size();
+
+ if (deque.isStack()) {
+ for (int i = childCount - 1; i >= 0; i--) {
+ addChild(deque, children.get(i));
+ }
+ } else {
+ for (int i = 0; i < childCount; i++) {
+ addChild(deque, children.get(i));
+ }
+ }
+ } finally {
+ children.clear();
+ }
+ }
+
+ private void addChild(ArrayDeque deque, View child) {
+ if (isShown(child)) {
+ AccessibilityNodeProvider provider = child.getAccessibilityNodeProvider();
+ if (provider == null) {
+ deque.push(new ViewNode(child));
+ } else {
+ deque.push(new VirtualNode(AccessibilityNodeProvider.HOST_VIEW_ID,
+ provider));
+ }
+ }
+ }
+ }
+
+ private class VirtualNode implements DequeNode {
+ long mInfoId;
+ AccessibilityNodeProvider mProvider;
+
+ VirtualNode(long id, AccessibilityNodeProvider provider) {
+ mInfoId = id;
+ mProvider = provider;
+ }
+ @Override
+ public AccessibilityNodeInfo getA11yNodeInfo() {
+ if (mProvider == null) {
+ return null;
+ }
+ return mProvider.createAccessibilityNodeInfo(
+ AccessibilityNodeInfo.getVirtualDescendantId(mInfoId));
+ }
+
+ @Override
+ public void addChildren(AccessibilityNodeInfo virtualRoot, PrefetchDeque deque) {
+ if (virtualRoot == null) {
+ return;
+ }
+ final int childCount = virtualRoot.getChildCount();
+ if (deque.isStack()) {
+ for (int i = childCount - 1; i >= 0; i--) {
+ final long childNodeId = virtualRoot.getChildId(i);
+ deque.push(new VirtualNode(childNodeId, mProvider));
+ }
+ } else {
+ for (int i = 0; i < childCount; i++) {
+ final long childNodeId = virtualRoot.getChildId(i);
+ deque.push(new VirtualNode(childNodeId, mProvider));
+ }
+ }
+ }
+ }
}
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 246a8c9..7d8e998 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -42,6 +42,7 @@
import android.hardware.display.DeviceProductInfo;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerGlobal;
+import android.hardware.graphics.common.DisplayDecorationSupport;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -1856,6 +1857,19 @@
}
/**
+ * Returns whether/how the specified display supports DISPLAY_DECORATION.
+ *
+ * Composition.DISPLAY_DECORATION is a special layer type which is used to
+ * render the screen decorations (i.e. antialiased rounded corners and
+ * cutouts) while taking advantage of specific hardware.
+ *
+ * @hide
+ */
+ public DisplayDecorationSupport getDisplayDecorationSupport() {
+ return mGlobal.getDisplayDecorationSupport(mDisplayId);
+ }
+
+ /**
* A mode supported by a given display.
*
* @see Display#getSupportedModes()
diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java
index c87c13d..c1413be 100644
--- a/core/java/android/view/HandwritingInitiator.java
+++ b/core/java/android/view/HandwritingInitiator.java
@@ -24,6 +24,9 @@
import com.android.internal.annotations.VisibleForTesting;
import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
/**
* Initiates handwriting mode once it detects stylus movement in handwritable areas.
@@ -58,6 +61,7 @@
private final long mTapTimeoutInMillis;
private State mState = new State();
+ private final HandwritingAreaTracker mHandwritingAreasTracker = new HandwritingAreaTracker();
/**
* Helper method to reset the internal state of this class.
@@ -83,8 +87,8 @@
private final InputMethodManager mImm;
@VisibleForTesting
- public HandwritingInitiator(ViewConfiguration viewConfiguration,
- InputMethodManager inputMethodManager) {
+ public HandwritingInitiator(@NonNull ViewConfiguration viewConfiguration,
+ @NonNull InputMethodManager inputMethodManager) {
mTouchSlop = viewConfiguration.getScaledTouchSlop();
mTapTimeoutInMillis = ViewConfiguration.getTapTimeout();
mImm = inputMethodManager;
@@ -98,7 +102,7 @@
* @param motionEvent the stylus MotionEvent.
*/
@VisibleForTesting
- public void onTouchEvent(MotionEvent motionEvent) {
+ public void onTouchEvent(@NonNull MotionEvent motionEvent) {
final int maskedAction = motionEvent.getActionMasked();
switch (maskedAction) {
case MotionEvent.ACTION_DOWN:
@@ -151,11 +155,20 @@
final float y = motionEvent.getY(pointerIndex);
if (largerThanTouchSlop(x, y, mState.mStylusDownX, mState.mStylusDownY)) {
mState.mExceedTouchSlop = true;
- tryStartHandwriting();
+ View candidateView =
+ findBestCandidateView(mState.mStylusDownX, mState.mStylusDownY);
+ if (candidateView != null) {
+ if (candidateView == getConnectedView()) {
+ startHandwriting(candidateView);
+ } else {
+ candidateView.requestFocus();
+ }
+ }
}
}
}
+ @Nullable
private View getConnectedView() {
if (mConnectedView == null) return null;
return mConnectedView.get();
@@ -178,13 +191,16 @@
clearConnectedView();
return;
}
+
final View connectedView = getConnectedView();
if (connectedView == view) {
++mConnectionCount;
} else {
mConnectedView = new WeakReference<>(view);
mConnectionCount = 1;
- tryStartHandwriting();
+ if (mState.mShouldInitHandwriting) {
+ tryStartHandwriting();
+ }
}
}
@@ -233,17 +249,10 @@
return;
}
- final ViewParent viewParent = connectedView.getParent();
- // Do a final check before startHandwriting.
- if (viewParent != null && connectedView.isAttachedToWindow()) {
- final Rect editorBounds =
- new Rect(0, 0, connectedView.getWidth(), connectedView.getHeight());
- if (viewParent.getChildVisibleRect(connectedView, editorBounds, null)) {
- final int roundedInitX = Math.round(mState.mStylusDownX);
- final int roundedInitY = Math.round(mState.mStylusDownY);
- if (editorBounds.contains(roundedInitX, roundedInitY)) {
- startHandwriting(connectedView);
- }
+ Rect handwritingArea = getViewHandwritingArea(connectedView);
+ if (handwritingArea != null) {
+ if (contains(handwritingArea, mState.mStylusDownX, mState.mStylusDownY)) {
+ startHandwriting(connectedView);
}
}
reset();
@@ -251,10 +260,79 @@
/** For test only. */
@VisibleForTesting
- public void startHandwriting(View view) {
+ public void startHandwriting(@NonNull View view) {
mImm.startStylusHandwriting(view);
}
+ /**
+ * Notify that the handwriting area for the given view might be updated.
+ * @param view the view whose handwriting area might be updated.
+ */
+ public void updateHandwritingAreasForView(@NonNull View view) {
+ mHandwritingAreasTracker.updateHandwritingAreaForView(view);
+ }
+
+ /**
+ * Given the location of the stylus event, return the best candidate view to initialize
+ * handwriting mode.
+ *
+ * @param x the x coordinates of the stylus event, in the coordinates of the window.
+ * @param y the y coordinates of the stylus event, in the coordinates of the window.
+ */
+ @Nullable
+ private View findBestCandidateView(float x, float y) {
+ // If the connectedView is not null and do not set any handwriting area, it will check
+ // whether the connectedView's boundary contains the initial stylus position. If true,
+ // directly return the connectedView.
+ final View connectedView = getConnectedView();
+ if (connectedView != null && connectedView.isAutoHandwritingEnabled()) {
+ final Rect handwritingArea = getViewHandwritingArea(connectedView);
+ if (handwritingArea != null && contains(handwritingArea, x, y)) {
+ return connectedView;
+ }
+ }
+
+ // Check the registered handwriting areas.
+ final List<HandwritableViewInfo> handwritableViewInfos =
+ mHandwritingAreasTracker.computeViewInfos();
+ for (HandwritableViewInfo viewInfo : handwritableViewInfos) {
+ final View view = viewInfo.getView();
+ if (!view.isAutoHandwritingEnabled()) continue;
+ final Rect rect = viewInfo.getHandwritingArea();
+ if (rect != null && contains(rect, x, y)) {
+ return viewInfo.getView();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return the handwriting area of the given view, represented in the window's coordinate.
+ * If the view didn't set any handwriting area, it will return the view's boundary.
+ * It will return null if the view or its handwriting area is not visible.
+ */
+ @Nullable
+ private static Rect getViewHandwritingArea(@NonNull View view) {
+ final ViewParent viewParent = view.getParent();
+ if (viewParent != null && view.isAttachedToWindow() && view.isAggregatedVisible()) {
+ Rect handwritingArea = view.getHandwritingArea();
+ if (handwritingArea == null) {
+ handwritingArea = new Rect(0, 0, view.getWidth(), view.getHeight());
+ }
+ if (viewParent.getChildVisibleRect(view, handwritingArea, null)) {
+ return handwritingArea;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return true if the (x, y) is inside by the given {@link Rect}.
+ */
+ private boolean contains(@NonNull Rect rect, float x, float y) {
+ return x >= rect.left && x < rect.right && y >= rect.top && y < rect.bottom;
+ }
+
private boolean largerThanTouchSlop(float x1, float y1, float x2, float y2) {
float dx = x1 - x2;
float dy = y1 - y2;
@@ -291,4 +369,134 @@
private float mStylusDownX = Float.NaN;
private float mStylusDownY = Float.NaN;
}
+
+ /** The helper method to check if the given view is still active for handwriting. */
+ private static boolean isViewActive(@Nullable View view) {
+ return view != null && view.isAttachedToWindow() && view.isAggregatedVisible()
+ && view.isAutoHandwritingEnabled();
+ }
+
+ /**
+ * A class used to track the handwriting areas set by the Views.
+ *
+ * @hide
+ */
+ @VisibleForTesting
+ public static class HandwritingAreaTracker {
+ private final List<HandwritableViewInfo> mHandwritableViewInfos;
+
+ public HandwritingAreaTracker() {
+ mHandwritableViewInfos = new ArrayList<>();
+ }
+
+ /**
+ * Notify this tracker that the handwriting area of the given view has been updated.
+ * This method does three things:
+ * a) iterate over the all the tracked ViewInfos and remove those already invalid ones.
+ * b) mark the given view's ViewInfo to be dirty. So that next time when
+ * {@link #computeViewInfos} is called, this view's handwriting area will be recomputed.
+ * c) If no the given view is not in the tracked ViewInfo list, a new ViewInfo object will
+ * be created and added to the list.
+ *
+ * @param view the view whose handwriting area is updated.
+ */
+ public void updateHandwritingAreaForView(@NonNull View view) {
+ Iterator<HandwritableViewInfo> iterator = mHandwritableViewInfos.iterator();
+ boolean found = false;
+ while (iterator.hasNext()) {
+ final HandwritableViewInfo handwritableViewInfo = iterator.next();
+ final View curView = handwritableViewInfo.getView();
+ if (!isViewActive(curView)) {
+ iterator.remove();
+ }
+ if (curView == view) {
+ found = true;
+ handwritableViewInfo.mIsDirty = true;
+ }
+ }
+ if (!found && isViewActive(view)) {
+ // The given view is not tracked. Create a new HandwritableViewInfo for it and add
+ // to the list.
+ mHandwritableViewInfos.add(new HandwritableViewInfo(view));
+ }
+ }
+
+ /**
+ * Update the handwriting areas and return a list of ViewInfos containing the view
+ * reference and its handwriting area.
+ */
+ @NonNull
+ public List<HandwritableViewInfo> computeViewInfos() {
+ mHandwritableViewInfos.removeIf(viewInfo -> !viewInfo.update());
+ return mHandwritableViewInfos;
+ }
+ }
+
+ /**
+ * A class that reference to a View and its handwriting area(in the ViewRoot's coordinate.)
+ *
+ * @hide
+ */
+ @VisibleForTesting
+ public static class HandwritableViewInfo {
+ final WeakReference<View> mViewRef;
+ Rect mHandwritingArea = null;
+ @VisibleForTesting
+ public boolean mIsDirty = true;
+
+ @VisibleForTesting
+ public HandwritableViewInfo(@NonNull View view) {
+ mViewRef = new WeakReference<>(view);
+ }
+
+ /** Return the tracked view. */
+ @Nullable
+ public View getView() {
+ return mViewRef.get();
+ }
+
+ /**
+ * Return the tracked handwriting area, represented in the ViewRoot's coordinates.
+ * Notice, the caller should not modify the returned Rect.
+ */
+ @Nullable
+ public Rect getHandwritingArea() {
+ return mHandwritingArea;
+ }
+
+ /**
+ * Update the handwriting area in this ViewInfo.
+ *
+ * @return true if this ViewInfo is still valid. Or false if this ViewInfo has become
+ * invalid due to either view is no longer visible, or the handwriting area set by the
+ * view is removed. {@link HandwritingAreaTracker} no longer need to keep track of this
+ * HandwritableViewInfo this method returns false.
+ */
+ public boolean update() {
+ final View view = getView();
+ if (!isViewActive(view)) {
+ return false;
+ }
+
+ if (!mIsDirty) {
+ return true;
+ }
+ final Rect localRect = view.getHandwritingArea();
+ if (localRect == null) {
+ return false;
+ }
+
+ ViewParent parent = view.getParent();
+ if (parent != null) {
+ final Rect newRect = new Rect(localRect);
+ if (parent.getChildVisibleRect(view, newRect, null /* offset */)) {
+ mHandwritingArea = newRect;
+ } else {
+ mHandwritingArea = null;
+ }
+ }
+ mIsDirty = false;
+ return true;
+ }
+ }
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index c5ccc18..36baa04 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -941,4 +941,14 @@
* @hide
*/
void unregisterTaskFpsCallback(in IOnFpsCallbackListener listener);
+
+ /**
+ * Take a snapshot using the same path that's used for Recents. This is used for Testing only.
+ *
+ * @param taskId to take the snapshot of
+ *
+ * Returns a bitmap of the screenshot or {@code null} if it was unable to screenshot.
+ * @hide
+ */
+ Bitmap snapshotTaskForRecents(int taskId);
}
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 32054b1..a266a28 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -298,7 +298,7 @@
*/
void grantInputChannel(int displayId, in SurfaceControl surface, in IWindow window,
in IBinder hostInputToken, int flags, int privateFlags, int type,
- in IBinder focusGrantToken, out InputChannel outInputChannel);
+ in IBinder focusGrantToken, String inputHandleName, out InputChannel outInputChannel);
/**
* Update the flags on an input channel associated with a particular surface.
@@ -337,8 +337,10 @@
*
* @param window The token for the window to set the callback to.
* @param callback The {@link IOnBackInvokedCallback} to set.
+ * @param priority The priority of the callback.
*/
- oneway void setOnBackInvokedCallback(IWindow window, IOnBackInvokedCallback callback);
+ oneway void setOnBackInvokedCallback(
+ IWindow window, IOnBackInvokedCallback callback, int priority);
/**
* Clears a touchable region set by {@link #setInsets}.
diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS
index 43df294..e313388 100644
--- a/core/java/android/view/OWNERS
+++ b/core/java/android/view/OWNERS
@@ -11,6 +11,9 @@
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/OnBackInvokedCallback.java b/core/java/android/view/OnBackInvokedCallback.java
index b5cd89c..37f858a 100644
--- a/core/java/android/view/OnBackInvokedCallback.java
+++ b/core/java/android/view/OnBackInvokedCallback.java
@@ -18,6 +18,7 @@
import android.app.Activity;
import android.app.Dialog;
+import android.window.BackEvent;
/**
* Interface for applications to register back invocation callbacks. This allows the client
@@ -46,14 +47,12 @@
/**
* Called on back gesture progress.
*
- * @param touchX Absolute X location of the touch point.
- * @param touchY Absolute Y location of the touch point.
- * @param progress Value between 0 and 1 on how far along the back gesture is.
+ * @param backEvent An {@link android.window.BackEvent} object describing the progress event.
*
+ * @see android.window.BackEvent
* @hide
*/
- // TODO(b/210539672): combine back progress params into BackEvent.
- default void onBackProgressed(int touchX, int touchY, float progress) { };
+ default void onBackProgressed(BackEvent backEvent) { };
/**
* Called when a back gesture or back button press has been cancelled.
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 7f115fa..ce54968 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -49,6 +49,7 @@
import android.hardware.display.DeviceProductInfo;
import android.hardware.display.DisplayedContentSample;
import android.hardware.display.DisplayedContentSamplingAttributes;
+import android.hardware.graphics.common.DisplayDecorationSupport;
import android.os.Build;
import android.os.IBinder;
import android.os.Parcel;
@@ -235,7 +236,8 @@
float shadowRadius);
private static native void nativeSetGlobalShadowSettings(@Size(4) float[] ambientColor,
@Size(4) float[] spotColor, float lightPosY, float lightPosZ, float lightRadius);
- private static native boolean nativeGetDisplayDecorationSupport(IBinder displayToken);
+ private static native DisplayDecorationSupport nativeGetDisplayDecorationSupport(
+ IBinder displayToken);
private static native void nativeSetFrameRate(long transactionObj, long nativeObject,
float frameRate, int compatibility, int changeFrameRateStrategy);
@@ -2694,16 +2696,18 @@
}
/**
- * Returns whether a display supports DISPLAY_DECORATION.
+ * Returns whether/how a display supports DISPLAY_DECORATION.
*
* @param displayToken
* The token for the display.
*
- * @return Whether the display supports DISPLAY_DECORATION.
+ * @return A class describing how the display supports DISPLAY_DECORATION or null if it does
+ * not.
*
+ * TODO (b/218524164): Move this out of SurfaceControl.
* @hide
*/
- public static boolean getDisplayDecorationSupport(IBinder displayToken) {
+ public static DisplayDecorationSupport getDisplayDecorationSupport(IBinder displayToken) {
return nativeGetDisplayDecorationSupport(displayToken);
}
@@ -2779,9 +2783,13 @@
* is allowed as a convenience.
*/
public Transaction() {
- mNativeObject = nativeCreateTransaction();
- mFreeNativeResources
- = sRegistry.registerNativeAllocation(this, mNativeObject);
+ this(nativeCreateTransaction());
+ }
+
+ private Transaction(long nativeObject) {
+ mNativeObject = nativeObject;
+ mFreeNativeResources =
+ sRegistry.registerNativeAllocation(this, mNativeObject);
}
private Transaction(Parcel in) {
@@ -3692,21 +3700,32 @@
/**
* Sets the buffer transform that should be applied to the current buffer.
*
+ * This can be used in combination with
+ * {@link AttachedSurfaceControl#addOnBufferTransformHintChangedListener(AttachedSurfaceControl.OnBufferTransformHintChangedListener)}
+ * to pre-rotate the buffer for the current display orientation. This can
+ * improve the performance of displaying the associated buffer.
+ *
* @param sc The SurfaceControl to update
* @param transform The transform to apply to the buffer.
* @return this
*/
public @NonNull Transaction setBufferTransform(@NonNull SurfaceControl sc,
- /* TODO: Mark the intdef */ int transform) {
+ @SurfaceControl.BufferTransform int transform) {
checkPreconditions(sc);
nativeSetBufferTransform(mNativeObject, sc.mNativeObject, transform);
return this;
}
/**
- * Updates the region for the content on this surface updated in this transaction.
+ * Updates the region for the content on this surface updated in this transaction. The
+ * damage region is the area of the buffer that has changed since the previously
+ * sent buffer. This can be used to reduce the amount of recomposition that needs
+ * to happen when only a small region of the buffer is being updated, such as for
+ * a small blinking cursor or a loading indicator.
*
- * If unspecified, the complete surface is assumed to be damaged.
+ * @param sc The SurfaceControl on which to set the damage region
+ * @param region The region to set. If null, the entire buffer is assumed dirty. This is
+ * equivalent to not setting a damage region at all.
*/
public @NonNull Transaction setDamageRegion(@NonNull SurfaceControl sc,
@Nullable Region region) {
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index 7e0d887..2edfda5 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -27,8 +27,10 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
-import android.view.accessibility.IAccessibilityEmbeddedConnection;
+import android.util.Log;
import android.view.InsetsState;
+import android.view.WindowManagerGlobal;
+import android.view.accessibility.IAccessibilityEmbeddedConnection;
import java.util.Objects;
@@ -43,11 +45,13 @@
* {@link SurfaceView#setChildSurfacePackage}.
*/
public class SurfaceControlViewHost {
+ private final static String TAG = "SurfaceControlViewHost";
private final ViewRootImpl mViewRoot;
private WindowlessWindowManager mWm;
private SurfaceControl mSurfaceControl;
private IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection;
+ private boolean mReleased = false;
private final class ISurfaceControlViewHostImpl extends ISurfaceControlViewHost.Stub {
@Override
@@ -268,6 +272,8 @@
@NonNull WindowlessWindowManager wwm, boolean useSfChoreographer) {
mWm = wwm;
mViewRoot = new ViewRootImpl(c, d, mWm, useSfChoreographer);
+ WindowManagerGlobal.getInstance().addWindowlessRoot(mViewRoot);
+
mAccessibilityEmbeddedConnection = mViewRoot.getAccessibilityEmbeddedConnection();
}
@@ -292,7 +298,10 @@
.build();
mWm = new WindowlessWindowManager(context.getResources().getConfiguration(),
mSurfaceControl, hostToken);
+
mViewRoot = new ViewRootImpl(context, display, mWm);
+ WindowManagerGlobal.getInstance().addWindowlessRoot(mViewRoot);
+
mAccessibilityEmbeddedConnection = mViewRoot.getAccessibilityEmbeddedConnection();
}
@@ -301,12 +310,15 @@
*/
@Override
protected void finalize() throws Throwable {
- // We aren't on the UI thread here so we need to pass false to
- // doDie
+ if (mReleased) {
+ return;
+ }
+ Log.e(TAG, "SurfaceControlViewHost finalized without being released: " + this);
+ // We aren't on the UI thread here so we need to pass false to doDie
mViewRoot.die(false /* immediate */);
+ WindowManagerGlobal.getInstance().removeWindowlessRoot(mViewRoot);
}
-
/**
* Return a SurfacePackage for the root SurfaceControl of the embedded hierarchy.
* Rather than be directly reparented using {@link SurfaceControl.Transaction} this
@@ -413,5 +425,14 @@
public void release() {
// ViewRoot will release mSurfaceControl for us.
mViewRoot.die(true /* immediate */);
+ WindowManagerGlobal.getInstance().removeWindowlessRoot(mViewRoot);
+ mReleased = true;
+ }
+
+ /**
+ * @hide
+ */
+ public IBinder getFocusGrantToken() {
+ return mWm.getFocusGrantToken();
}
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 83a59e7..1a458ce 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -23,7 +23,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.res.CompatibilityInfo.Translator;
import android.graphics.BLASTBufferQueue;
@@ -42,7 +41,6 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.SystemClock;
-import android.provider.Settings;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceControl.Transaction;
@@ -135,7 +133,7 @@
private boolean mDisableBackgroundLayer = false;
/**
- * We use this lock to protect access to mSurfaceControl and
+ * We use this lock to protect access to mSurfaceControl and
* SurfaceViewPositionUpdateListener#mPositionChangedTransaction. Both are accessed on the UI
* thread and the render thread.
*/
@@ -376,11 +374,7 @@
}
private void updateSurfaceAlpha() {
- if (!mUseAlpha) {
- if (DEBUG) {
- Log.d(TAG, System.identityHashCode(this)
- + " updateSurfaceAlpha: setUseAlpha() is not called, ignored.");
- }
+ if (!mUseAlpha || !mHaveFrame || mSurfaceControl == null) {
return;
}
final float viewAlpha = getAlpha();
@@ -389,88 +383,16 @@
+ " updateSurfaceAlpha:"
+ " translucent color is not supported for a surface placed z-below.");
}
- if (!mHaveFrame) {
- if (DEBUG) {
- Log.d(TAG, System.identityHashCode(this)
- + " updateSurfaceAlpha: has no surface.");
- }
- return;
- }
final ViewRootImpl viewRoot = getViewRootImpl();
if (viewRoot == null) {
- if (DEBUG) {
- Log.d(TAG, System.identityHashCode(this)
- + " updateSurfaceAlpha: ViewRootImpl not available.");
- }
- return;
- }
- if (mSurfaceControl == null) {
- if (DEBUG) {
- Log.d(TAG, System.identityHashCode(this)
- + "updateSurfaceAlpha:"
- + " surface is not yet created, or already released.");
- }
- return;
- }
- final Surface parent = viewRoot.mSurface;
- if (parent == null || !parent.isValid()) {
- if (DEBUG) {
- Log.d(TAG, System.identityHashCode(this)
- + " updateSurfaceAlpha: ViewRootImpl has no valid surface");
- }
return;
}
final float alpha = getFixedAlpha();
if (alpha != mSurfaceAlpha) {
- if (isHardwareAccelerated()) {
- /*
- * Schedule a callback that reflects an alpha value onto the underlying surfaces.
- * This gets called on a RenderThread worker thread, so members accessed here must
- * be protected by a lock.
- */
- viewRoot.registerRtFrameCallback(frame -> {
- try {
- synchronized (mSurfaceControlLock) {
- if (!parent.isValid()) {
- if (DEBUG) {
- Log.d(TAG, System.identityHashCode(this)
- + " updateSurfaceAlpha RT:"
- + " ViewRootImpl has no valid surface");
- }
- return;
- }
- if (mSurfaceControl == null) {
- if (DEBUG) {
- Log.d(TAG, System.identityHashCode(this)
- + "updateSurfaceAlpha RT:"
- + " mSurfaceControl has already released");
- }
- return;
- }
- if (DEBUG) {
- Log.d(TAG, System.identityHashCode(this)
- + " updateSurfaceAlpha RT: set alpha=" + alpha);
- }
-
- mFrameCallbackTransaction.setAlpha(mSurfaceControl, alpha);
- applyOrMergeTransaction(mFrameCallbackTransaction, frame);
- }
- // It's possible that mSurfaceControl is released in the UI thread before
- // the transaction completes. If that happens, an exception is thrown, which
- // must be caught immediately.
- } catch (Exception e) {
- Log.e(TAG, System.identityHashCode(this)
- + "updateSurfaceAlpha RT: Exception during surface transaction", e);
- }
- });
- damageInParent();
- } else {
- if (DEBUG) {
- Log.d(TAG, System.identityHashCode(this)
- + " updateSurfaceAlpha: set alpha=" + alpha);
- }
- mTmpTransaction.setAlpha(mSurfaceControl, alpha).apply();
- }
+ final Transaction transaction = new Transaction();
+ transaction.setAlpha(mSurfaceControl, alpha);
+ viewRoot.applyTransactionOnDraw(transaction);
+ damageInParent();
mSurfaceAlpha = alpha;
}
}
@@ -527,20 +449,7 @@
mRequestedVisible = false;
updateSurface();
- tryReleaseSurfaces();
-
- // We don't release this as part of releaseSurfaces as
- // that is also called on transient visibility changes. We can't
- // recreate this Surface, so only release it when we are fully
- // detached.
- if (mSurfacePackage != null) {
- final SurfaceControl sc = mSurfacePackage.getSurfaceControl();
- if (sc != null && sc.isValid()) {
- mTmpTransaction.reparent(sc, null).apply();
- }
- mSurfacePackage.release();
- mSurfacePackage = null;
- }
+ releaseSurfaces(true /* releaseSurfacePackage*/);
mHaveFrame = false;
super.onDetachedFromWindow();
@@ -633,7 +542,7 @@
public void setClipBounds(Rect clipBounds) {
super.setClipBounds(clipBounds);
- if (!mClipSurfaceToBounds) {
+ if (!mClipSurfaceToBounds || mSurfaceControl == null) {
return;
}
@@ -643,18 +552,15 @@
invalidate();
}
- if (mSurfaceControl != null) {
- if (mClipBounds != null) {
- mTmpRect.set(mClipBounds);
- } else {
- mTmpRect.set(0, 0, mSurfaceWidth, mSurfaceHeight);
- }
- SyncRtSurfaceTransactionApplier applier = new SyncRtSurfaceTransactionApplier(this);
- applier.scheduleApply(
- new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(mSurfaceControl)
- .withWindowCrop(mTmpRect)
- .build());
+ if (mClipBounds != null) {
+ mTmpRect.set(mClipBounds);
+ } else {
+ mTmpRect.set(0, 0, mSurfaceWidth, mSurfaceHeight);
}
+ final Transaction transaction = new Transaction();
+ transaction.setWindowCrop(mSurfaceControl, mTmpRect);
+ applyTransactionOnVriDraw(transaction);
+ invalidate();
}
private void clearSurfaceViewPort(Canvas canvas) {
@@ -790,37 +696,10 @@
if (viewRoot == null) {
return true;
}
- final Surface parent = viewRoot.mSurface;
- if (parent == null || !parent.isValid()) {
- return true;
- }
-
- /*
- * Schedule a callback that reflects an alpha value onto the underlying surfaces.
- * This gets called on a RenderThread worker thread, so members accessed here must
- * be protected by a lock.
- */
- viewRoot.registerRtFrameCallback(frame -> {
- try {
- synchronized (mSurfaceControlLock) {
- if (!parent.isValid() || mSurfaceControl == null) {
- return;
- }
-
- updateRelativeZ(mFrameCallbackTransaction);
- applyOrMergeTransaction(mFrameCallbackTransaction, frame);
- }
- // It's possible that mSurfaceControl is released in the UI thread before
- // the transaction completes. If that happens, an exception is thrown, which
- // must be caught immediately.
- } catch (Exception e) {
- Log.e(TAG, System.identityHashCode(this)
- + "setZOrderOnTop RT: Exception during surface transaction", e);
- }
- });
-
+ final Transaction transaction = new SurfaceControl.Transaction();
+ updateRelativeZ(transaction);
+ viewRoot.applyTransactionOnDraw(transaction);
invalidate();
-
return true;
}
@@ -871,7 +750,7 @@
return t;
}
- private void tryReleaseSurfaces() {
+ private void releaseSurfaces(boolean releaseSurfacePackage) {
mSurfaceAlpha = 1f;
synchronized (mSurfaceControlLock) {
@@ -881,33 +760,29 @@
mBlastBufferQueue = null;
}
- ViewRootImpl viewRoot = getViewRootImpl();
Transaction transaction = new Transaction();
- releaseSurfaces(transaction);
- if (viewRoot != null) {
- viewRoot.applyTransactionOnDraw(transaction);
- } else {
- transaction.apply();
+ if (mSurfaceControl != null) {
+ transaction.remove(mSurfaceControl);
+ mSurfaceControl = null;
}
+ if (mBackgroundControl != null) {
+ transaction.remove(mBackgroundControl);
+ mBackgroundControl = null;
+ }
+ if (mBlastSurfaceControl != null) {
+ transaction.remove(mBlastSurfaceControl);
+ mBlastSurfaceControl = null;
+ }
+
+ if (releaseSurfacePackage && mSurfacePackage != null) {
+ mSurfacePackage.release();
+ mSurfacePackage = null;
+ }
+
+ applyTransactionOnVriDraw(transaction);
}
}
- private void releaseSurfaces(Transaction transaction) {
- if (mSurfaceControl != null) {
- transaction.remove(mSurfaceControl);
- mSurfaceControl = null;
- }
- if (mBackgroundControl != null) {
- transaction.remove(mBackgroundControl);
- mBackgroundControl = null;
- }
- if (mBlastSurfaceControl != null) {
- transaction.remove(mBlastSurfaceControl);
- mBlastSurfaceControl = null;
- }
- }
-
-
// The position update listener is used to safely share the surface size between render thread
// workers and the UI thread. Both threads need to know the surface size to determine the scale.
// The parent layer scales the surface size to view size. The child (BBQ) layer scales
@@ -1048,7 +923,7 @@
if (viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
notifySurfaceDestroyed();
- tryReleaseSurfaces();
+ releaseSurfaces(false /* releaseSurfacePackage*/);
return;
}
@@ -1189,7 +1064,7 @@
} finally {
mIsCreating = false;
if (mSurfaceControl != null && !mSurfaceCreated) {
- tryReleaseSurfaces();
+ releaseSurfaces(false /* releaseSurfacePackage*/);
}
}
} catch (Exception ex) {
@@ -1324,17 +1199,6 @@
}
/**
- * A place to over-ride for applying child-surface transactions.
- * These can be synchronized with the viewroot surface using deferTransaction.
- *
- * Called from RenderWorker while UI thread is paused.
- * @hide
- */
- protected void applyChildSurfaceTransaction_renderWorker(SurfaceControl.Transaction t,
- Surface viewRootSurface, long nextViewRootFrameNumber) {
- }
-
- /**
* Sets the surface position and scale. Can be called on
* the UI thread as well as on the renderer thread.
*
@@ -1442,11 +1306,6 @@
if (mViewVisibility) {
mPositionChangedTransaction.show(mSurfaceControl);
}
- final ViewRootImpl viewRoot = getViewRootImpl();
- if (viewRoot != null) {
- applyChildSurfaceTransaction_renderWorker(mPositionChangedTransaction,
- viewRoot.mSurface, frameNumber);
- }
applyOrMergeTransaction(mPositionChangedTransaction, frameNumber);
mPendingTransaction = false;
} catch (Exception ex) {
@@ -1835,43 +1694,19 @@
* @param p The SurfacePackage to embed.
*/
public void setChildSurfacePackage(@NonNull SurfaceControlViewHost.SurfacePackage p) {
- setChildSurfacePackage(p, false /* applyTransactionOnDraw */);
- }
-
- /**
- * Similar to setChildSurfacePackage, but using the BLAST queue so the transaction can be
- * synchronized with the ViewRootImpl frame.
- * @hide
- */
- public void setChildSurfacePackageOnDraw(
- @NonNull SurfaceControlViewHost.SurfacePackage p) {
- setChildSurfacePackage(p, true /* applyTransactionOnDraw */);
- }
-
- /**
- * @param applyTransactionOnDraw Whether to apply transaction at onDraw or immediately.
- */
- private void setChildSurfacePackage(
- @NonNull SurfaceControlViewHost.SurfacePackage p, boolean applyTransactionOnDraw) {
final SurfaceControl lastSc = mSurfacePackage != null ?
mSurfacePackage.getSurfaceControl() : null;
+ final SurfaceControl.Transaction transaction = new Transaction();
if (mSurfaceControl != null) {
if (lastSc != null) {
- mTmpTransaction.reparent(lastSc, null);
+ transaction.reparent(lastSc, null);
mSurfacePackage.release();
}
- reparentSurfacePackage(mTmpTransaction, p);
- applyTransaction(applyTransactionOnDraw);
+ reparentSurfacePackage(transaction, p);
+ applyTransactionOnVriDraw(transaction);
}
mSurfacePackage = p;
- }
-
- private void applyTransaction(boolean applyTransactionOnDraw) {
- if (applyTransactionOnDraw) {
- getViewRootImpl().applyTransactionOnDraw(mTmpTransaction);
- } else {
- mTmpTransaction.apply();
- }
+ invalidate();
}
private void reparentSurfacePackage(SurfaceControl.Transaction t,
@@ -1974,4 +1809,13 @@
}
}
+ private void applyTransactionOnVriDraw(Transaction t) {
+ final ViewRootImpl viewRoot = getViewRootImpl();
+ if (viewRoot != null) {
+ // If we are using BLAST, merge the transaction with the viewroot buffer transaction.
+ viewRoot.applyTransactionOnDraw(t);
+ } else {
+ t.apply();
+ }
+ }
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f74b599..179f6ee 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4745,9 +4745,11 @@
private List<Rect> mSystemGestureExclusionRects = null;
private List<Rect> mKeepClearRects = null;
private boolean mPreferKeepClear = false;
+ private Rect mHandwritingArea = null;
/**
- * Used to track {@link #mSystemGestureExclusionRects} and {@link #mKeepClearRects}
+ * Used to track {@link #mSystemGestureExclusionRects}, {@link #mKeepClearRects} and
+ * {@link #mHandwritingArea}.
*/
public RenderNode.PositionUpdateListener mPositionUpdateListener;
private Runnable mPositionChangedUpdate;
@@ -11710,7 +11712,8 @@
private void updatePositionUpdateListener() {
final ListenerInfo info = getListenerInfo();
if (getSystemGestureExclusionRects().isEmpty()
- && collectPreferKeepClearRects().isEmpty()) {
+ && collectPreferKeepClearRects().isEmpty()
+ && (info.mHandwritingArea == null || !isAutoHandwritingEnabled())) {
if (info.mPositionUpdateListener != null) {
mRenderNode.removePositionUpdateListener(info.mPositionUpdateListener);
info.mPositionChangedUpdate = null;
@@ -11720,6 +11723,7 @@
info.mPositionChangedUpdate = () -> {
updateSystemGestureExclusionRects();
updateKeepClearRects();
+ updateHandwritingArea();
};
info.mPositionUpdateListener = new RenderNode.PositionUpdateListener() {
@Override
@@ -11876,6 +11880,51 @@
}
/**
+ * Set a list of handwriting areas in this view. If there is any stylus {@link MotionEvent}
+ * occurs within those areas, it will trigger stylus handwriting mode. This can be disabled by
+ * disabling the auto handwriting initiation by calling
+ * {@link #setAutoHandwritingEnabled(boolean)} with false.
+ *
+ * @attr rects a list of handwriting area in the view's local coordiniates.
+ *
+ * @see android.view.inputmethod.InputMethodManager#startStylusHandwriting(View)
+ * @see #setAutoHandwritingEnabled(boolean)
+ *
+ * @hide
+ */
+ public void setHandwritingArea(@Nullable Rect rect) {
+ final ListenerInfo info = getListenerInfo();
+ info.mHandwritingArea = rect;
+ updatePositionUpdateListener();
+ postUpdate(this::updateHandwritingArea);
+ }
+
+ /**
+ * Return the handwriting areas set on this view, in its local coordinates.
+ * Notice: the caller of this method should not modify the Rect returned.
+ * @see #setHandwritingArea(Rect)
+ *
+ * @hide
+ */
+ @Nullable
+ public Rect getHandwritingArea() {
+ final ListenerInfo info = mListenerInfo;
+ if (info != null) {
+ return info.mHandwritingArea;
+ }
+ return null;
+ }
+
+ void updateHandwritingArea() {
+ // If autoHandwritingArea is not enabled, do nothing.
+ if (!isAutoHandwritingEnabled()) return;
+ final AttachInfo ai = mAttachInfo;
+ if (ai != null) {
+ ai.mViewRootImpl.getHandwritingInitiator().updateHandwritingAreasForView(this);
+ }
+ }
+
+ /**
* Compute the view's coordinate within the surface.
*
* <p>Computes the coordinates of this view in its surface. The argument
@@ -31181,6 +31230,8 @@
} else {
mPrivateFlags4 &= ~PFLAG4_AUTO_HANDWRITING_ENABLED;
}
+ updatePositionUpdateListener();
+ postUpdate(this::updateHandwritingArea);
}
/**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 777e89d..8236fbb 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -583,6 +583,12 @@
boolean mForceNextWindowRelayout;
CountDownLatch mWindowDrawCountDown;
+ // Whether we have used applyTransactionOnDraw to schedule an RT
+ // frame callback consuming a passed in transaction. In this case
+ // we also need to schedule a commit callback so we can observe
+ // if the draw was skipped, and the BBQ pending transactions.
+ boolean mHasPendingTransactions;
+
boolean mIsDrawing;
int mLastSystemUiVisibility;
int mClientWindowLayoutFlags;
@@ -1788,10 +1794,16 @@
}
void pokeDrawLockIfNeeded() {
- final int displayState = mAttachInfo.mDisplayState;
- if (mView != null && mAdded && mTraversalScheduled
- && (displayState == Display.STATE_DOZE
- || displayState == Display.STATE_DOZE_SUSPEND)) {
+ if (!Display.isDozeState(mAttachInfo.mDisplayState)) {
+ // Only need to acquire wake lock for DOZE state.
+ return;
+ }
+ if (mWindowAttributes.type != WindowManager.LayoutParams.TYPE_BASE_APPLICATION) {
+ // Non-activity windows should be responsible to hold wake lock by themself, because
+ // usually they are system windows.
+ return;
+ }
+ if (mAdded && mTraversalScheduled && mAttachInfo.mHasWindowFocus) {
try {
mWindowSession.pokeDrawLock(mWindow);
} catch (RemoteException ex) {
@@ -4169,19 +4181,25 @@
+ " didProduceBuffer=" + didProduceBuffer);
}
+ Transaction tmpTransaction = new Transaction();
+ tmpTransaction.merge(mRtBLASTSyncTransaction);
+
// If frame wasn't drawn, clear out the next transaction so it doesn't affect the next
// draw attempt. The next transaction and transaction complete callback were only set
// for the current draw attempt.
if (!didProduceBuffer) {
mBlastBufferQueue.setSyncTransaction(null);
- // Apply the transactions that were sent to mergeWithNextTransaction since the
+ // Get the transactions that were sent to mergeWithNextTransaction since the
// frame didn't draw on this vsync. It's possible the frame will draw later, but
// it's better to not be sync than to block on a frame that may never come.
- mBlastBufferQueue.applyPendingTransactions(mRtLastAttemptedDrawFrameNum);
+ Transaction pendingTransactions = mBlastBufferQueue.gatherPendingTransactions(
+ mRtLastAttemptedDrawFrameNum);
+ tmpTransaction.merge(pendingTransactions);
+ }
+ if (!useBlastSync && !reportNextDraw) {
+ tmpTransaction.apply();
}
- Transaction tmpTransaction = new Transaction();
- tmpTransaction.merge(mRtBLASTSyncTransaction);
// Post at front of queue so the buffer can be processed immediately and allow RT
// to continue processing new buffers. If RT tries to process buffers before the sync
// buffer is applied, the new buffers will not get acquired and could result in a
@@ -4211,7 +4229,7 @@
final boolean hasBlurUpdates = mBlurRegionAggregator.hasUpdates();
final boolean needsCallbackForBlur = hasBlurUpdates || mBlurRegionAggregator.hasRegions();
- if (!useBlastSync && !needsCallbackForBlur && !reportNextDraw) {
+ if (!useBlastSync && !needsCallbackForBlur && !reportNextDraw && !mHasPendingTransactions) {
return null;
}
@@ -4223,11 +4241,14 @@
+ " nextDrawUseBlastSync=" + useBlastSync
+ " reportNextDraw=" + reportNextDraw
+ " hasBlurUpdates=" + hasBlurUpdates
- + " hasBlastSyncConsumer=" + (blastSyncConsumer != null));
+ + " hasBlastSyncConsumer=" + (blastSyncConsumer != null)
+ + " mHasPendingTransactions=" + mHasPendingTransactions);
}
final BackgroundBlurDrawable.BlurRegion[] blurRegionsForFrame =
needsCallbackForBlur ? mBlurRegionAggregator.getBlurRegionsCopyForRT() : null;
+ final boolean hasPendingTransactions = mHasPendingTransactions;
+ mHasPendingTransactions = false;
// The callback will run on the render thread.
return new FrameDrawingCallback() {
@@ -4254,7 +4275,7 @@
return null;
}
- if (!useBlastSync && !reportNextDraw) {
+ if (!useBlastSync && !reportNextDraw && !hasPendingTransactions) {
return null;
}
@@ -10697,7 +10718,10 @@
if (mRemoved || !isHardwareEnabled()) {
t.apply();
} else {
- registerRtFrameCallback(frame -> mergeWithNextTransaction(t, frame));
+ mHasPendingTransactions = true;
+ registerRtFrameCallback(frame -> {
+ mergeWithNextTransaction(t, frame);
+ });
}
return true;
}
@@ -10838,6 +10862,7 @@
private void unregisterCompatOnBackInvokedCallback() {
if (mCompatOnBackInvokedCallback != null) {
mOnBackInvokedDispatcher.unregisterOnBackInvokedCallback(mCompatOnBackInvokedCallback);
+ mCompatOnBackInvokedCallback = null;
}
}
@@ -10851,4 +10876,8 @@
mLastGivenInsets.reset();
requestLayout();
}
+
+ IWindowSession getWindowSession() {
+ return mWindowSession;
+ }
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index ca7f900..771d40b 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -97,6 +97,7 @@
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
+import android.graphics.Bitmap;
import android.graphics.Insets;
import android.graphics.PixelFormat;
import android.graphics.Point;
@@ -4886,4 +4887,21 @@
*/
@SystemApi
default void unregisterTaskFpsCallback(@NonNull TaskFpsCallback callback) {}
+
+ /**
+ * Take a snapshot using the same path that's used for Recents. This is used for Testing only.
+ *
+ * @param taskId to take the snapshot of
+ *
+ * @return a bitmap of the screenshot or {@code null} if it was unable to screenshot. The
+ * screenshot can fail if the taskId is invalid or if there's no SurfaceControl associated with
+ * that task.
+ *
+ * @hide
+ */
+ @TestApi
+ @Nullable
+ default Bitmap snapshotTaskForRecents(@IntRange(from = 0) int taskId) {
+ return null;
+ }
}
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index c92a3a0..93cb0dd7 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -159,6 +159,8 @@
new ArrayList<WindowManager.LayoutParams>();
private final ArraySet<View> mDyingViews = new ArraySet<View>();
+ private final ArrayList<ViewRootImpl> mWindowlessRoots = new ArrayList<ViewRootImpl>();
+
private Runnable mSystemPropertyUpdater;
private WindowManagerGlobal() {
@@ -387,7 +389,25 @@
}
}
- root = new ViewRootImpl(view.getContext(), display);
+ IWindowSession windowlessSession = null;
+ // If there is a parent set, but we can't find it, it may be coming
+ // from a SurfaceControlViewHost hierarchy.
+ if (wparams.token != null && panelParentView == null) {
+ for (int i = 0; i < mWindowlessRoots.size(); i++) {
+ ViewRootImpl maybeParent = mWindowlessRoots.get(i);
+ if (maybeParent.getWindowToken() == wparams.token) {
+ windowlessSession = maybeParent.getWindowSession();
+ break;
+ }
+ }
+ }
+
+ if (windowlessSession == null) {
+ root = new ViewRootImpl(view.getContext(), display);
+ } else {
+ root = new ViewRootImpl(view.getContext(), display,
+ windowlessSession);
+ }
view.setLayoutParams(wparams);
@@ -720,6 +740,20 @@
throw e.rethrowFromSystemServer();
}
}
+
+ /** @hide */
+ public void addWindowlessRoot(ViewRootImpl impl) {
+ synchronized (mLock) {
+ mWindowlessRoots.add(impl);
+ }
+ }
+
+ /** @hide */
+ public void removeWindowlessRoot(ViewRootImpl impl) {
+ synchronized (mLock) {
+ mWindowlessRoots.remove(impl);
+ }
+ }
}
final class WindowLeaked extends AndroidRuntimeException {
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index c16703ef..f4353eb 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -32,6 +32,7 @@
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.Configuration;
+import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Bundle;
@@ -439,4 +440,14 @@
} catch (RemoteException e) {
}
}
+
+ @Override
+ public Bitmap snapshotTaskForRecents(int taskId) {
+ try {
+ return WindowManagerGlobal.getWindowManagerService().snapshotTaskForRecents(taskId);
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ }
+ return null;
+ }
}
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 56f0915..c81b8cc 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -27,8 +27,6 @@
import android.os.RemoteException;
import android.util.Log;
import android.util.MergedConfiguration;
-import android.view.InsetsState;
-import android.view.IWindow;
import android.window.ClientWindowFrames;
import android.window.IOnBackInvokedCallback;
@@ -160,14 +158,15 @@
if (((attrs.inputFeatures &
WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0)) {
try {
- if(mRealWm instanceof IWindowSession.Stub) {
+ if (mRealWm instanceof IWindowSession.Stub) {
mRealWm.grantInputChannel(displayId,
- new SurfaceControl(sc, "WindowlessWindowManager.addToDisplay"),
- window, mHostInputToken, attrs.flags, attrs.privateFlags, attrs.type,
- mFocusGrantToken, outInputChannel);
+ new SurfaceControl(sc, "WindowlessWindowManager.addToDisplay"),
+ window, mHostInputToken, attrs.flags, attrs.privateFlags, attrs.type,
+ mFocusGrantToken, attrs.getTitle().toString(), outInputChannel);
} else {
mRealWm.grantInputChannel(displayId, sc, window, mHostInputToken, attrs.flags,
- attrs.privateFlags, attrs.type, mFocusGrantToken, outInputChannel);
+ attrs.privateFlags, attrs.type, mFocusGrantToken,
+ attrs.getTitle().toString(), outInputChannel);
}
} catch (RemoteException e) {
Log.e(TAG, "Failed to grant input to surface: ", e);
@@ -485,7 +484,7 @@
@Override
public void grantInputChannel(int displayId, SurfaceControl surface, IWindow window,
IBinder hostInputToken, int flags, int privateFlags, int type, IBinder focusGrantToken,
- InputChannel outInputChannel) {
+ String inputHandleName, InputChannel outInputChannel) {
}
@Override
@@ -510,7 +509,7 @@
@Override
public void setOnBackInvokedCallback(IWindow iWindow,
- IOnBackInvokedCallback iOnBackInvokedCallback) throws RemoteException { }
+ IOnBackInvokedCallback iOnBackInvokedCallback, int priority) throws RemoteException { }
@Override
public boolean dropForAccessibility(IWindow window, int x, int y) {
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 82e823f..07b7a18 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -19,6 +19,8 @@
import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_INTERACTION_CLIENT;
import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION_CALLBACK;
import static android.os.Build.VERSION_CODES.S;
+import static android.view.accessibility.AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS_MASK;
+import static android.view.accessibility.AccessibilityNodeInfo.FLAG_PREFETCH_MASK;
import android.accessibilityservice.IAccessibilityServiceConnection;
import android.annotation.NonNull;
@@ -301,10 +303,11 @@
* @param connectionId The id of a connection for interacting with the system.
* @return The root {@link AccessibilityNodeInfo} if found, null otherwise.
*/
- public AccessibilityNodeInfo getRootInActiveWindow(int connectionId) {
+ public AccessibilityNodeInfo getRootInActiveWindow(int connectionId,
+ @AccessibilityNodeInfo.PrefetchingStrategy int strategy) {
return findAccessibilityNodeInfoByAccessibilityId(connectionId,
AccessibilityWindowInfo.ACTIVE_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID,
- false, AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS, null);
+ false, strategy, null);
}
/**
@@ -529,11 +532,6 @@
public @Nullable AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityId(
int connectionId, int accessibilityWindowId, long accessibilityNodeId,
boolean bypassCache, int prefetchFlags, Bundle arguments) {
- if ((prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS) != 0
- && (prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) == 0) {
- throw new IllegalArgumentException("FLAG_PREFETCH_SIBLINGS"
- + " requires FLAG_PREFETCH_PREDECESSORS");
- }
try {
IAccessibilityServiceConnection connection = getConnection(connectionId);
if (connection != null) {
@@ -560,7 +558,7 @@
}
if (!cache.isEnabled()) {
// Skip prefetching if cache is disabled.
- prefetchFlags &= ~AccessibilityNodeInfo.FLAG_PREFETCH_MASK;
+ prefetchFlags &= ~FLAG_PREFETCH_MASK;
}
if (DEBUG) {
Log.i(LOG_TAG, "Node cache miss for "
@@ -573,12 +571,18 @@
}
} else {
// No need to prefech nodes in bypass cache case.
- prefetchFlags &= ~AccessibilityNodeInfo.FLAG_PREFETCH_MASK;
+ prefetchFlags &= ~FLAG_PREFETCH_MASK;
}
// Skip prefetching if window is scrolling.
- if ((prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_MASK) != 0
+ if ((prefetchFlags & FLAG_PREFETCH_MASK) != 0
&& isWindowScrolling(accessibilityWindowId)) {
- prefetchFlags &= ~AccessibilityNodeInfo.FLAG_PREFETCH_MASK;
+ prefetchFlags &= ~FLAG_PREFETCH_MASK;
+ }
+
+ final int descendantPrefetchFlags = prefetchFlags & FLAG_PREFETCH_DESCENDANTS_MASK;
+ if ((descendantPrefetchFlags & (descendantPrefetchFlags - 1)) != 0) {
+ throw new IllegalArgumentException("There can be no more than one descendant"
+ + " prefetching strategy");
}
final int interactionId = mInteractionIdCounter.getAndIncrement();
if (shouldTraceClient()) {
@@ -599,21 +603,41 @@
Binder.restoreCallingIdentity(identityToken);
}
if (packageNames != null) {
- AccessibilityNodeInfo info =
- getFindAccessibilityNodeInfoResultAndClear(interactionId);
- if (shouldTraceCallback()) {
- logTraceCallback(connection, "findAccessibilityNodeInfoByAccessibilityId",
- "InteractionId:" + interactionId + ";connectionId="
- + connectionId + ";Result: " + info);
+ if ((prefetchFlags
+ & AccessibilityNodeInfo.FLAG_PREFETCH_UNINTERRUPTIBLE) != 0) {
+ List<AccessibilityNodeInfo> infos =
+ getFindAccessibilityNodeInfosResultAndClear(
+ interactionId);
+ if (shouldTraceCallback()) {
+ logTraceCallback(connection,
+ "findAccessibilityNodeInfoByAccessibilityId",
+ "InteractionId:" + interactionId + ";connectionId="
+ + connectionId + ";Result: " + infos);
+ }
+ finalizeAndCacheAccessibilityNodeInfos(infos, connectionId,
+ bypassCache, packageNames);
+ if (infos != null && !infos.isEmpty()) {
+ return infos.get(0);
+ }
+ } else {
+ AccessibilityNodeInfo info =
+ getFindAccessibilityNodeInfoResultAndClear(interactionId);
+ if (shouldTraceCallback()) {
+ logTraceCallback(connection,
+ "findAccessibilityNodeInfoByAccessibilityId",
+ "InteractionId:" + interactionId + ";connectionId="
+ + connectionId + ";Result: " + info);
+ }
+ if ((prefetchFlags & FLAG_PREFETCH_MASK) != 0
+ && info != null) {
+ setInteractionWaitingForPrefetchResult(interactionId, connectionId,
+ packageNames);
+ }
+ finalizeAndCacheAccessibilityNodeInfo(info, connectionId,
+ bypassCache, packageNames);
+ return info;
}
- if ((prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_MASK) != 0
- && info != null) {
- setInteractionWaitingForPrefetchResult(interactionId, connectionId,
- packageNames);
- }
- finalizeAndCacheAccessibilityNodeInfo(info, connectionId,
- bypassCache, packageNames);
- return info;
+
}
} else {
if (DEBUG) {
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index e54ed18..c6cd2e8 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -1773,8 +1773,7 @@
* @param userId The user Id.
* @hide
*/
- @RequiresPermission(Manifest.permission.SET_SYSTEM_AUDIO_CAPTION)
- public void setSystemAudioCaptioningRequested(boolean isEnabled, int userId) {
+ public void setSystemAudioCaptioningEnabled(boolean isEnabled, int userId) {
final IAccessibilityManager service;
synchronized (mLock) {
service = getServiceLocked();
@@ -1783,7 +1782,7 @@
}
}
try {
- service.setSystemAudioCaptioningRequested(isEnabled, userId);
+ service.setSystemAudioCaptioningEnabled(isEnabled, userId);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -1796,7 +1795,7 @@
* @return the system audio caption UI enabled state.
* @hide
*/
- public boolean isSystemAudioCaptioningUiRequested(int userId) {
+ public boolean isSystemAudioCaptioningUiEnabled(int userId) {
final IAccessibilityManager service;
synchronized (mLock) {
service = getServiceLocked();
@@ -1805,7 +1804,7 @@
}
}
try {
- return service.isSystemAudioCaptioningUiRequested(userId);
+ return service.isSystemAudioCaptioningUiEnabled(userId);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -1818,8 +1817,7 @@
* @param userId The user Id.
* @hide
*/
- @RequiresPermission(Manifest.permission.SET_SYSTEM_AUDIO_CAPTION)
- public void setSystemAudioCaptioningUiRequested(boolean isEnabled, int userId) {
+ public void setSystemAudioCaptioningUiEnabled(boolean isEnabled, int userId) {
final IAccessibilityManager service;
synchronized (mLock) {
service = getServiceLocked();
@@ -1828,7 +1826,7 @@
}
}
try {
- service.setSystemAudioCaptioningUiRequested(isEnabled, userId);
+ service.setSystemAudioCaptioningUiEnabled(isEnabled, userId);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index a31cacf..aeef76c 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -23,8 +23,10 @@
import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.AccessibilityServiceInfo;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ClipData;
@@ -62,6 +64,8 @@
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.Preconditions;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -128,23 +132,99 @@
public static final long LEASHED_NODE_ID = makeNodeId(LEASHED_ITEM_ID,
AccessibilityNodeProvider.HOST_VIEW_ID);
- /** @hide */
- public static final int FLAG_PREFETCH_PREDECESSORS = 0x00000001;
+ /**
+ * Prefetching strategy that prefetches the ancestors of the requested node.
+ * <p> Ancestors will be prefetched before siblings and descendants.
+ *
+ * @see #getChild(int, int)
+ * @see #getParent(int)
+ * @see AccessibilityWindowInfo#getRoot(int)
+ * @see AccessibilityService#getRootInActiveWindow(int)
+ * @see AccessibilityEvent#getSource(int)
+ */
+ public static final int FLAG_PREFETCH_ANCESTORS = 0x00000001;
- /** @hide */
+ /**
+ * Prefetching strategy that prefetches the siblings of the requested node.
+ * <p> To avoid disconnected trees, this flag will also prefetch the parent. Siblings will be
+ * prefetched before descendants.
+ *
+ * @see #FLAG_PREFETCH_ANCESTORS for where to use these flags.
+ */
public static final int FLAG_PREFETCH_SIBLINGS = 0x00000002;
- /** @hide */
- public static final int FLAG_PREFETCH_DESCENDANTS = 0x00000004;
+ /**
+ * Prefetching strategy that prefetches the descendants in a hybrid depth first and breadth
+ * first approach.
+ * <p> The children of the root node is prefetched before recursing on the children. This
+ * must not be combined with {@link #FLAG_PREFETCH_DESCENDANTS_DEPTH_FIRST} or
+ * {@link #FLAG_PREFETCH_DESCENDANTS_BREADTH_FIRST} or this will trigger an
+ * IllegalArgumentException.
+ *
+ * @see #FLAG_PREFETCH_ANCESTORS for where to use these flags.
+ */
+ public static final int FLAG_PREFETCH_DESCENDANTS_HYBRID = 0x00000004;
+
+ /**
+ * Prefetching strategy that prefetches the descendants of the requested node depth-first.
+ * <p> This must not be combined with {@link #FLAG_PREFETCH_DESCENDANTS_HYBRID} or
+ * {@link #FLAG_PREFETCH_DESCENDANTS_BREADTH_FIRST} or this will trigger an
+ * IllegalArgumentException.
+ *
+ * @see #FLAG_PREFETCH_ANCESTORS for where to use these flags.
+ */
+ public static final int FLAG_PREFETCH_DESCENDANTS_DEPTH_FIRST = 0x00000008;
+
+ /**
+ * Prefetching strategy that prefetches the descendants of the requested node breadth-first.
+ * <p> This must not be combined with {@link #FLAG_PREFETCH_DESCENDANTS_HYBRID} or
+ * {@link #FLAG_PREFETCH_DESCENDANTS_DEPTH_FIRST} or this will trigger an
+ * IllegalArgumentException.
+ *
+ * @see #FLAG_PREFETCH_ANCESTORS for where to use these flags.
+ */
+ public static final int FLAG_PREFETCH_DESCENDANTS_BREADTH_FIRST = 0x00000010;
+
+ /**
+ * Prefetching flag that specifies prefetching should not be interrupted by a request to
+ * retrieve a node or perform an action on a node.
+ *
+ * @see #FLAG_PREFETCH_ANCESTORS for where to use these flags.
+ */
+ public static final int FLAG_PREFETCH_UNINTERRUPTIBLE = 0x00000020;
/** @hide */
- public static final int FLAG_PREFETCH_MASK = 0x00000007;
+ public static final int FLAG_PREFETCH_MASK = 0x0000003f;
/** @hide */
- public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x00000008;
+ public static final int FLAG_PREFETCH_DESCENDANTS_MASK = 0x0000001C;
+
+ /**
+ * Maximum batch size of prefetched nodes for a request.
+ */
+ @SuppressLint("MinMaxConstant")
+ public static final int MAX_NUMBER_OF_PREFETCHED_NODES = 50;
/** @hide */
- public static final int FLAG_REPORT_VIEW_IDS = 0x00000010;
+ @IntDef(flag = true, prefix = { "FLAG_PREFETCH" }, value = {
+ FLAG_PREFETCH_ANCESTORS,
+ FLAG_PREFETCH_SIBLINGS,
+ FLAG_PREFETCH_DESCENDANTS_HYBRID,
+ FLAG_PREFETCH_DESCENDANTS_DEPTH_FIRST,
+ FLAG_PREFETCH_DESCENDANTS_BREADTH_FIRST,
+ FLAG_PREFETCH_UNINTERRUPTIBLE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PrefetchingStrategy {}
+
+ /** @hide */
+ public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x00000080;
+
+ /** @hide */
+ public static final int FLAG_REPORT_VIEW_IDS = 0x00000100;
+
+ /** @hide */
+ public static final int FLAG_REPORT_MASK = 0x00000180;
// Actions.
@@ -1079,11 +1159,6 @@
/**
* Get the child at given index.
- * <p>
- * <strong>Note:</strong> It is a client responsibility to recycle the
- * received info by calling {@link AccessibilityNodeInfo#recycle()}
- * to avoid creating of multiple instances.
- * </p>
*
* @param index The child index.
* @return The child node.
@@ -1092,6 +1167,23 @@
*
*/
public AccessibilityNodeInfo getChild(int index) {
+ return getChild(index, FLAG_PREFETCH_DESCENDANTS_HYBRID);
+ }
+
+
+ /**
+ * Get the child at given index.
+ *
+ * @param index The child index.
+ * @param prefetchingStrategy the prefetching strategy.
+ * @return The child node.
+ *
+ * @throws IllegalStateException If called outside of an AccessibilityService.
+ *
+ * @see AccessibilityNodeInfo#getParent(int) for a description of prefetching.
+ */
+ @Nullable
+ public AccessibilityNodeInfo getChild(int index, @PrefetchingStrategy int prefetchingStrategy) {
enforceSealed();
if (mChildNodeIds == null) {
return null;
@@ -1103,11 +1195,11 @@
final AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
if (mLeashedChild != null && childId == LEASHED_NODE_ID) {
return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, mLeashedChild,
- ROOT_NODE_ID, false, FLAG_PREFETCH_DESCENDANTS, null);
+ ROOT_NODE_ID, false, prefetchingStrategy, null);
}
return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, mWindowId,
- childId, false, FLAG_PREFETCH_DESCENDANTS, null);
+ childId, false, prefetchingStrategy, null);
}
/**
@@ -1816,23 +1908,56 @@
/**
* Gets the parent.
- * <p>
- * <strong>Note:</strong> It is a client responsibility to recycle the
- * received info by calling {@link AccessibilityNodeInfo#recycle()}
- * to avoid creating of multiple instances.
- * </p>
*
* @return The parent.
*/
public AccessibilityNodeInfo getParent() {
enforceSealed();
if (mLeashedParent != null && mLeashedParentNodeId != UNDEFINED_NODE_ID) {
- return getNodeForAccessibilityId(mConnectionId, mLeashedParent, mLeashedParentNodeId);
+ return getNodeForAccessibilityId(mConnectionId, mLeashedParent, mLeashedParentNodeId,
+ FLAG_PREFETCH_ANCESTORS | FLAG_PREFETCH_SIBLINGS);
}
return getNodeForAccessibilityId(mConnectionId, mWindowId, mParentNodeId);
}
/**
+ * Gets the parent.
+ *
+ * <p>
+ * Use {@code prefetchingStrategy} to determine the types of
+ * nodes prefetched from the app if the requested node is not in the cache and must be retrieved
+ * by the app. The default strategy for {@link #getParent()} is a combination of ancestor and
+ * sibling strategies. The app will prefetch until all nodes fulfilling the strategies are
+ * fetched, another node request is sent, or the maximum prefetch batch size of
+ * {@link #MAX_NUMBER_OF_PREFETCHED_NODES} nodes is reached. To prevent interruption by another
+ * request and to force prefetching of the max batch size, use
+ * {@link AccessibilityNodeInfo#FLAG_PREFETCH_UNINTERRUPTIBLE}.
+ * </p>
+ *
+ * @param prefetchingStrategy the prefetching strategy.
+ * @return The parent.
+ *
+ * @throws IllegalStateException If called outside of an AccessibilityService.
+ *
+ * @see #FLAG_PREFETCH_ANCESTORS
+ * @see #FLAG_PREFETCH_DESCENDANTS_BREADTH_FIRST
+ * @see #FLAG_PREFETCH_DESCENDANTS_DEPTH_FIRST
+ * @see #FLAG_PREFETCH_DESCENDANTS_HYBRID
+ * @see #FLAG_PREFETCH_SIBLINGS
+ * @see #FLAG_PREFETCH_UNINTERRUPTIBLE
+ */
+ @Nullable
+ public AccessibilityNodeInfo getParent(@PrefetchingStrategy int prefetchingStrategy) {
+ enforceSealed();
+ if (mLeashedParent != null && mLeashedParentNodeId != UNDEFINED_NODE_ID) {
+ return getNodeForAccessibilityId(mConnectionId, mLeashedParent, mLeashedParentNodeId,
+ prefetchingStrategy);
+ }
+ return getNodeForAccessibilityId(mConnectionId, mWindowId, mParentNodeId,
+ prefetchingStrategy);
+ }
+
+ /**
* @return The parent node id.
*
* @hide
@@ -4507,17 +4632,31 @@
private static AccessibilityNodeInfo getNodeForAccessibilityId(int connectionId,
int windowId, long accessibilityId) {
+ return getNodeForAccessibilityId(connectionId, windowId, accessibilityId,
+ FLAG_PREFETCH_ANCESTORS
+ | FLAG_PREFETCH_DESCENDANTS_HYBRID | FLAG_PREFETCH_SIBLINGS);
+ }
+
+ private static AccessibilityNodeInfo getNodeForAccessibilityId(int connectionId,
+ int windowId, long accessibilityId, @PrefetchingStrategy int prefetchingStrategy) {
if (!canPerformRequestOverConnection(connectionId, windowId, accessibilityId)) {
return null;
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
return client.findAccessibilityNodeInfoByAccessibilityId(connectionId,
- windowId, accessibilityId, false, FLAG_PREFETCH_PREDECESSORS
- | FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS, null);
+ windowId, accessibilityId, false, prefetchingStrategy, null);
}
private static AccessibilityNodeInfo getNodeForAccessibilityId(int connectionId,
IBinder leashToken, long accessibilityId) {
+ return getNodeForAccessibilityId(connectionId, leashToken, accessibilityId,
+ FLAG_PREFETCH_ANCESTORS
+ | FLAG_PREFETCH_DESCENDANTS_HYBRID | FLAG_PREFETCH_SIBLINGS);
+ }
+
+ private static AccessibilityNodeInfo getNodeForAccessibilityId(int connectionId,
+ IBinder leashToken, long accessibilityId,
+ @PrefetchingStrategy int prefetchingStrategy) {
if (!((leashToken != null)
&& (getAccessibilityViewId(accessibilityId) != UNDEFINED_ITEM_ID)
&& (connectionId != UNDEFINED_CONNECTION_ID))) {
@@ -4525,8 +4664,7 @@
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
return client.findAccessibilityNodeInfoByAccessibilityId(connectionId,
- leashToken, accessibilityId, false, FLAG_PREFETCH_PREDECESSORS
- | FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS, null);
+ leashToken, accessibilityId, false, prefetchingStrategy, null);
}
/** @hide */
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index cf2ea15..036316e 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -74,10 +74,9 @@
private static final int PROPERTY_IMPORTANT_FOR_ACCESSIBILITY = 0x00000200;
private static final int GET_SOURCE_PREFETCH_FLAGS =
- AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS
- | AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS
- | AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS;
-
+ AccessibilityNodeInfo.FLAG_PREFETCH_ANCESTORS
+ | AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS
+ | AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS_HYBRID;
@UnsupportedAppUsage
boolean mSealed;
@@ -185,16 +184,30 @@
* @return The info of the source.
*/
public @Nullable AccessibilityNodeInfo getSource() {
+ return getSource(GET_SOURCE_PREFETCH_FLAGS);
+ }
+
+ /**
+ * Gets the {@link AccessibilityNodeInfo} of the event source.
+ *
+ * @param prefetchingStrategy the prefetching strategy.
+ * @return The info of the source.
+ *
+ * @see AccessibilityNodeInfo#getParent(int) for a description of prefetching.
+ */
+ @Nullable
+ public AccessibilityNodeInfo getSource(
+ @AccessibilityNodeInfo.PrefetchingStrategy int prefetchingStrategy) {
enforceSealed();
if ((mConnectionId == UNDEFINED)
|| (mSourceWindowId == AccessibilityWindowInfo.UNDEFINED_WINDOW_ID)
|| (AccessibilityNodeInfo.getAccessibilityViewId(mSourceNodeId)
- == AccessibilityNodeInfo.UNDEFINED_ITEM_ID)) {
+ == AccessibilityNodeInfo.UNDEFINED_ITEM_ID)) {
return null;
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, mSourceWindowId,
- mSourceNodeId, false, GET_SOURCE_PREFETCH_FLAGS, null);
+ mSourceNodeId, false, prefetchingStrategy, null);
}
/**
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index 540f5dc..f155bad 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -219,13 +219,27 @@
* @return The root node.
*/
public AccessibilityNodeInfo getRoot() {
+ return getRoot(AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS_HYBRID);
+ }
+
+ /**
+ * Gets the root node in the window's hierarchy.
+ *
+ * @param prefetchingStrategy the prefetching strategy.
+ * @return The root node.
+ *
+ * @see AccessibilityNodeInfo#getParent(int) for a description of prefetching.
+ */
+ @Nullable
+ public AccessibilityNodeInfo getRoot(
+ @AccessibilityNodeInfo.PrefetchingStrategy int prefetchingStrategy) {
if (mConnectionId == UNDEFINED_WINDOW_ID) {
return null;
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
mId, AccessibilityNodeInfo.ROOT_NODE_ID,
- true, AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS, null);
+ true, prefetchingStrategy, null);
}
/**
@@ -382,6 +396,14 @@
* Gets if this window is active. An active window is the one
* the user is currently touching or the window has input focus
* and the user is not touching any window.
+ * <p>
+ * This is defined as the window that most recently fired one
+ * of the following events:
+ * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED},
+ * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER},
+ * {@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT}.
+ * In other words, the last window shown that also has input focus.
+ * </p>
*
* @return Whether this is the active window.
*/
diff --git a/core/java/android/view/accessibility/CaptioningManager.java b/core/java/android/view/accessibility/CaptioningManager.java
index 4f9781b..e960bec 100644
--- a/core/java/android/view/accessibility/CaptioningManager.java
+++ b/core/java/android/view/accessibility/CaptioningManager.java
@@ -152,7 +152,7 @@
/**
* @return the system audio caption enabled state.
*/
- public final boolean isSystemAudioCaptioningRequested() {
+ public final boolean isSystemAudioCaptioningEnabled() {
return Secure.getIntForUser(mContentResolver, Secure.ODI_CAPTIONS_ENABLED,
SYSTEM_AUDIO_CAPTIONING_DEFAULT_ENABLED ? 1 : 0, mContext.getUserId()) == 1;
}
@@ -169,9 +169,9 @@
*/
@SystemApi
@RequiresPermission(Manifest.permission.SET_SYSTEM_AUDIO_CAPTION)
- public final void setSystemAudioCaptioningRequested(boolean isEnabled) {
+ public final void setSystemAudioCaptioningEnabled(boolean isEnabled) {
if (mAccessibilityManager != null) {
- mAccessibilityManager.setSystemAudioCaptioningRequested(isEnabled,
+ mAccessibilityManager.setSystemAudioCaptioningEnabled(isEnabled,
mContext.getUserId());
}
}
@@ -179,9 +179,9 @@
/**
* @return the system audio caption UI enabled state.
*/
- public final boolean isSystemAudioCaptioningUiRequested() {
+ public final boolean isSystemAudioCaptioningUiEnabled() {
return mAccessibilityManager != null
- && mAccessibilityManager.isSystemAudioCaptioningUiRequested(mContext.getUserId());
+ && mAccessibilityManager.isSystemAudioCaptioningUiEnabled(mContext.getUserId());
}
/**
@@ -196,9 +196,9 @@
*/
@SystemApi
@RequiresPermission(Manifest.permission.SET_SYSTEM_AUDIO_CAPTION)
- public final void setSystemAudioCaptioningUiRequested(boolean isEnabled) {
+ public final void setSystemAudioCaptioningUiEnabled(boolean isEnabled) {
if (mAccessibilityManager != null) {
- mAccessibilityManager.setSystemAudioCaptioningUiRequested(isEnabled,
+ mAccessibilityManager.setSystemAudioCaptioningUiEnabled(isEnabled,
mContext.getUserId());
}
}
@@ -300,7 +300,7 @@
}
private void notifySystemAudioCaptionChanged() {
- final boolean enabled = isSystemAudioCaptioningRequested();
+ final boolean enabled = isSystemAudioCaptioningEnabled();
synchronized (mListeners) {
for (CaptioningChangeListener listener : mListeners) {
listener.onSystemAudioCaptioningChanged(enabled);
@@ -309,7 +309,7 @@
}
private void notifySystemAudioCaptionUiChanged() {
- final boolean enabled = isSystemAudioCaptioningUiRequested();
+ final boolean enabled = isSystemAudioCaptioningUiEnabled();
synchronized (mListeners) {
for (CaptioningChangeListener listener : mListeners) {
listener.onSystemAudioCaptioningUiChanged(enabled);
@@ -686,7 +686,7 @@
* @param isEnabled The system audio captioning enabled state.
* @param userId The user Id.
*/
- void setSystemAudioCaptioningRequested(boolean isEnabled, int userId);
+ void setSystemAudioCaptioningEnabled(boolean isEnabled, int userId);
/**
* Gets the system audio caption UI enabled state.
@@ -694,7 +694,7 @@
* @param userId The user Id.
* @return the system audio caption UI enabled state.
*/
- boolean isSystemAudioCaptioningUiRequested(int userId);
+ boolean isSystemAudioCaptioningUiEnabled(int userId);
/**
* Sets the system audio caption UI enabled state.
@@ -702,6 +702,6 @@
* @param isEnabled The system audio captioning UI enabled state.
* @param userId The user Id.
*/
- void setSystemAudioCaptioningUiRequested(boolean isEnabled, int userId);
+ void setSystemAudioCaptioningUiEnabled(boolean isEnabled, int userId);
}
}
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 645ddf5..418132a 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -101,13 +101,11 @@
boolean isAudioDescriptionByDefaultEnabled();
- // Requires Manifest.permission.SET_SYSTEM_AUDIO_CAPTION
- // System process only
- void setSystemAudioCaptioningRequested(boolean isEnabled, int userId);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.SET_SYSTEM_AUDIO_CAPTION)")
+ void setSystemAudioCaptioningEnabled(boolean isEnabled, int userId);
- boolean isSystemAudioCaptioningUiRequested(int userId);
+ boolean isSystemAudioCaptioningUiEnabled(int userId);
- // Requires Manifest.permission.SET_SYSTEM_AUDIO_CAPTION
- // System process only
- void setSystemAudioCaptioningUiRequested(boolean isEnabled, int userId);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.SET_SYSTEM_AUDIO_CAPTION)")
+ void setSystemAudioCaptioningUiEnabled(boolean isEnabled, int userId);
}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 60ccf67..b7994db 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -3100,11 +3100,51 @@
}
/**
- * Checks the id of autofill whether supported the fill dialog.
+ * If autofill suggestions for a dialog-style UI are available for {@code view}, shows a dialog
+ * allowing the user to select a suggestion and returns {@code true}.
+ * <p>
+ * The dialog may not be available if the autofill service does not support it, or if the
+ * autofill request has not returned a response yet.
+ * <p>
+ * It is recommended to call this method the first time a user focuses on an autofill-able form,
+ * and to avoid showing the input method if the dialog is shown. If this method returns
+ * {@code false}, you should then instead show the input method (assuming that is how the
+ * view normally handles the focus event). If the user re-focuses on the view, you should not
+ * call this method again so as to not disrupt usage of the input method.
*
- * @hide
+ * @param view the view for which to show autofill suggestions. This is typically a view
+ * receiving a focus event. The autofill suggestions shown will include content for
+ * related views as well.
+ * @return {@code true} if the autofill dialog is being shown
*/
- public boolean isShowFillDialog(AutofillId id) {
+ // TODO(b/210926084): Consider whether to include the one-time show logic within this method.
+ public boolean showAutofillDialog(@NonNull View view) {
+ Objects.requireNonNull(view);
+ if (shouldShowAutofillDialog(view.getAutofillId())) {
+ // If the id matches a trigger id, this will trigger the fill dialog.
+ notifyViewEntered(view);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Like {@link #showAutofillDialog(View)} but for virtual views.
+ *
+ * @param virtualId id identifying the virtual child inside the parent view.
+ */
+ // TODO(b/210926084): Consider whether to include the one-time show logic within this method.
+ public boolean showAutofillDialog(@NonNull View view, int virtualId) {
+ Objects.requireNonNull(view);
+ if (shouldShowAutofillDialog(getAutofillId(view, virtualId))) {
+ // If the id matches a trigger id, this will trigger the fill dialog.
+ notifyViewEntered(view, virtualId, /* bounds= */ null, /* flags= */ 0);
+ return true;
+ }
+ return false;
+ }
+
+ private boolean shouldShowAutofillDialog(AutofillId id) {
if (!hasFillDialogUiFeature() || mFillDialogTriggerIds == null) {
return false;
}
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 7e6e6fd..9a70667 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -278,6 +278,7 @@
.InputMethod_Subtype_subtypeId, 0 /* use Arrays.hashCode */))
.setIsAsciiCapable(a.getBoolean(com.android.internal.R.styleable
.InputMethod_Subtype_isAsciiCapable, false)).build();
+ a.recycle();
if (!subtype.isAuxiliary()) {
isAuxIme = false;
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index f480b24..2359d8d 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -115,6 +115,7 @@
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
/**
* Central system API to the overall input method framework (IMF) architecture,
@@ -426,6 +427,8 @@
int mCursorSelEnd;
int mCursorCandStart;
int mCursorCandEnd;
+ int mInitialSelStart;
+ int mInitialSelEnd;
/**
* The instance that has previously been sent to the input method.
@@ -468,6 +471,13 @@
@Nullable
@GuardedBy("mH")
private InputMethodSessionWrapper mCurrentInputMethodSession = null;
+ /**
+ * Encapsulates IPCs to the currently connected AccessibilityServices.
+ */
+ @Nullable
+ @GuardedBy("mH")
+ private final SparseArray<InputMethodSessionWrapper> mAccessibilityInputMethodSession =
+ new SparseArray<>();
InputChannel mCurChannel;
ImeInputEventSender mCurSender;
@@ -499,6 +509,8 @@
static final int MSG_TIMEOUT_INPUT_EVENT = 6;
static final int MSG_FLUSH_INPUT_EVENT = 7;
static final int MSG_REPORT_FULLSCREEN_MODE = 10;
+ static final int MSG_BIND_ACCESSIBILITY_SERVICE = 11;
+ static final int MSG_UNBIND_ACCESSIBILITY_SERVICE = 12;
private static boolean isAutofillUIShowing(View servedView) {
AutofillManager afm = servedView.getContext().getSystemService(AutofillManager.class);
@@ -626,6 +638,7 @@
if (mCurrentInputMethodSession != null) {
mCurrentInputMethodSession.finishInput();
}
+ forAccessibilitySessions(InputMethodSessionWrapper::finishInput);
}
}
@@ -881,6 +894,7 @@
if (mBindSequence != sequence) {
return;
}
+ clearAllAccessibilityBindingLocked();
clearBindingLocked();
// If we were actively using the last input method, then
// we would like to re-connect to the next input method.
@@ -896,6 +910,73 @@
}
return;
}
+ case MSG_BIND_ACCESSIBILITY_SERVICE: {
+ final int id = msg.arg1;
+ final InputBindResult res = (InputBindResult) msg.obj;
+ if (DEBUG) {
+ Log.i(TAG, "handleMessage: MSG_BIND_ACCESSIBILITY " + res.sequence
+ + "," + res.id);
+ }
+ synchronized (mH) {
+ if (mBindSequence < 0 || mBindSequence != res.sequence) {
+ Log.w(TAG, "Ignoring onBind: cur seq=" + mBindSequence
+ + ", given seq=" + res.sequence);
+ if (res.channel != null && res.channel != mCurChannel) {
+ res.channel.dispose();
+ }
+ return;
+ }
+
+ // Since IMM can start inputting text before a11y sessions are back,
+ // we send a notification so that the a11y service knows the session is
+ // registered and update the a11y service with the current cursor positions.
+ if (res.accessibilitySessions != null) {
+ InputMethodSessionWrapper wrapper =
+ InputMethodSessionWrapper.createOrNull(
+ res.accessibilitySessions.get(id));
+ if (wrapper != null) {
+ mAccessibilityInputMethodSession.put(id, wrapper);
+ if (mServedInputConnection != null) {
+ wrapper.updateSelection(mInitialSelStart, mInitialSelEnd,
+ mCursorSelStart, mCursorSelEnd, mCursorCandStart,
+ mCursorCandEnd);
+ } else {
+ // If an a11y service binds before input starts, we should still
+ // send a notification because the a11y service doesn't know it
+ // binds before or after input starts, it may wonder if it binds
+ // after input starts, why it doesn't receive a notification of
+ // the current cursor positions.
+ wrapper.updateSelection(-1, -1,
+ -1, -1, -1,
+ -1);
+ }
+ }
+ }
+ mBindSequence = res.sequence;
+ }
+ startInputInner(StartInputReason.BOUND_ACCESSIBILITY_SESSION_TO_IMMS, null,
+ 0, 0, 0);
+ return;
+ }
+ case MSG_UNBIND_ACCESSIBILITY_SERVICE: {
+ final int sequence = msg.arg1;
+ final int id = msg.arg2;
+ if (DEBUG) {
+ Log.i(TAG, "handleMessage: MSG_UNBIND_ACCESSIBILITY_SERVICE "
+ + sequence + " id=" + id);
+ }
+ synchronized (mH) {
+ if (mBindSequence != sequence) {
+ if (DEBUG) {
+ Log.i(TAG, "mBindSequence =" + mBindSequence + " sequence ="
+ + sequence + " id=" + id);
+ }
+ return;
+ }
+ clearAccessibilityBindingLocked(id);
+ }
+ return;
+ }
case MSG_SET_ACTIVE: {
final boolean active = msg.arg1 != 0;
final boolean fullscreen = msg.arg2 != 0;
@@ -996,11 +1077,21 @@
}
@Override
+ public void onBindAccessibilityService(InputBindResult res, int id) {
+ mH.obtainMessage(MSG_BIND_ACCESSIBILITY_SERVICE, id, 0, res).sendToTarget();
+ }
+
+ @Override
public void onUnbindMethod(int sequence, @UnbindReason int unbindReason) {
mH.obtainMessage(MSG_UNBIND, sequence, unbindReason).sendToTarget();
}
@Override
+ public void onUnbindAccessibilityService(int sequence, int id) {
+ mH.obtainMessage(MSG_UNBIND_ACCESSIBILITY_SERVICE, sequence, id).sendToTarget();
+ }
+
+ @Override
public void setActive(boolean active, boolean fullscreen, boolean reportToImeController) {
mH.obtainMessage(MSG_SET_ACTIVE, active ? 1 : 0, fullscreen ? 1 : 0,
reportToImeController).sendToTarget();
@@ -1420,16 +1511,36 @@
/**
* Reset all of the state associated with being bound to an input method.
*/
+ @GuardedBy("mH")
void clearBindingLocked() {
if (DEBUG) Log.v(TAG, "Clearing binding!");
clearConnectionLocked();
setInputChannelLocked(null);
+ // We only reset sequence number for input method, but not accessibility.
mBindSequence = -1;
mCurId = null;
mCurMethod = null; // for @UnsupportedAppUsage
mCurrentInputMethodSession = null;
}
+ /**
+ * Reset all of the state associated with being bound to an accessibility service.
+ */
+ @GuardedBy("mH")
+ void clearAccessibilityBindingLocked(int id) {
+ if (DEBUG) Log.v(TAG, "Clearing accessibility binding " + id);
+ mAccessibilityInputMethodSession.remove(id);
+ }
+
+ /**
+ * Reset all of the state associated with being bound to all ccessibility services.
+ */
+ @GuardedBy("mH")
+ void clearAllAccessibilityBindingLocked() {
+ if (DEBUG) Log.v(TAG, "Clearing all accessibility bindings");
+ mAccessibilityInputMethodSession.clear();
+ }
+
void setInputChannelLocked(InputChannel channel) {
if (mCurChannel == channel) {
return;
@@ -1653,7 +1764,7 @@
}
/**
- * This method is still kept for a while until android.support.v7.widget.SearchView ver. 26.0
+ * This method is still kept for a while until androidx.appcompat.widget.SearchView ver. 26.0
* is publicly released because previous implementations of that class had relied on this method
* via reflection.
*
@@ -1666,7 +1777,7 @@
synchronized (mH) {
try {
Log.w(TAG, "showSoftInputUnchecked() is a hidden method, which will be"
- + " removed soon. If you are using android.support.v7.widget.SearchView,"
+ + " removed soon. If you are using androidx.appcompat.widget.SearchView,"
+ " please update to version 26.0 or newer version.");
if (mCurRootView == null || mCurRootView.getView() == null) {
Log.w(TAG, "No current root view, ignoring showSoftInputUnchecked()");
@@ -1938,6 +2049,8 @@
editorInfo.setInitialSurroundingTextInternal(textSnapshot.getSurroundingText());
mCurrentInputMethodSession.invalidateInput(editorInfo, mServedInputConnection,
sessionId);
+ forAccessibilitySessions(wrapper -> wrapper.invalidateInput(editorInfo,
+ mServedInputConnection, sessionId));
}
}
@@ -2080,6 +2193,8 @@
if (ic != null) {
mCursorSelStart = tba.initialSelStart;
mCursorSelEnd = tba.initialSelEnd;
+ mInitialSelStart = mCursorSelStart;
+ mInitialSelEnd = mCursorSelEnd;
mCursorCandStart = -1;
mCursorCandEnd = -1;
mCursorRect.setEmpty();
@@ -2128,6 +2243,17 @@
mBindSequence = res.sequence;
mCurMethod = res.method; // for @UnsupportedAppUsage
mCurrentInputMethodSession = InputMethodSessionWrapper.createOrNull(res.method);
+ mAccessibilityInputMethodSession.clear();
+ if (res.accessibilitySessions != null) {
+ for (int i = 0; i < res.accessibilitySessions.size(); i++) {
+ InputMethodSessionWrapper wrapper = InputMethodSessionWrapper.createOrNull(
+ res.accessibilitySessions.valueAt(i));
+ if (wrapper != null) {
+ mAccessibilityInputMethodSession.append(
+ res.accessibilitySessions.keyAt(i), wrapper);
+ }
+ }
+ }
mCurId = res.id;
} else if (res.channel != null && res.channel != mCurChannel) {
res.channel.dispose();
@@ -2137,8 +2263,10 @@
mRestartOnNextWindowFocus = true;
break;
}
- if (mCurrentInputMethodSession != null && mCompletions != null) {
- mCurrentInputMethodSession.displayCompletions(mCompletions);
+ if (mCompletions != null) {
+ if (mCurrentInputMethodSession != null) {
+ mCurrentInputMethodSession.displayCompletions(mCompletions);
+ }
}
}
@@ -2369,6 +2497,8 @@
mCursorCandEnd = candidatesEnd;
mCurrentInputMethodSession.updateSelection(
oldSelStart, oldSelEnd, selStart, selEnd, candidatesStart, candidatesEnd);
+ forAccessibilitySessions(wrapper -> wrapper.updateSelection(oldSelStart,
+ oldSelEnd, selStart, selEnd, candidatesStart, candidatesEnd));
}
}
}
@@ -3233,6 +3363,11 @@
} else {
p.println(" mCurMethod= null");
}
+ for (int i = 0; i < mAccessibilityInputMethodSession.size(); i++) {
+ p.println(" mAccessibilityInputMethodSession("
+ + mAccessibilityInputMethodSession.keyAt(i) + ")="
+ + mAccessibilityInputMethodSession.valueAt(i));
+ }
p.println(" mCurRootView=" + mCurRootView);
p.println(" mServedView=" + getServedViewLocked());
p.println(" mNextServedView=" + getNextServedViewLocked());
@@ -3377,4 +3512,10 @@
}
}
}
+
+ private void forAccessibilitySessions(Consumer<InputMethodSessionWrapper> consumer) {
+ for (int i = 0; i < mAccessibilityInputMethodSession.size(); i++) {
+ consumer.accept(mAccessibilityInputMethodSession.valueAt(i));
+ }
+ }
}
diff --git a/core/java/android/view/textservice/SpellCheckerInfo.java b/core/java/android/view/textservice/SpellCheckerInfo.java
index 13d44da..edcbce9 100644
--- a/core/java/android/view/textservice/SpellCheckerInfo.java
+++ b/core/java/android/view/textservice/SpellCheckerInfo.java
@@ -124,6 +124,7 @@
.SpellChecker_Subtype_subtypeExtraValue),
a.getInt(com.android.internal.R.styleable
.SpellChecker_Subtype_subtypeId, 0));
+ a.recycle();
mSubtypes.add(subtype);
}
}
diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java
index de9f76d..f554f89 100644
--- a/core/java/android/widget/ArrayAdapter.java
+++ b/core/java/android/widget/ArrayAdapter.java
@@ -61,7 +61,7 @@
* </p>
* <p class="note"><strong>Note:</strong>
* If you are considering using array adapter with a ListView, consider using
- * {@link android.support.v7.widget.RecyclerView} instead.
+ * {@link androidx.recyclerview.widget.RecyclerView} instead.
* RecyclerView offers similar features with better performance and more flexibility than
* ListView provides.
* See the
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index ec07209..1bde235 100755
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -209,6 +209,7 @@
// Generate a non-activated color using the disabled alpha.
final TypedArray ta = mContext.obtainStyledAttributes(ATTRS_DISABLED_ALPHA);
final float disabledAlpha = ta.getFloat(0, 0.30f);
+ ta.recycle();
defaultColor = multiplyAlphaComponent(activatedColor, disabledAlpha);
}
diff --git a/core/java/android/widget/EditText.java b/core/java/android/widget/EditText.java
index 2c61280..9c0900b 100644
--- a/core/java/android/widget/EditText.java
+++ b/core/java/android/widget/EditText.java
@@ -17,6 +17,7 @@
package android.widget;
import android.content.Context;
+import android.graphics.Rect;
import android.text.Editable;
import android.text.Selection;
import android.text.Spannable;
@@ -173,6 +174,12 @@
return EditText.class.getName();
}
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ setHandwritingArea(new Rect(0, 0, w, h));
+ }
+
/** @hide */
@Override
protected boolean supportsAutoSizeText() {
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index d969a88..b2bc0764 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -57,7 +57,7 @@
* @attr ref android.R.styleable#Gallery_gravity
*
* @deprecated This widget is no longer supported. Other horizontally scrolling
- * widgets include {@link HorizontalScrollView} and {@link android.support.v4.view.ViewPager}
+ * widgets include {@link HorizontalScrollView} and {@link androidx.viewpager.widget.ViewPager}
* from the support library.
*/
@Deprecated
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 3ad7b46..15cd17b 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -63,12 +63,12 @@
* <p>Scroll view supports vertical scrolling only. For horizontal scrolling,
* use {@link HorizontalScrollView} instead.</p>
*
- * <p>Never add a {@link android.support.v7.widget.RecyclerView} or {@link ListView} to
+ * <p>Never add a {@link androidx.recyclerview.widget.RecyclerView} or {@link ListView} to
* a scroll view. Doing so results in poor user interface performance and a poor user
* experience.</p>
*
* <p class="note">
- * For vertical scrolling, consider {@link android.support.v4.widget.NestedScrollView}
+ * For vertical scrolling, consider {@link androidx.core.widget.NestedScrollView}
* instead of scroll view which offers greater user interface flexibility and
* support for the material design scrolling patterns.</p>
*
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index d3600ef..872e65a 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -72,7 +72,7 @@
* {@link #setSwitchTextAppearance(android.content.Context, int) switchTextAppearance} and
* the related setSwitchTypeface() methods control that of the thumb.
*
- * <p>{@link android.support.v7.widget.SwitchCompat} is a version of
+ * <p>{@link androidx.recyclerview.widget.RecyclerView} is a version of
* the Switch widget which runs on devices back to API 7.</p>
*
* <p>See the <a href="{@docRoot}guide/topics/ui/controls/togglebutton.html">Toggle Buttons</a>
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 9efa583..3dfb4a5 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -5081,7 +5081,7 @@
*
* @param color A color value in the form 0xAARRGGBB.
* Do not pass a resource ID. To get a color value from a resource ID, call
- * {@link android.support.v4.content.ContextCompat#getColor(Context, int) getColor}.
+ * {@link androidx.core.content.ContextCompat#getColor(Context, int) getColor}.
*
* @see #setTextColor(ColorStateList)
* @see #getTextColors()
@@ -12295,7 +12295,7 @@
EXTRA_DATA_RENDERING_INFO_KEY,
EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY
));
- info.setTextSelectable(isTextSelectable());
+ info.setTextSelectable(isTextSelectable() || isTextEditable());
} else {
info.setAvailableExtraData(Arrays.asList(
EXTRA_DATA_RENDERING_INFO_KEY
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index dc9a585..a453c28 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -373,6 +373,7 @@
// Generate a non-activated color using the disabled alpha.
final TypedArray ta = mContext.obtainStyledAttributes(ATTRS_DISABLED_ALPHA);
final float disabledAlpha = ta.getFloat(0, 0.30f);
+ ta.recycle();
defaultColor = multiplyAlphaComponent(activatedColor, disabledAlpha);
}
diff --git a/core/java/android/app/ambientcontext/AmbientContextEventResponse.aidl b/core/java/android/window/BackEvent.aidl
similarity index 80%
copy from core/java/android/app/ambientcontext/AmbientContextEventResponse.aidl
copy to core/java/android/window/BackEvent.aidl
index 4dc6466..821f1fa 100644
--- a/core/java/android/app/ambientcontext/AmbientContextEventResponse.aidl
+++ b/core/java/android/window/BackEvent.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 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,9 @@
* limitations under the License.
*/
-package android.app.ambientcontext;
+package android.window;
-parcelable AmbientContextEventResponse;
\ No newline at end of file
+/**
+ * @hide
+ */
+parcelable BackEvent;
diff --git a/core/java/android/window/BackEvent.java b/core/java/android/window/BackEvent.java
new file mode 100644
index 0000000..14985c9
--- /dev/null
+++ b/core/java/android/window/BackEvent.java
@@ -0,0 +1,159 @@
+/*
+ * 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.window;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.view.RemoteAnimationTarget;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Represents an event that is sent out by the system during back navigation gesture.
+ * Holds information about the touch event, swipe direction and overall progress of the gesture
+ * interaction.
+ *
+ * @hide
+ */
+public class BackEvent implements Parcelable {
+ /** Indicates that the edge swipe starts from the left edge of the screen */
+ public static final int EDGE_LEFT = 0;
+ /** Indicates that the edge swipe starts from the right edge of the screen */
+ public static final int EDGE_RIGHT = 1;
+
+ @IntDef({
+ EDGE_LEFT,
+ EDGE_RIGHT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SwipeEdge{}
+
+ private final int mTouchX;
+ private final int mTouchY;
+ private final float mProgress;
+
+ @SwipeEdge
+ private final int mSwipeEdge;
+ @Nullable
+ private final RemoteAnimationTarget mDepartingAnimationTarget;
+
+ /**
+ * Creates a new {@link BackEvent} instance.
+ *
+ * @param touchX Absolute X location of the touch point.
+ * @param touchY Absolute Y location of the touch point.
+ * @param progress Value between 0 and 1 on how far along the back gesture is.
+ * @param swipeEdge Indicates which edge the swipe starts from.
+ * @param departingAnimationTarget The remote animation target of the departing application
+ * window.
+ */
+ public BackEvent(int touchX, int touchY, float progress, @SwipeEdge int swipeEdge,
+ @Nullable RemoteAnimationTarget departingAnimationTarget) {
+ mTouchX = touchX;
+ mTouchY = touchY;
+ mProgress = progress;
+ mSwipeEdge = swipeEdge;
+ mDepartingAnimationTarget = departingAnimationTarget;
+ }
+
+ private BackEvent(@NonNull Parcel in) {
+ mTouchX = in.readInt();
+ mTouchY = in.readInt();
+ mProgress = in.readFloat();
+ mSwipeEdge = in.readInt();
+ mDepartingAnimationTarget = in.readTypedObject(RemoteAnimationTarget.CREATOR);
+ }
+
+ public static final Creator<BackEvent> CREATOR = new Creator<BackEvent>() {
+ @Override
+ public BackEvent createFromParcel(Parcel in) {
+ return new BackEvent(in);
+ }
+
+ @Override
+ public BackEvent[] newArray(int size) {
+ return new BackEvent[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mTouchX);
+ dest.writeInt(mTouchY);
+ dest.writeFloat(mProgress);
+ dest.writeInt(mSwipeEdge);
+ dest.writeTypedObject(mDepartingAnimationTarget, flags);
+ }
+
+ /**
+ * Returns a value between 0 and 1 on how far along the back gesture is.
+ */
+ public float getProgress() {
+ return mProgress;
+ }
+
+ /**
+ * Returns the absolute X location of the touch point.
+ */
+ public int getTouchX() {
+ return mTouchX;
+ }
+
+ /**
+ * Returns the absolute Y location of the touch point.
+ */
+ public int getTouchY() {
+ return mTouchY;
+ }
+
+ /**
+ * Returns the screen edge that the swipe starts from.
+ */
+ public int getSwipeEdge() {
+ return mSwipeEdge;
+ }
+
+ /**
+ * Returns the {@link RemoteAnimationTarget} of the top departing application window,
+ * or {@code null} if the top window should not be moved for the current type of back
+ * destination.
+ */
+ @Nullable
+ public RemoteAnimationTarget getDepartingAnimationTarget() {
+ return mDepartingAnimationTarget;
+ }
+
+ @Override
+ public String toString() {
+ return "BackEvent{"
+ + "mTouchX=" + mTouchX
+ + ", mTouchY=" + mTouchY
+ + ", mProgress=" + mProgress
+ + ", mSwipeEdge" + mSwipeEdge
+ + ", mDepartingAnimationTarget" + mDepartingAnimationTarget
+ + "}";
+ }
+}
diff --git a/core/java/android/window/BackNavigationInfo.java b/core/java/android/window/BackNavigationInfo.java
index 18c20e2..1e922d9 100644
--- a/core/java/android/window/BackNavigationInfo.java
+++ b/core/java/android/window/BackNavigationInfo.java
@@ -21,9 +21,11 @@
import android.annotation.Nullable;
import android.app.WindowConfiguration;
import android.hardware.HardwareBuffer;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteCallback;
+import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
/**
@@ -65,6 +67,12 @@
public static final int TYPE_CALLBACK = 4;
/**
+ * Key to access the boolean value passed in {#mOnBackNavigationDone} result bundle
+ * that represents if back navigation has been triggered.
+ */
+ public static final String KEY_TRIGGER_BACK = "TriggerBack";
+
+ /**
* Defines the type of back destinations a back even can lead to. This is used to define the
* type of animation that need to be run on SystemUI.
*/
@@ -79,13 +87,13 @@
private final int mType;
@Nullable
- private final SurfaceControl mDepartingWindowContainer;
+ private final RemoteAnimationTarget mDepartingAnimationTarget;
@Nullable
private final SurfaceControl mScreenshotSurface;
@Nullable
private final HardwareBuffer mScreenshotBuffer;
@Nullable
- private final RemoteCallback mRemoteCallback;
+ private final RemoteCallback mOnBackNavigationDone;
@Nullable
private final WindowConfiguration mTaskWindowConfiguration;
@Nullable
@@ -96,8 +104,9 @@
*
* @param type The {@link BackTargetType} of the destination (what will be
* displayed after the back action).
- * @param topWindowLeash The leash to animate away the current topWindow. The consumer
- * of the leash is responsible for removing it.
+ * @param departingAnimationTarget The remote animation target, containing a leash to animate
+ * away the departing window. The consumer of the leash is
+ * responsible for removing it.
* @param screenshotSurface The screenshot of the previous activity to be displayed.
* @param screenshotBuffer A buffer containing a screenshot used to display the activity.
* See {@link #getScreenshotHardwareBuffer()} for information
@@ -108,39 +117,39 @@
* @param onBackInvokedCallback The back callback registered by the current top level window.
*/
public BackNavigationInfo(@BackTargetType int type,
- @Nullable SurfaceControl topWindowLeash,
+ @Nullable RemoteAnimationTarget departingAnimationTarget,
@Nullable SurfaceControl screenshotSurface,
@Nullable HardwareBuffer screenshotBuffer,
@Nullable WindowConfiguration taskWindowConfiguration,
- @Nullable RemoteCallback onBackNavigationDone,
- @Nullable IOnBackInvokedCallback onBackInvokedCallback) {
+ @NonNull RemoteCallback onBackNavigationDone,
+ @NonNull IOnBackInvokedCallback onBackInvokedCallback) {
mType = type;
- mDepartingWindowContainer = topWindowLeash;
+ mDepartingAnimationTarget = departingAnimationTarget;
mScreenshotSurface = screenshotSurface;
mScreenshotBuffer = screenshotBuffer;
mTaskWindowConfiguration = taskWindowConfiguration;
- mRemoteCallback = onBackNavigationDone;
+ mOnBackNavigationDone = onBackNavigationDone;
mOnBackInvokedCallback = onBackInvokedCallback;
}
private BackNavigationInfo(@NonNull Parcel in) {
mType = in.readInt();
- mDepartingWindowContainer = in.readTypedObject(SurfaceControl.CREATOR);
+ mDepartingAnimationTarget = in.readTypedObject(RemoteAnimationTarget.CREATOR);
mScreenshotSurface = in.readTypedObject(SurfaceControl.CREATOR);
mScreenshotBuffer = in.readTypedObject(HardwareBuffer.CREATOR);
mTaskWindowConfiguration = in.readTypedObject(WindowConfiguration.CREATOR);
- mRemoteCallback = in.readTypedObject(RemoteCallback.CREATOR);
+ mOnBackNavigationDone = in.readTypedObject(RemoteCallback.CREATOR);
mOnBackInvokedCallback = IOnBackInvokedCallback.Stub.asInterface(in.readStrongBinder());
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mType);
- dest.writeTypedObject(mDepartingWindowContainer, flags);
+ dest.writeTypedObject(mDepartingAnimationTarget, flags);
dest.writeTypedObject(mScreenshotSurface, flags);
dest.writeTypedObject(mScreenshotBuffer, flags);
dest.writeTypedObject(mTaskWindowConfiguration, flags);
- dest.writeTypedObject(mRemoteCallback, flags);
+ dest.writeTypedObject(mOnBackNavigationDone, flags);
dest.writeStrongInterface(mOnBackInvokedCallback);
}
@@ -154,12 +163,13 @@
}
/**
- * Returns a leash to the top window container that needs to be animated. This can be null if
- * the back animation is controlled by the application.
+ * Returns a {@link RemoteAnimationTarget}, containing a leash to the top window container
+ * that needs to be animated. This can be null if the back animation is controlled by
+ * the application.
*/
@Nullable
- public SurfaceControl getDepartingWindowContainer() {
- return mDepartingWindowContainer;
+ public RemoteAnimationTarget getDepartingAnimationTarget() {
+ return mDepartingAnimationTarget;
}
/**
@@ -212,10 +222,14 @@
/**
* Callback to be called when the back preview is finished in order to notify the server that
* it can clean up the resources created for the animation.
+ *
+ * @param triggerBack Boolean indicating if back navigation has been triggered.
*/
- public void onBackNavigationFinished() {
- if (mRemoteCallback != null) {
- mRemoteCallback.sendResult(null);
+ public void onBackNavigationFinished(boolean triggerBack) {
+ if (mOnBackNavigationDone != null) {
+ Bundle result = new Bundle();
+ result.putBoolean(KEY_TRIGGER_BACK, triggerBack);
+ mOnBackNavigationDone.sendResult(result);
}
}
@@ -240,11 +254,11 @@
public String toString() {
return "BackNavigationInfo{"
+ "mType=" + typeToString(mType) + " (" + mType + ")"
- + ", mDepartingWindowContainer=" + mDepartingWindowContainer
+ + ", mDepartingAnimationTarget=" + mDepartingAnimationTarget
+ ", mScreenshotSurface=" + mScreenshotSurface
+ ", mTaskWindowConfiguration= " + mTaskWindowConfiguration
+ ", mScreenshotBuffer=" + mScreenshotBuffer
- + ", mRemoteCallback=" + mRemoteCallback
+ + ", mOnBackNavigationDone=" + mOnBackNavigationDone
+ ", mOnBackInvokedCallback=" + mOnBackInvokedCallback
+ '}';
}
diff --git a/core/java/android/window/IOnBackInvokedCallback.aidl b/core/java/android/window/IOnBackInvokedCallback.aidl
index a42863c..47796de 100644
--- a/core/java/android/window/IOnBackInvokedCallback.aidl
+++ b/core/java/android/window/IOnBackInvokedCallback.aidl
@@ -17,6 +17,8 @@
package android.window;
+import android.window.BackEvent;
+
/**
* Interface that wraps a {@link OnBackInvokedCallback} object, to be stored in window manager
* and called from back handling process when back is invoked.
@@ -38,7 +40,7 @@
* @param touchY Absolute Y location of the touch point.
* @param progress Value between 0 and 1 on how far along the back gesture is.
*/
- void onBackProgressed(int touchX, int touchY, float progress);
+ void onBackProgressed(in BackEvent backEvent);
/**
* Called when a back gesture or back button press has been cancelled.
diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java
index b90e628..34a3418 100644
--- a/core/java/android/window/SplashScreenView.java
+++ b/core/java/android/window/SplashScreenView.java
@@ -493,7 +493,7 @@
Log.d(TAG, "Transferring surface " + mSurfaceView.toString());
}
- mSurfaceView.setChildSurfacePackageOnDraw(mSurfacePackage);
+ mSurfaceView.setChildSurfacePackage(mSurfacePackage);
}
void initIconAnimation(Drawable iconDrawable, long duration) {
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index d37d3b4..62292f9 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -55,10 +55,6 @@
private static final boolean IS_BACK_PREDICTABILITY_ENABLED = SystemProperties
.getInt(BACK_PREDICTABILITY_PROP, 0) > 0;
- /** The currently most prioritized callback. */
- @Nullable
- private OnBackInvokedCallbackWrapper mTopCallback;
-
/** Convenience hashmap to quickly decide if a callback has been added. */
private final HashMap<OnBackInvokedCallback, Integer> mAllCallbacks = new HashMap<>();
/** Holds all callbacks by priorities. */
@@ -72,8 +68,8 @@
public void attachToWindow(@NonNull IWindowSession windowSession, @NonNull IWindow window) {
mWindowSession = windowSession;
mWindow = window;
- if (mTopCallback != null) {
- setTopOnBackInvokedCallback(mTopCallback);
+ if (!mAllCallbacks.isEmpty()) {
+ setTopOnBackInvokedCallback(getTopCallback());
}
}
@@ -81,6 +77,7 @@
public void detachFromWindow() {
mWindow = null;
mWindowSession = null;
+ clear();
}
// TODO: Take an Executor for the callback to run on.
@@ -110,11 +107,13 @@
mOnBackInvokedCallbacks.get(prevPriority).remove(callback);
}
+ OnBackInvokedCallback previousTopCallback = getTopCallback();
callbacks.add(callback);
mAllCallbacks.put(callback, priority);
- if (mTopCallback == null || (mTopCallback.getCallback() != callback
- && mAllCallbacks.get(mTopCallback.getCallback()) <= priority)) {
- setTopOnBackInvokedCallback(new OnBackInvokedCallbackWrapper(callback, priority));
+ if (previousTopCallback == null
+ || (previousTopCallback != callback
+ && mAllCallbacks.get(previousTopCallback) <= priority)) {
+ setTopOnBackInvokedCallback(callback);
}
}
@@ -126,11 +125,17 @@
}
return;
}
+ OnBackInvokedCallback previousTopCallback = getTopCallback();
Integer priority = mAllCallbacks.get(callback);
- mOnBackInvokedCallbacks.get(priority).remove(callback);
+ ArrayList<OnBackInvokedCallback> callbacks = mOnBackInvokedCallbacks.get(priority);
+ callbacks.remove(callback);
+ if (callbacks.isEmpty()) {
+ mOnBackInvokedCallbacks.remove(priority);
+ }
mAllCallbacks.remove(callback);
- if (mTopCallback != null && mTopCallback.getCallback() == callback) {
- findAndSetTopOnBackInvokedCallback();
+ // Re-populate the top callback to WM if the removed callback was previously the top one.
+ if (previousTopCallback == callback) {
+ setTopOnBackInvokedCallback(getTopCallback());
}
}
@@ -141,41 +146,26 @@
/** Clears all registered callbacks on the instance. */
public void clear() {
+ if (!mAllCallbacks.isEmpty()) {
+ // Clear binder references in WM.
+ setTopOnBackInvokedCallback(null);
+ }
mAllCallbacks.clear();
- mTopCallback = null;
mOnBackInvokedCallbacks.clear();
}
- /**
- * Iterates through all callbacks to find the most prioritized one and pushes it to
- * window manager.
- */
- private void findAndSetTopOnBackInvokedCallback() {
- if (mAllCallbacks.isEmpty()) {
- setTopOnBackInvokedCallback(null);
- return;
- }
-
- for (Integer priority : mOnBackInvokedCallbacks.descendingKeySet()) {
- ArrayList<OnBackInvokedCallback> callbacks = mOnBackInvokedCallbacks.get(priority);
- if (!callbacks.isEmpty()) {
- OnBackInvokedCallbackWrapper callback = new OnBackInvokedCallbackWrapper(
- callbacks.get(callbacks.size() - 1), priority);
- setTopOnBackInvokedCallback(callback);
- return;
- }
- }
- setTopOnBackInvokedCallback(null);
- }
-
- // Pushes the top priority callback to window manager.
- private void setTopOnBackInvokedCallback(@Nullable OnBackInvokedCallbackWrapper callback) {
- mTopCallback = callback;
+ private void setTopOnBackInvokedCallback(@Nullable OnBackInvokedCallback callback) {
if (mWindowSession == null || mWindow == null) {
return;
}
try {
- mWindowSession.setOnBackInvokedCallback(mWindow, mTopCallback);
+ if (callback == null) {
+ mWindowSession.setOnBackInvokedCallback(mWindow, null, PRIORITY_DEFAULT);
+ } else {
+ int priority = mAllCallbacks.get(callback);
+ mWindowSession.setOnBackInvokedCallback(
+ mWindow, new OnBackInvokedCallbackWrapper(callback, priority), priority);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Failed to set OnBackInvokedCallback to WM. Error: " + e);
}
@@ -202,9 +192,9 @@
}
@Override
- public void onBackProgressed(int touchX, int touchY, float progress)
+ public void onBackProgressed(BackEvent backEvent)
throws RemoteException {
- Handler.getMain().post(() -> mCallback.onBackProgressed(touchX, touchY, progress));
+ Handler.getMain().post(() -> mCallback.onBackProgressed(backEvent));
}
@Override
@@ -220,7 +210,16 @@
@Override
public OnBackInvokedCallback getTopCallback() {
- return mTopCallback == null ? null : mTopCallback.getCallback();
+ if (mAllCallbacks.isEmpty()) {
+ return null;
+ }
+ for (Integer priority : mOnBackInvokedCallbacks.descendingKeySet()) {
+ ArrayList<OnBackInvokedCallback> callbacks = mOnBackInvokedCallbacks.get(priority);
+ if (!callbacks.isEmpty()) {
+ return callbacks.get(callbacks.size() - 1);
+ }
+ }
+ return null;
}
/**
diff --git a/core/java/com/android/internal/inputmethod/InputBindResult.java b/core/java/com/android/internal/inputmethod/InputBindResult.java
index 1357bac..e838401 100644
--- a/core/java/com/android/internal/inputmethod/InputBindResult.java
+++ b/core/java/com/android/internal/inputmethod/InputBindResult.java
@@ -25,6 +25,7 @@
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.SparseArray;
import android.view.InputChannel;
import com.android.internal.view.IInputMethodSession;
@@ -53,7 +54,8 @@
ResultCode.ERROR_NOT_IME_TARGET_WINDOW,
ResultCode.ERROR_NO_EDITOR,
ResultCode.ERROR_DISPLAY_ID_MISMATCH,
- ResultCode.ERROR_INVALID_DISPLAY_ID
+ ResultCode.ERROR_INVALID_DISPLAY_ID,
+ ResultCode.SUCCESS_WITH_ACCESSIBILITY_SESSION
})
public @interface ResultCode {
/**
@@ -168,6 +170,7 @@
* display.
*/
int ERROR_INVALID_DISPLAY_ID = 15;
+ int SUCCESS_WITH_ACCESSIBILITY_SESSION = 16;
}
@ResultCode
@@ -179,6 +182,11 @@
public final IInputMethodSession method;
/**
+ * The accessibility services.
+ */
+ public SparseArray<IInputMethodSession> accessibilitySessions;
+
+ /**
* The input channel used to send input events to this IME.
*/
public final InputChannel channel;
@@ -204,6 +212,8 @@
*
* @param result A result code defined in {@link ResultCode}.
* @param method {@link IInputMethodSession} to interact with the IME.
+ * @param accessibilitySessions {@link IInputMethodSession} to interact with accessibility
+ * services.
* @param channel {@link InputChannel} to forward input events to the IME.
* @param id The {@link String} representations of the IME, which is the same as
* {@link android.view.inputmethod.InputMethodInfo#getId()} and
@@ -213,10 +223,12 @@
* {@code suppressesSpellChecker="true"}.
*/
public InputBindResult(@ResultCode int result,
- IInputMethodSession method, InputChannel channel, String id, int sequence,
+ IInputMethodSession method, SparseArray<IInputMethodSession> accessibilitySessions,
+ InputChannel channel, String id, int sequence,
boolean isInputMethodSuppressingSpellChecker) {
this.result = result;
this.method = method;
+ this.accessibilitySessions = accessibilitySessions;
this.channel = channel;
this.id = id;
this.sequence = sequence;
@@ -226,6 +238,19 @@
private InputBindResult(Parcel source) {
result = source.readInt();
method = IInputMethodSession.Stub.asInterface(source.readStrongBinder());
+ int n = source.readInt();
+ if (n < 0) {
+ accessibilitySessions = null;
+ } else {
+ accessibilitySessions = new SparseArray<>(n);
+ while (n > 0) {
+ int key = source.readInt();
+ IInputMethodSession value =
+ IInputMethodSession.Stub.asInterface(source.readStrongBinder());
+ accessibilitySessions.append(key, value);
+ n--;
+ }
+ }
if (source.readInt() != 0) {
channel = InputChannel.CREATOR.createFromParcel(source);
} else {
@@ -254,6 +279,18 @@
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(result);
dest.writeStrongInterface(method);
+ if (accessibilitySessions == null) {
+ dest.writeInt(-1);
+ } else {
+ int n = accessibilitySessions.size();
+ dest.writeInt(n);
+ int i = 0;
+ while (i < n) {
+ dest.writeInt(accessibilitySessions.keyAt(i));
+ dest.writeStrongInterface(accessibilitySessions.valueAt(i));
+ i++;
+ }
+ }
if (channel != null) {
dest.writeInt(1);
channel.writeToParcel(dest, flags);
@@ -329,7 +366,7 @@
}
private static InputBindResult error(@ResultCode int result) {
- return new InputBindResult(result, null, null, null, -1, false);
+ return new InputBindResult(result, null, null, null, null, -1, false);
}
/**
diff --git a/core/java/com/android/internal/inputmethod/InputMethodDebug.java b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
index bf094db..d669768 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodDebug.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
@@ -64,6 +64,8 @@
return "DEACTIVATED_BY_IMMS";
case StartInputReason.SESSION_CREATED_BY_IME:
return "SESSION_CREATED_BY_IME";
+ case StartInputReason.BOUND_ACCESSIBILITY_SESSION_TO_IMMS:
+ return "BOUND_ACCESSIBILITY_SESSION_TO_IMMS";
default:
return "Unknown=" + reason;
}
@@ -91,6 +93,8 @@
return "SWITCH_IME_FAILED";
case UnbindReason.SWITCH_USER:
return "SWITCH_USER";
+ case UnbindReason.ACCESSIBILITY_SERVICE_DISABLED:
+ return "ACCESSIBILITY_SERVICE_DISABLED";
default:
return "Unknown=" + reason;
}
diff --git a/core/java/com/android/internal/inputmethod/StartInputReason.java b/core/java/com/android/internal/inputmethod/StartInputReason.java
index 2ba708d..1263466 100644
--- a/core/java/com/android/internal/inputmethod/StartInputReason.java
+++ b/core/java/com/android/internal/inputmethod/StartInputReason.java
@@ -38,7 +38,9 @@
StartInputReason.UNBOUND_FROM_IMMS,
StartInputReason.ACTIVATED_BY_IMMS,
StartInputReason.DEACTIVATED_BY_IMMS,
- StartInputReason.SESSION_CREATED_BY_IME})
+ StartInputReason.SESSION_CREATED_BY_IME,
+ StartInputReason.SESSION_CREATED_BY_ACCESSIBILITY,
+ StartInputReason.BOUND_ACCESSIBILITY_SESSION_TO_IMMS})
public @interface StartInputReason {
/**
* Reason is not specified.
@@ -96,4 +98,14 @@
* {@link com.android.internal.view.IInputSessionCallback#sessionCreated}.
*/
int SESSION_CREATED_BY_IME = 10;
+ /**
+ * {@link android.accessibilityservice.AccessibilityService} is responding to
+ * {@link com.android.internal.view.IInputSessionWithIdCallback#sessionCreated}.
+ */
+ int SESSION_CREATED_BY_ACCESSIBILITY = 11;
+ /**
+ * {@link android.view.inputmethod.InputMethodManager} is responding to
+ * {@link com.android.internal.view.IInputMethodClient#onBindAccessibilityService(InputBindResult, int)}.
+ */
+ int BOUND_ACCESSIBILITY_SESSION_TO_IMMS = 12;
}
diff --git a/core/java/com/android/internal/inputmethod/UnbindReason.java b/core/java/com/android/internal/inputmethod/UnbindReason.java
index f0f18f1..e926625 100644
--- a/core/java/com/android/internal/inputmethod/UnbindReason.java
+++ b/core/java/com/android/internal/inputmethod/UnbindReason.java
@@ -34,7 +34,9 @@
UnbindReason.DISCONNECT_IME,
UnbindReason.NO_IME,
UnbindReason.SWITCH_IME_FAILED,
- UnbindReason.SWITCH_USER})
+ UnbindReason.SWITCH_USER,
+ UnbindReason.ACCESSIBILITY_SERVICE_DISABLED
+})
public @interface UnbindReason {
/**
* Reason is not specified.
@@ -66,4 +68,5 @@
* user's active IME.
*/
int SWITCH_USER = 6;
+ int ACCESSIBILITY_SERVICE_DISABLED = 7;
}
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index 7b6df6c..e58f4f0 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -22,7 +22,6 @@
import android.view.View;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.util.FrameworkStatsLog;
/**
* Writes sysui_multi_event records to the system event log.
@@ -53,10 +52,7 @@
}
protected void saveLog(LogMaker log) {
- // TODO(b/116684537): Flag guard logging to event log and statsd socket.
EventLogTags.writeSysuiMultiAction(log.serialize());
- FrameworkStatsLog.write(FrameworkStatsLog.KEY_VALUE_PAIRS_ATOM,
- /* UID is retrieved from statsd side */ 0, log.getEntries());
}
public static final int VIEW_UNKNOWN = MetricsEvent.VIEW_UNKNOWN;
diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java
index b579be0..ec95baa 100644
--- a/core/java/com/android/internal/net/VpnConfig.java
+++ b/core/java/com/android/internal/net/VpnConfig.java
@@ -105,6 +105,7 @@
public boolean allowIPv4;
public boolean allowIPv6;
public boolean isMetered = true;
+ public boolean requiresInternetValidation = false;
public Network[] underlyingNetworks;
public ProxyInfo proxyInfo;
@@ -131,6 +132,7 @@
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 @@
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 @@
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, android.net.ProxyInfo.class);
return config;
@@ -248,6 +252,8 @@
.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 519faa8..576860d 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 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 @@
areAuthParamsInline = in.readBoolean();
isRestrictedToTestNetworks = in.readBoolean();
excludeLocalRoutes = in.readBoolean();
+ requiresInternetValidation = in.readBoolean();
}
/**
@@ -239,6 +243,7 @@
out.writeBoolean(areAuthParamsInline);
out.writeBoolean(isRestrictedToTestNetworks);
out.writeBoolean(excludeLocalRoutes);
+ out.writeBoolean(requiresInternetValidation);
}
/**
@@ -258,9 +263,11 @@
// 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 @@
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 @@
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 @@
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 @@
&& 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/AmbientDisplayPowerCalculator.java b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java
index d8e89b4..888f830 100644
--- a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java
+++ b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java
@@ -22,10 +22,6 @@
import android.os.BatteryStats;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
-import android.os.UserHandle;
-import android.util.SparseArray;
-
-import java.util.List;
/**
* Estimates power consumed by the ambient display
@@ -67,29 +63,6 @@
powerMah, powerModel);
}
- /**
- * Ambient display power is the additional power the screen takes while in ambient display/
- * screen doze/ always-on display (interchangeable terms) mode. Ambient display power should
- * be hidden {@link BatteryStatsHelper#shouldHideSipper(BatterySipper)}, but should not be
- * included in smearing {@link BatteryStatsHelper#removeHiddenBatterySippers(List)}.
- */
- @Override
- public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
- long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
- final long measuredEnergyUC = batteryStats.getScreenDozeMeasuredBatteryConsumptionUC();
- final long durationMs = calculateDuration(batteryStats, rawRealtimeUs, statsType);
- final int powerModel = getPowerModel(measuredEnergyUC);
- final double powerMah = calculateTotalPower(powerModel, batteryStats, rawRealtimeUs,
- measuredEnergyUC);
- if (powerMah > 0) {
- BatterySipper bs = new BatterySipper(BatterySipper.DrainType.AMBIENT_DISPLAY, null, 0);
- bs.usagePowerMah = powerMah;
- bs.usageTimeMs = durationMs;
- bs.sumPower();
- sippers.add(bs);
- }
- }
-
private long calculateDuration(BatteryStats batteryStats, long rawRealtimeUs, int statsType) {
return batteryStats.getScreenDozeTime(rawRealtimeUs, statsType) / 1000;
}
diff --git a/core/java/com/android/internal/os/BatteryChargeCalculator.java b/core/java/com/android/internal/os/BatteryChargeCalculator.java
index 71a1463..912ec8f 100644
--- a/core/java/com/android/internal/os/BatteryChargeCalculator.java
+++ b/core/java/com/android/internal/os/BatteryChargeCalculator.java
@@ -20,10 +20,6 @@
import android.os.BatteryStats;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
-import android.os.UserHandle;
-import android.util.SparseArray;
-
-import java.util.List;
/**
* Estimates the battery discharge amounts.
@@ -81,10 +77,4 @@
BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)
.setConsumedPower(dischargeMah);
}
-
- @Override
- public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
- long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
- // Not implemented. The computation is done by BatteryStatsHelper
- }
}
diff --git a/core/java/com/android/internal/os/BatterySipper.java b/core/java/com/android/internal/os/BatterySipper.java
deleted file mode 100644
index dfd561a..0000000
--- a/core/java/com/android/internal/os/BatterySipper.java
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * Copyright (C) 2009 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.internal.os;
-
-import android.compat.annotation.UnsupportedAppUsage;
-import android.os.BatteryStats.Uid;
-import android.os.Build;
-
-import java.util.List;
-
-/**
- * Contains power usage of an application, system service, or hardware type.
- *
- * @deprecated Please use BatteryStatsManager.getBatteryUsageStats instead.
- */
-@Deprecated
-public class BatterySipper implements Comparable<BatterySipper> {
- @UnsupportedAppUsage
- public int userId;
- @UnsupportedAppUsage
- public Uid uidObj;
- @UnsupportedAppUsage
- public DrainType drainType;
-
- /**
- * Smeared power from screen usage.
- * We split the screen usage power and smear them among apps, based on activity time.
- * The actual screen usage power may be measured or estimated, affecting the granularity and
- * accuracy of the smearing, but the smearing algorithm is essentially the same.
- */
- public double screenPowerMah;
-
- /**
- * Smeared power using proportional method.
- *
- * we smear power usage from hidden sippers to all apps proportionally.(except for screen usage)
- *
- * @see BatteryStatsHelper#shouldHideSipper(BatterySipper)
- * @see BatteryStatsHelper#removeHiddenBatterySippers(List)
- */
- public double proportionalSmearMah;
-
- /**
- * Total power that adding the smeared power.
- *
- * @see #sumPower()
- */
- public double totalSmearedPowerMah;
-
- /**
- * Total power before smearing
- */
- @UnsupportedAppUsage
- public double totalPowerMah;
-
- /**
- * Whether we should hide this sipper
- *
- * @see BatteryStatsHelper#shouldHideSipper(BatterySipper)
- */
- public boolean shouldHide;
-
- /**
- * Generic usage time in milliseconds.
- */
- @UnsupportedAppUsage
- public long usageTimeMs;
-
- /**
- * Generic power usage in mAh.
- */
- public double usagePowerMah;
-
- // Subsystem usage times.
- public long audioTimeMs;
- public long bluetoothRunningTimeMs;
- public long cameraTimeMs;
- @UnsupportedAppUsage
- public long cpuFgTimeMs;
- @UnsupportedAppUsage
- public long cpuTimeMs;
- public long flashlightTimeMs;
- @UnsupportedAppUsage
- public long gpsTimeMs;
- public long videoTimeMs;
- @UnsupportedAppUsage
- public long wakeLockTimeMs;
- @UnsupportedAppUsage
- public long wifiRunningTimeMs;
-
- public long mobileRxPackets;
- public long mobileTxPackets;
- public long mobileActive;
- public int mobileActiveCount;
- public double mobilemspp; // milliseconds per packet
- public long wifiRxPackets;
- public long wifiTxPackets;
- public long mobileRxBytes;
- public long mobileTxBytes;
- public long wifiRxBytes;
- public long wifiTxBytes;
- public long btRxBytes;
- public long btTxBytes;
- public double percent;
- public double noCoveragePercent;
- @UnsupportedAppUsage
- public String[] mPackages;
- @UnsupportedAppUsage
- public String packageWithHighestDrain;
-
- // Measured in mAh (milli-ampere per hour).
- // These are included when summed.
- public double audioPowerMah;
- public double bluetoothPowerMah;
- public double cameraPowerMah;
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public double cpuPowerMah;
- public double flashlightPowerMah;
- public double gpsPowerMah;
- public double mobileRadioPowerMah;
- public double sensorPowerMah;
- public double videoPowerMah;
- public double wakeLockPowerMah;
- public double wifiPowerMah;
- public double systemServiceCpuPowerMah;
- public double[] customMeasuredPowerMah;
-
- // Power that is re-attributed to other sippers. For example, for System Server
- // this represents the power attributed to apps requesting system services.
- // The value should be negative or zero.
- public double powerReattributedToOtherSippersMah;
-
- // Do not include this sipper in results because it is included
- // in an aggregate sipper.
- public boolean isAggregated;
-
- // ****************
- // This list must be kept current with atoms.proto (frameworks/base/cmds/statsd/src/atoms.proto)
- // so the ordinal values (and therefore the order) must never change.
- // ****************
- @UnsupportedAppUsage(implicitMember =
- "values()[Lcom/android/internal/os/BatterySipper$DrainType;")
- public enum DrainType {
- AMBIENT_DISPLAY,
- @UnsupportedAppUsage
- APP,
- BLUETOOTH,
- CAMERA,
- CELL,
- FLASHLIGHT,
- IDLE,
- MEMORY,
- OVERCOUNTED,
- PHONE,
- SCREEN,
- UNACCOUNTED,
- USER,
- WIFI,
- }
-
- @UnsupportedAppUsage
- public BatterySipper(DrainType drainType, Uid uid, double value) {
- this.totalPowerMah = value;
- this.drainType = drainType;
- uidObj = uid;
- }
-
- public void computeMobilemspp() {
- long packets = mobileRxPackets + mobileTxPackets;
- mobilemspp = packets > 0 ? (mobileActive / (double) packets) : 0;
- }
-
- @Override
- public int compareTo(BatterySipper other) {
- // Over-counted always goes to the bottom.
- if (drainType != other.drainType) {
- if (drainType == DrainType.OVERCOUNTED) {
- // This is "larger"
- return 1;
- } else if (other.drainType == DrainType.OVERCOUNTED) {
- return -1;
- }
- }
- // Return the flipped value because we want the items in descending order
- return Double.compare(other.totalPowerMah, totalPowerMah);
- }
-
- /**
- * Gets a list of packages associated with the current user
- */
- @UnsupportedAppUsage
- public String[] getPackages() {
- return mPackages;
- }
-
- @UnsupportedAppUsage
- public int getUid() {
- // Bail out if the current sipper is not an App sipper.
- if (uidObj == null) {
- return 0;
- }
- return uidObj.getUid();
- }
-
- /**
- * Add stats from other to this BatterySipper.
- */
- @UnsupportedAppUsage
- public void add(BatterySipper other) {
- totalPowerMah += other.totalPowerMah;
- usageTimeMs += other.usageTimeMs;
- usagePowerMah += other.usagePowerMah;
- audioTimeMs += other.audioTimeMs;
- cpuTimeMs += other.cpuTimeMs;
- gpsTimeMs += other.gpsTimeMs;
- wifiRunningTimeMs += other.wifiRunningTimeMs;
- cpuFgTimeMs += other.cpuFgTimeMs;
- videoTimeMs += other.videoTimeMs;
- wakeLockTimeMs += other.wakeLockTimeMs;
- cameraTimeMs += other.cameraTimeMs;
- flashlightTimeMs += other.flashlightTimeMs;
- bluetoothRunningTimeMs += other.bluetoothRunningTimeMs;
- mobileRxPackets += other.mobileRxPackets;
- mobileTxPackets += other.mobileTxPackets;
- mobileActive += other.mobileActive;
- mobileActiveCount += other.mobileActiveCount;
- wifiRxPackets += other.wifiRxPackets;
- wifiTxPackets += other.wifiTxPackets;
- mobileRxBytes += other.mobileRxBytes;
- mobileTxBytes += other.mobileTxBytes;
- wifiRxBytes += other.wifiRxBytes;
- wifiTxBytes += other.wifiTxBytes;
- btRxBytes += other.btRxBytes;
- btTxBytes += other.btTxBytes;
- audioPowerMah += other.audioPowerMah;
- wifiPowerMah += other.wifiPowerMah;
- gpsPowerMah += other.gpsPowerMah;
- cpuPowerMah += other.cpuPowerMah;
- sensorPowerMah += other.sensorPowerMah;
- mobileRadioPowerMah += other.mobileRadioPowerMah;
- wakeLockPowerMah += other.wakeLockPowerMah;
- cameraPowerMah += other.cameraPowerMah;
- flashlightPowerMah += other.flashlightPowerMah;
- bluetoothPowerMah += other.bluetoothPowerMah;
- screenPowerMah += other.screenPowerMah;
- videoPowerMah += other.videoPowerMah;
- proportionalSmearMah += other.proportionalSmearMah;
- totalSmearedPowerMah += other.totalSmearedPowerMah;
- systemServiceCpuPowerMah += other.systemServiceCpuPowerMah;
- if (other.customMeasuredPowerMah != null) {
- if (customMeasuredPowerMah == null) {
- customMeasuredPowerMah = new double[other.customMeasuredPowerMah.length];
- }
- if (customMeasuredPowerMah.length == other.customMeasuredPowerMah.length) {
- // This should always be true.
- for (int idx = 0; idx < other.customMeasuredPowerMah.length; idx++) {
- customMeasuredPowerMah[idx] += other.customMeasuredPowerMah[idx];
- }
- }
- }
- powerReattributedToOtherSippersMah += other.powerReattributedToOtherSippersMah;
- }
-
- /**
- * Sum all the powers and store the value into `value`.
- * Also sum the {@code smearedTotalPowerMah} by adding smeared powerMah.
- *
- * @return the sum of all the power in this BatterySipper.
- */
- public double sumPower() {
- totalPowerMah = usagePowerMah + wifiPowerMah + gpsPowerMah + cpuPowerMah +
- sensorPowerMah + mobileRadioPowerMah + wakeLockPowerMah + cameraPowerMah +
- flashlightPowerMah + bluetoothPowerMah + audioPowerMah + videoPowerMah
- + systemServiceCpuPowerMah;
- if (customMeasuredPowerMah != null) {
- for (int idx = 0; idx < customMeasuredPowerMah.length; idx++) {
- totalPowerMah += customMeasuredPowerMah[idx];
- }
- }
-
- // powerAttributedToOtherSippersMah is negative or zero
- totalPowerMah = totalPowerMah + powerReattributedToOtherSippersMah;
-
- totalSmearedPowerMah = totalPowerMah + screenPowerMah + proportionalSmearMah;
-
- return totalPowerMah;
- }
-}
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
deleted file mode 100644
index 4515a09..0000000
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ /dev/null
@@ -1,703 +0,0 @@
-/*
- * Copyright (C) 2009 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.internal.os;
-
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.hardware.SensorManager;
-import android.os.BatteryStats;
-import android.os.BatteryStats.Uid;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.MemoryFile;
-import android.os.Parcel;
-import android.os.ParcelFileDescriptor;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.SELinux;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.telephony.TelephonyManager;
-import android.util.ArrayMap;
-import android.util.Log;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.app.IBatteryStats;
-import com.android.internal.os.BatterySipper.DrainType;
-import com.android.internal.util.ArrayUtils;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * A helper class for retrieving the power usage information for all applications and services.
- *
- * The caller must initialize this class as soon as activity object is ready to use (for example, in
- * onAttach() for Fragment), call create() in onCreate() and call destroy() in onDestroy().
- *
- * @deprecated Please use BatteryStatsManager.getBatteryUsageStats instead.
- */
-@Deprecated
-public class BatteryStatsHelper {
- private static final boolean DEBUG = false;
-
- private static final String TAG = BatteryStatsHelper.class.getSimpleName();
-
- private static BatteryStats sStatsXfer;
- private static Intent sBatteryBroadcastXfer;
- private static ArrayMap<File, BatteryStats> sFileXfer = new ArrayMap<>();
-
- final private Context mContext;
- final private boolean mCollectBatteryBroadcast;
- final private boolean mWifiOnly;
-
- private List<PowerCalculator> mPowerCalculators;
-
- @UnsupportedAppUsage
- private IBatteryStats mBatteryInfo;
- private BatteryStats mStats;
- private Intent mBatteryBroadcast;
- @UnsupportedAppUsage
- private PowerProfile mPowerProfile;
-
- private String[] mSystemPackageArray;
- private String[] mServicepackageArray;
- private PackageManager mPackageManager;
-
- /**
- * List of apps using power.
- */
- @UnsupportedAppUsage
- private final List<BatterySipper> mUsageList = new ArrayList<>();
-
- private final List<BatterySipper> mMobilemsppList = new ArrayList<>();
-
- private int mStatsType = BatteryStats.STATS_SINCE_CHARGED;
-
- long mRawRealtimeUs;
- long mRawUptimeUs;
- long mBatteryRealtimeUs;
- long mBatteryUptimeUs;
- long mBatteryTimeRemainingUs;
- long mChargeTimeRemainingUs;
-
- private long mStatsPeriod = 0;
-
- // The largest entry by power.
- private double mMaxPower = 1;
-
- // The largest real entry by power (not undercounted or overcounted).
- private double mMaxRealPower = 1;
-
- // Total computed power.
- private double mComputedPower;
- private double mTotalPower;
- private double mMinDrainedPower;
- private double mMaxDrainedPower;
-
- public static boolean checkWifiOnly(Context context) {
- final TelephonyManager tm = context.getSystemService(TelephonyManager.class);
- if (tm == null) {
- return false;
- }
- return !tm.isDataCapable();
- }
-
- @UnsupportedAppUsage
- public BatteryStatsHelper(Context context) {
- this(context, true);
- }
-
- @UnsupportedAppUsage
- public BatteryStatsHelper(Context context, boolean collectBatteryBroadcast) {
- this(context, collectBatteryBroadcast, checkWifiOnly(context));
- }
-
- @UnsupportedAppUsage
- public BatteryStatsHelper(Context context, boolean collectBatteryBroadcast, boolean wifiOnly) {
- mContext = context;
- mCollectBatteryBroadcast = collectBatteryBroadcast;
- mWifiOnly = wifiOnly;
- mPackageManager = context.getPackageManager();
-
- final Resources resources = context.getResources();
- mSystemPackageArray = resources.getStringArray(
- com.android.internal.R.array.config_batteryPackageTypeSystem);
- mServicepackageArray = resources.getStringArray(
- com.android.internal.R.array.config_batteryPackageTypeService);
- }
-
- public void storeStatsHistoryInFile(String fname) {
- synchronized (sFileXfer) {
- File path = makeFilePath(mContext, fname);
- sFileXfer.put(path, this.getStats());
- FileOutputStream fout = null;
- try {
- fout = new FileOutputStream(path);
- Parcel hist = Parcel.obtain();
- getStats().writeToParcelWithoutUids(hist, 0);
- byte[] histData = hist.marshall();
- fout.write(histData);
- } catch (IOException e) {
- Log.w(TAG, "Unable to write history to file", e);
- } finally {
- if (fout != null) {
- try {
- fout.close();
- } catch (IOException e) {
- }
- }
- }
- }
- }
-
- public static BatteryStats statsFromFile(Context context, String fname) {
- synchronized (sFileXfer) {
- File path = makeFilePath(context, fname);
- BatteryStats stats = sFileXfer.get(path);
- if (stats != null) {
- return stats;
- }
- FileInputStream fin = null;
- try {
- fin = new FileInputStream(path);
- byte[] data = readFully(fin);
- Parcel parcel = Parcel.obtain();
- parcel.unmarshall(data, 0, data.length);
- parcel.setDataPosition(0);
- return com.android.internal.os.BatteryStatsImpl.CREATOR.createFromParcel(parcel);
- } catch (IOException e) {
- Log.w(TAG, "Unable to read history to file", e);
- } finally {
- if (fin != null) {
- try {
- fin.close();
- } catch (IOException e) {
- }
- }
- }
- }
- return getStats(IBatteryStats.Stub.asInterface(
- ServiceManager.getService(BatteryStats.SERVICE_NAME)), true);
- }
-
- @UnsupportedAppUsage
- public static void dropFile(Context context, String fname) {
- makeFilePath(context, fname).delete();
- }
-
- private static File makeFilePath(Context context, String fname) {
- return new File(context.getFilesDir(), fname);
- }
-
- /** Clears the current stats and forces recreating for future use. */
- @UnsupportedAppUsage
- public void clearStats() {
- mStats = null;
- }
-
- @UnsupportedAppUsage
- public BatteryStats getStats() {
- return getStats(true /* updateAll */);
- }
-
- /** Retrieves stats from BatteryService, optionally getting updated numbers */
- public BatteryStats getStats(boolean updateAll) {
- if (mStats == null) {
- load(updateAll);
- }
- return mStats;
- }
-
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public Intent getBatteryBroadcast() {
- if (mBatteryBroadcast == null && mCollectBatteryBroadcast) {
- load();
- }
- return mBatteryBroadcast;
- }
-
- public PowerProfile getPowerProfile() {
- return mPowerProfile;
- }
-
- public void create(BatteryStats stats) {
- mPowerProfile = new PowerProfile(mContext);
- mStats = stats;
- }
-
- @UnsupportedAppUsage
- public void create(Bundle icicle) {
- if (icicle != null) {
- mStats = sStatsXfer;
- mBatteryBroadcast = sBatteryBroadcastXfer;
- }
- mBatteryInfo = IBatteryStats.Stub.asInterface(
- ServiceManager.getService(BatteryStats.SERVICE_NAME));
- mPowerProfile = new PowerProfile(mContext);
- }
-
- @UnsupportedAppUsage
- public void storeState() {
- sStatsXfer = mStats;
- sBatteryBroadcastXfer = mBatteryBroadcast;
- }
-
- /**
- * Refreshes the power usage list.
- */
- @UnsupportedAppUsage
- public void refreshStats(int statsType, int asUser) {
- SparseArray<UserHandle> users = new SparseArray<>(1);
- users.put(asUser, new UserHandle(asUser));
- refreshStats(statsType, users);
- }
-
- /**
- * Refreshes the power usage list.
- */
- @UnsupportedAppUsage
- public void refreshStats(int statsType, List<UserHandle> asUsers) {
- final int n = asUsers.size();
- SparseArray<UserHandle> users = new SparseArray<>(n);
- for (int i = 0; i < n; ++i) {
- UserHandle userHandle = asUsers.get(i);
- users.put(userHandle.getIdentifier(), userHandle);
- }
- refreshStats(statsType, users);
- }
-
- /**
- * Refreshes the power usage list.
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public void refreshStats(int statsType, SparseArray<UserHandle> asUsers) {
- refreshStats(statsType, asUsers, SystemClock.elapsedRealtime() * 1000,
- SystemClock.uptimeMillis() * 1000);
- }
-
- public void refreshStats(int statsType, SparseArray<UserHandle> asUsers, long rawRealtimeUs,
- long rawUptimeUs) {
- if (statsType != BatteryStats.STATS_SINCE_CHARGED) {
- Log.w(TAG, "refreshStats called for statsType " + statsType + " but only "
- + "STATS_SINCE_CHARGED is supported. Using STATS_SINCE_CHARGED instead.");
- }
-
- // Initialize mStats if necessary.
- getStats();
-
- mMaxPower = 0;
- mMaxRealPower = 0;
- mComputedPower = 0;
- mTotalPower = 0;
-
- mUsageList.clear();
- mMobilemsppList.clear();
-
- if (mStats == null) {
- return;
- }
-
- if (mPowerCalculators == null) {
- mPowerCalculators = new ArrayList<>();
-
- // Power calculators are applied in the order of registration
- mPowerCalculators.add(new CpuPowerCalculator(mPowerProfile));
- mPowerCalculators.add(new MemoryPowerCalculator(mPowerProfile));
- mPowerCalculators.add(new WakelockPowerCalculator(mPowerProfile));
- if (!mWifiOnly) {
- mPowerCalculators.add(new MobileRadioPowerCalculator(mPowerProfile));
- }
- mPowerCalculators.add(new WifiPowerCalculator(mPowerProfile));
- mPowerCalculators.add(new BluetoothPowerCalculator(mPowerProfile));
- mPowerCalculators.add(new SensorPowerCalculator(
- mContext.getSystemService(SensorManager.class)));
- mPowerCalculators.add(new GnssPowerCalculator(mPowerProfile));
- mPowerCalculators.add(new CameraPowerCalculator(mPowerProfile));
- mPowerCalculators.add(new FlashlightPowerCalculator(mPowerProfile));
- mPowerCalculators.add(new MediaPowerCalculator(mPowerProfile));
- mPowerCalculators.add(new PhonePowerCalculator(mPowerProfile));
- mPowerCalculators.add(new ScreenPowerCalculator(mPowerProfile));
- mPowerCalculators.add(new AmbientDisplayPowerCalculator(mPowerProfile));
- mPowerCalculators.add(new SystemServicePowerCalculator(mPowerProfile));
- mPowerCalculators.add(new IdlePowerCalculator(mPowerProfile));
- mPowerCalculators.add(new CustomMeasuredPowerCalculator(mPowerProfile));
-
- mPowerCalculators.add(new UserPowerCalculator());
- }
-
- for (int i = 0, size = mPowerCalculators.size(); i < size; i++) {
- mPowerCalculators.get(i).reset();
- }
-
- mStatsType = statsType;
- mRawUptimeUs = rawUptimeUs;
- mRawRealtimeUs = rawRealtimeUs;
- mBatteryUptimeUs = mStats.getBatteryUptime(rawUptimeUs);
- mBatteryRealtimeUs = mStats.getBatteryRealtime(rawRealtimeUs);
- mBatteryTimeRemainingUs = mStats.computeBatteryTimeRemaining(rawRealtimeUs);
- mChargeTimeRemainingUs = mStats.computeChargeTimeRemaining(rawRealtimeUs);
- mStatsPeriod = mStats.computeBatteryRealtime(rawRealtimeUs, mStatsType);
-
- if (DEBUG) {
- Log.d(TAG, "Raw time: realtime=" + (rawRealtimeUs / 1000) + " uptime="
- + (rawUptimeUs / 1000));
- Log.d(TAG, "Battery time: realtime=" + (mBatteryRealtimeUs / 1000) + " uptime="
- + (mBatteryUptimeUs / 1000));
- Log.d(TAG, "Battery type time: realtime=" + (mStatsPeriod / 1000) + " uptime="
- + (mStats.computeBatteryUptime(rawRealtimeUs, mStatsType) / 1000));
- }
- mMinDrainedPower = (mStats.getLowDischargeAmountSinceCharge()
- * mPowerProfile.getBatteryCapacity()) / 100;
- mMaxDrainedPower = (mStats.getHighDischargeAmountSinceCharge()
- * mPowerProfile.getBatteryCapacity()) / 100;
-
- // Create list of (almost all) sippers, calculate their usage, and put them in mUsageList.
- processAppUsage(asUsers);
-
- Collections.sort(mUsageList);
-
- Collections.sort(mMobilemsppList,
- (lhs, rhs) -> Double.compare(rhs.mobilemspp, lhs.mobilemspp));
-
- // At this point, we've sorted the list so we are guaranteed the max values are at the top.
- // We have only added real powers so far.
- if (!mUsageList.isEmpty()) {
- mMaxRealPower = mMaxPower = mUsageList.get(0).totalPowerMah;
- final int usageListCount = mUsageList.size();
- for (int i = 0; i < usageListCount; i++) {
- mComputedPower += mUsageList.get(i).totalPowerMah;
- }
- }
-
- if (DEBUG) {
- Log.d(TAG, "Accuracy: total computed=" + PowerCalculator.formatCharge(mComputedPower)
- + ", min discharge=" + PowerCalculator.formatCharge(mMinDrainedPower)
- + ", max discharge=" + PowerCalculator.formatCharge(mMaxDrainedPower));
- }
-
- mTotalPower = mComputedPower;
- if (mStats.getLowDischargeAmountSinceCharge() > 1) {
- if (mMinDrainedPower > mComputedPower) {
- double amount = mMinDrainedPower - mComputedPower;
- mTotalPower = mMinDrainedPower;
- BatterySipper bs = new BatterySipper(DrainType.UNACCOUNTED, null, amount);
-
- // Insert the BatterySipper in its sorted position.
- int index = Collections.binarySearch(mUsageList, bs);
- if (index < 0) {
- index = -(index + 1);
- }
- mUsageList.add(index, bs);
- mMaxPower = Math.max(mMaxPower, amount);
- } else if (mMaxDrainedPower < mComputedPower) {
- double amount = mComputedPower - mMaxDrainedPower;
-
- // Insert the BatterySipper in its sorted position.
- BatterySipper bs = new BatterySipper(DrainType.OVERCOUNTED, null, amount);
- int index = Collections.binarySearch(mUsageList, bs);
- if (index < 0) {
- index = -(index + 1);
- }
- mUsageList.add(index, bs);
- mMaxPower = Math.max(mMaxPower, amount);
- }
- }
-
- // Smear it!
- final double hiddenPowerMah = removeHiddenBatterySippers(mUsageList);
- final double totalRemainingPower = getTotalPower() - hiddenPowerMah;
- if (Math.abs(totalRemainingPower) > 1e-3) {
- for (int i = 0, size = mUsageList.size(); i < size; i++) {
- final BatterySipper sipper = mUsageList.get(i);
- if (!sipper.shouldHide) {
- sipper.proportionalSmearMah = hiddenPowerMah
- * ((sipper.totalPowerMah + sipper.screenPowerMah)
- / totalRemainingPower);
- sipper.sumPower();
- }
- }
- }
- }
-
- private void processAppUsage(SparseArray<UserHandle> asUsers) {
- final SparseArray<? extends Uid> uidStats = mStats.getUidStats();
-
- final ArrayList<BatterySipper> sippers = new ArrayList<>(uidStats.size());
-
- for (int iu = 0, size = uidStats.size(); iu < size; iu++) {
- final Uid u = uidStats.valueAt(iu);
- sippers.add(new BatterySipper(DrainType.APP, u, 0));
- }
-
- for (int i = 0, size = mPowerCalculators.size(); i < size; i++) {
- final PowerCalculator calculator = mPowerCalculators.get(i);
- calculator.calculate(sippers, mStats, mRawRealtimeUs, mRawUptimeUs, mStatsType,
- asUsers);
- }
-
- for (int i = sippers.size() - 1; i >= 0; i--) {
- final BatterySipper sipper = sippers.get(i);
- final double totalPower = sipper.sumPower();
- if (DEBUG && totalPower != 0) {
- Log.d(TAG, String.format("UID %d: total power=%s", sipper.getUid(),
- PowerCalculator.formatCharge(totalPower)));
- }
-
- // Add the sipper to the list if it is consuming power.
- if (totalPower != 0 || sipper.getUid() == 0) {
- if (sipper.drainType == DrainType.APP) {
- sipper.computeMobilemspp();
- if (sipper.mobilemspp != 0) {
- mMobilemsppList.add(sipper);
- }
- }
-
- if (!sipper.isAggregated) {
- mUsageList.add(sipper);
- }
- }
- }
- }
-
- @UnsupportedAppUsage
- public List<BatterySipper> getUsageList() {
- return mUsageList;
- }
-
- public List<BatterySipper> getMobilemsppList() {
- return mMobilemsppList;
- }
-
- public long getStatsPeriod() {
- return mStatsPeriod;
- }
-
- public int getStatsType() {
- return mStatsType;
- }
-
- @UnsupportedAppUsage
- public double getMaxPower() {
- return mMaxPower;
- }
-
- public double getMaxRealPower() {
- return mMaxRealPower;
- }
-
- @UnsupportedAppUsage
- public double getTotalPower() {
- return mTotalPower;
- }
-
- public double getComputedPower() {
- return mComputedPower;
- }
-
- public double getMinDrainedPower() {
- return mMinDrainedPower;
- }
-
- public double getMaxDrainedPower() {
- return mMaxDrainedPower;
- }
-
- public static byte[] readFully(FileInputStream stream) throws java.io.IOException {
- return readFully(stream, stream.available());
- }
-
- public static byte[] readFully(FileInputStream stream, int avail) throws java.io.IOException {
- int pos = 0;
- byte[] data = new byte[avail];
- while (true) {
- int amt = stream.read(data, pos, data.length - pos);
- //Log.i("foo", "Read " + amt + " bytes at " + pos
- // + " of avail " + data.length);
- if (amt <= 0) {
- //Log.i("foo", "**** FINISHED READING: pos=" + pos
- // + " len=" + data.length);
- return data;
- }
- pos += amt;
- avail = stream.available();
- if (avail > data.length - pos) {
- byte[] newData = new byte[pos + avail];
- System.arraycopy(data, 0, newData, 0, pos);
- data = newData;
- }
- }
- }
-
- /**
- * Mark the {@link BatterySipper} that we should hide.
- *
- * @param sippers sipper list that need to check and remove
- * @return the total power of the hidden items of {@link BatterySipper}
- * for proportional smearing
- */
- public double removeHiddenBatterySippers(List<BatterySipper> sippers) {
- double proportionalSmearPowerMah = 0;
- for (int i = sippers.size() - 1; i >= 0; i--) {
- final BatterySipper sipper = sippers.get(i);
- sipper.shouldHide = shouldHideSipper(sipper);
- if (sipper.shouldHide) {
- if (sipper.drainType != DrainType.OVERCOUNTED
- && sipper.drainType != DrainType.SCREEN
- && sipper.drainType != DrainType.AMBIENT_DISPLAY
- && sipper.drainType != DrainType.UNACCOUNTED
- && sipper.drainType != DrainType.BLUETOOTH
- && sipper.drainType != DrainType.WIFI
- && sipper.drainType != DrainType.IDLE) {
- // Don't add it if it is overcounted, unaccounted or screen
- proportionalSmearPowerMah += sipper.totalPowerMah;
- }
- }
- }
- return proportionalSmearPowerMah;
- }
-
- /**
- * Check whether we should hide the battery sipper.
- */
- public boolean shouldHideSipper(BatterySipper sipper) {
- final DrainType drainType = sipper.drainType;
-
- return drainType == DrainType.IDLE
- || drainType == DrainType.CELL
- || drainType == DrainType.SCREEN
- || drainType == DrainType.AMBIENT_DISPLAY
- || drainType == DrainType.UNACCOUNTED
- || drainType == DrainType.OVERCOUNTED
- || isTypeService(sipper)
- || isTypeSystem(sipper);
- }
-
- /**
- * Check whether {@code sipper} is type service
- */
- public boolean isTypeService(BatterySipper sipper) {
- final String[] packages = mPackageManager.getPackagesForUid(sipper.getUid());
- if (packages == null) {
- return false;
- }
-
- for (String packageName : packages) {
- if (ArrayUtils.contains(mServicepackageArray, packageName)) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Check whether {@code sipper} is type system
- */
- public boolean isTypeSystem(BatterySipper sipper) {
- final int uid = sipper.uidObj == null ? -1 : sipper.getUid();
- sipper.mPackages = mPackageManager.getPackagesForUid(uid);
- // Classify all the sippers to type system if the range of uid is 0...FIRST_APPLICATION_UID
- if (uid >= Process.ROOT_UID && uid < Process.FIRST_APPLICATION_UID) {
- return true;
- } else if (sipper.mPackages != null) {
- for (final String packageName : sipper.mPackages) {
- if (ArrayUtils.contains(mSystemPackageArray, packageName)) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- public long convertUsToMs(long timeUs) {
- return timeUs / 1000;
- }
-
- public long convertMsToUs(long timeMs) {
- return timeMs * 1000;
- }
-
- @VisibleForTesting
- public void setPackageManager(PackageManager packageManager) {
- mPackageManager = packageManager;
- }
-
- @VisibleForTesting
- public void setSystemPackageArray(String[] array) {
- mSystemPackageArray = array;
- }
-
- @VisibleForTesting
- public void setServicePackageArray(String[] array) {
- mServicepackageArray = array;
- }
-
- @UnsupportedAppUsage
- private void load() {
- load(true);
- }
-
- private void load(boolean updateAll) {
- if (mBatteryInfo == null) {
- return;
- }
- mStats = getStats(mBatteryInfo, updateAll);
- if (mCollectBatteryBroadcast) {
- mBatteryBroadcast = mContext.registerReceiver(null,
- new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
- }
- }
-
- private static BatteryStatsImpl getStats(IBatteryStats service, boolean updateAll) {
- try {
- ParcelFileDescriptor pfd = service.getStatisticsStream(updateAll);
- if (pfd != null) {
- if (false) {
- Log.d(TAG, "selinux context: "
- + SELinux.getFileContext(pfd.getFileDescriptor()));
- }
- try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
- byte[] data = readFully(fis, MemoryFile.getSize(pfd.getFileDescriptor()));
- Parcel parcel = Parcel.obtain();
- parcel.unmarshall(data, 0, data.length);
- parcel.setDataPosition(0);
- BatteryStatsImpl stats = com.android.internal.os.BatteryStatsImpl.CREATOR
- .createFromParcel(parcel);
- return stats;
- } catch (IOException e) {
- Log.w(TAG, "Unable to read statistics stream", e);
- }
- }
- } catch (RemoteException e) {
- Log.w(TAG, "RemoteException:", e);
- }
- return new BatteryStatsImpl();
- }
-}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 5ba45c9..70b9639 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -9211,7 +9211,7 @@
* Gets the minimum of the uid's foreground activity time and its PROCESS_STATE_TOP time
* since last marked. Also sets the mark time for both these timers.
*
- * @see BatteryStatsHelper#getProcessForegroundTimeMs
+ * @see CpuPowerCalculator
*
* @param doCalc if true, then calculate the minimum; else don't bother and return 0. Either
* way, the mark is set.
diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
index e4d5fb7..a1c1917 100644
--- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
+++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
@@ -73,7 +73,7 @@
mPowerCalculators.add(new CpuPowerCalculator(mPowerProfile));
mPowerCalculators.add(new MemoryPowerCalculator(mPowerProfile));
mPowerCalculators.add(new WakelockPowerCalculator(mPowerProfile));
- if (!BatteryStatsHelper.checkWifiOnly(mContext)) {
+ if (!BatteryStats.checkWifiOnly(mContext)) {
mPowerCalculators.add(new MobileRadioPowerCalculator(mPowerProfile));
}
mPowerCalculators.add(new WifiPowerCalculator(mPowerProfile));
diff --git a/core/java/com/android/internal/os/BluetoothPowerCalculator.java b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
index afa41a7..2ebf689 100644
--- a/core/java/com/android/internal/os/BluetoothPowerCalculator.java
+++ b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
@@ -21,14 +21,11 @@
import android.os.BatteryStats.ControllerActivityCounter;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
-import android.os.Process;
import android.os.UidBatteryConsumer;
-import android.os.UserHandle;
import android.util.Log;
import android.util.SparseArray;
import java.util.Arrays;
-import java.util.List;
public class BluetoothPowerCalculator extends PowerCalculator {
private static final String TAG = "BluetoothPowerCalc";
@@ -106,7 +103,7 @@
powerAndDuration.durationMs - powerAndDuration.totalDurationMs);
if (DEBUG) {
Log.d(TAG, "Bluetooth active: time=" + (systemComponentDurationMs)
- + " power=" + formatCharge(powerAndDuration.powerMah));
+ + " power=" + BatteryStats.formatCharge(powerAndDuration.powerMah));
}
builder.getAggregateBatteryConsumerBuilder(
@@ -159,73 +156,6 @@
}
}
- @Override
- public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
- long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
- if (!mHasBluetoothPowerController || !batteryStats.hasBluetoothActivityReporting()) {
- return;
- }
-
- PowerAndDuration powerAndDuration = new PowerAndDuration();
-
- for (int i = sippers.size() - 1; i >= 0; i--) {
- final BatterySipper app = sippers.get(i);
- if (app.drainType == BatterySipper.DrainType.APP) {
- calculateApp(app, app.uidObj, statsType, powerAndDuration);
- }
- }
-
- BatterySipper bs = new BatterySipper(BatterySipper.DrainType.BLUETOOTH, null, 0);
- final long measuredChargeUC = batteryStats.getBluetoothMeasuredBatteryConsumptionUC();
- final int powerModel = getPowerModel(measuredChargeUC);
- final ControllerActivityCounter activityCounter =
- batteryStats.getBluetoothControllerActivity();
- calculatePowerAndDuration(null, powerModel, measuredChargeUC, activityCounter, false,
- powerAndDuration);
-
- // Subtract what the apps used, but clamp to 0.
- final double powerMah = Math.max(0,
- powerAndDuration.powerMah - powerAndDuration.totalPowerMah);
- final long durationMs = Math.max(0,
- powerAndDuration.durationMs - powerAndDuration.totalDurationMs);
- if (DEBUG && powerMah != 0) {
- Log.d(TAG, "Bluetooth active: time=" + (durationMs)
- + " power=" + formatCharge(powerMah));
- }
-
- bs.bluetoothPowerMah = powerMah;
- bs.bluetoothRunningTimeMs = durationMs;
-
- for (int i = sippers.size() - 1; i >= 0; i--) {
- BatterySipper app = sippers.get(i);
- if (app.getUid() == Process.BLUETOOTH_UID) {
- if (DEBUG) Log.d(TAG, "Bluetooth adding sipper " + app + ": cpu=" + app.cpuTimeMs);
- app.isAggregated = true;
- bs.add(app);
- }
- }
- if (bs.sumPower() > 0) {
- sippers.add(bs);
- }
- }
-
- private void calculateApp(BatterySipper app, BatteryStats.Uid u, int statsType,
- PowerAndDuration powerAndDuration) {
- final long measuredChargeUC = u.getBluetoothMeasuredBatteryConsumptionUC();
- final int powerModel = getPowerModel(measuredChargeUC);
- final ControllerActivityCounter activityCounter = u.getBluetoothControllerActivity();
- calculatePowerAndDuration(u, powerModel, measuredChargeUC, activityCounter,
- false, powerAndDuration);
-
- app.bluetoothRunningTimeMs = powerAndDuration.durationMs;
- app.bluetoothPowerMah = powerAndDuration.powerMah;
- app.btRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_BT_RX_DATA, statsType);
- app.btTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_BT_TX_DATA, statsType);
-
- powerAndDuration.totalDurationMs += powerAndDuration.durationMs;
- powerAndDuration.totalPowerMah += powerAndDuration.powerMah;
- }
-
/** Returns bluetooth power usage based on the best data available. */
private void calculatePowerAndDuration(@Nullable BatteryStats.Uid uid,
@BatteryConsumer.PowerModel int powerModel,
diff --git a/core/java/com/android/internal/os/CameraPowerCalculator.java b/core/java/com/android/internal/os/CameraPowerCalculator.java
index 7bccab5..d0749e0 100644
--- a/core/java/com/android/internal/os/CameraPowerCalculator.java
+++ b/core/java/com/android/internal/os/CameraPowerCalculator.java
@@ -69,14 +69,4 @@
app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA, durationMs)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA, powerMah);
}
-
- @Override
- protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
- long rawUptimeUs, int statsType) {
- final long durationMs = mPowerEstimator.calculateDuration(u.getCameraTurnedOnTimer(),
- rawRealtimeUs, statsType);
- final double powerMah = mPowerEstimator.calculatePower(durationMs);
- app.cameraTimeMs = durationMs;
- app.cameraPowerMah = powerMah;
- }
}
diff --git a/core/java/com/android/internal/os/CpuPowerCalculator.java b/core/java/com/android/internal/os/CpuPowerCalculator.java
index 9940a0a..1fc2baf 100644
--- a/core/java/com/android/internal/os/CpuPowerCalculator.java
+++ b/core/java/com/android/internal/os/CpuPowerCalculator.java
@@ -20,13 +20,11 @@
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import android.os.UidBatteryConsumer;
-import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseArray;
import java.util.Arrays;
-import java.util.List;
public class CpuPowerCalculator extends PowerCalculator {
private static final String TAG = "CpuPowerCalculator";
@@ -217,29 +215,6 @@
}
}
- @Override
- public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
- long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
- Result result = new Result();
- for (int i = sippers.size() - 1; i >= 0; i--) {
- final BatterySipper app = sippers.get(i);
- if (app.drainType == BatterySipper.DrainType.APP) {
- calculateApp(app, app.uidObj, statsType, result);
- }
- }
- }
-
- private void calculateApp(BatterySipper app, BatteryStats.Uid u, int statsType, Result result) {
- final long consumptionUC = u.getCpuMeasuredBatteryConsumptionUC();
- final int powerModel = getPowerModel(consumptionUC);
- calculatePowerAndDuration(u, powerModel, consumptionUC, statsType, result);
-
- app.cpuPowerMah = result.powerMah;
- app.cpuTimeMs = result.durationMs;
- app.cpuFgTimeMs = result.durationFgMs;
- app.packageWithHighestDrain = result.packageWithHighestDrain;
- }
-
private void calculatePowerAndDuration(BatteryStats.Uid u,
@BatteryConsumer.PowerModel int powerModel, long consumptionUC, int statsType,
Result result) {
@@ -258,7 +233,7 @@
if (DEBUG && (durationMs != 0 || powerMah != 0)) {
Log.d(TAG, "UID " + u.getUid() + ": CPU time=" + durationMs + " ms power="
- + formatCharge(powerMah));
+ + BatteryStats.formatCharge(powerMah));
}
// Keep track of the package with highest drain.
@@ -325,7 +300,7 @@
if (DEBUG) {
Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + cluster
+ " clusterTimeMs=" + cpuClusterTimes[cluster]
- + " power=" + formatCharge(power));
+ + " power=" + BatteryStats.formatCharge(power));
}
}
} else {
diff --git a/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java b/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java
index 4cb7ef1..cbbb526 100644
--- a/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java
+++ b/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java
@@ -102,16 +102,6 @@
return newTotalPowerMah;
}
- @Override
- protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
- long rawUptimeUs, int statsType) {
- updateCustomMeasuredPowerMah(app, u.getCustomConsumerMeasuredBatteryConsumptionUC());
- }
-
- private void updateCustomMeasuredPowerMah(BatterySipper sipper, long[] measuredChargeUC) {
- sipper.customMeasuredPowerMah = calculateMeasuredEnergiesMah(measuredChargeUC);
- }
-
private double[] calculateMeasuredEnergiesMah(long[] measuredChargeUC) {
if (measuredChargeUC == null) {
return null;
diff --git a/core/java/com/android/internal/os/FlashlightPowerCalculator.java b/core/java/com/android/internal/os/FlashlightPowerCalculator.java
index 7d3f962..ce3e7b9 100644
--- a/core/java/com/android/internal/os/FlashlightPowerCalculator.java
+++ b/core/java/com/android/internal/os/FlashlightPowerCalculator.java
@@ -66,14 +66,4 @@
app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT, durationMs)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT, powerMah);
}
-
- @Override
- protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
- long rawUptimeUs, int statsType) {
- final long durationMs = mPowerEstimator.calculateDuration(u.getFlashlightTurnedOnTimer(),
- rawRealtimeUs, statsType);
- final double powerMah = mPowerEstimator.calculatePower(durationMs);
- app.flashlightTimeMs = durationMs;
- app.flashlightPowerMah = powerMah;
- }
}
diff --git a/core/java/com/android/internal/os/GnssPowerCalculator.java b/core/java/com/android/internal/os/GnssPowerCalculator.java
index a836ddb..0f78306 100644
--- a/core/java/com/android/internal/os/GnssPowerCalculator.java
+++ b/core/java/com/android/internal/os/GnssPowerCalculator.java
@@ -21,11 +21,8 @@
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import android.os.UidBatteryConsumer;
-import android.os.UserHandle;
import android.util.SparseArray;
-import java.util.List;
-
/**
* Estimates the amount of power consumed by the GNSS (e.g. GPS).
*/
@@ -100,41 +97,6 @@
return powerMah;
}
- @Override
- public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
- long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
- double averageGnssPowerMa = getAverageGnssPower(batteryStats, rawRealtimeUs, statsType);
- for (int i = sippers.size() - 1; i >= 0; i--) {
- final BatterySipper app = sippers.get(i);
- if (app.drainType == BatterySipper.DrainType.APP) {
- final long consumptionUC =
- app.uidObj.getGnssMeasuredBatteryConsumptionUC();
- final int powerModel = getPowerModel(consumptionUC);
- calculateApp(app, app.uidObj, powerModel, rawRealtimeUs, averageGnssPowerMa,
- consumptionUC);
- }
- }
- }
-
- private void calculateApp(BatterySipper app, BatteryStats.Uid u,
- @BatteryConsumer.PowerModel int powerModel, long rawRealtimeUs,
- double averageGnssPowerMa, long measuredChargeUC) {
- final long durationMs = computeDuration(u, rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED);
-
- final double powerMah;
- switch (powerModel) {
- case BatteryConsumer.POWER_MODEL_MEASURED_ENERGY:
- powerMah = uCtoMah(measuredChargeUC);
- break;
- case BatteryConsumer.POWER_MODEL_POWER_PROFILE:
- default:
- powerMah = computePower(durationMs, averageGnssPowerMa);
- }
-
- app.gpsTimeMs = durationMs;
- app.gpsPowerMah = powerMah;
- }
-
private long computeDuration(BatteryStats.Uid u, long rawRealtimeUs, int statsType) {
final SparseArray<? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats();
final BatteryStats.Uid.Sensor sensor = sensorStats.get(BatteryStats.Uid.Sensor.GPS);
diff --git a/core/java/com/android/internal/os/IdlePowerCalculator.java b/core/java/com/android/internal/os/IdlePowerCalculator.java
index 9491b3b..5b2052e 100644
--- a/core/java/com/android/internal/os/IdlePowerCalculator.java
+++ b/core/java/com/android/internal/os/IdlePowerCalculator.java
@@ -20,11 +20,7 @@
import android.os.BatteryStats;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
-import android.os.UserHandle;
import android.util.Log;
-import android.util.SparseArray;
-
-import java.util.List;
/**
* Estimates the amount of power consumed when the device is idle.
@@ -64,20 +60,6 @@
}
}
- @Override
- public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
- long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
- calculatePowerAndDuration(batteryStats, rawRealtimeUs, rawUptimeUs, statsType);
-
- if (mPowerMah != 0) {
- BatterySipper bs = new BatterySipper(BatterySipper.DrainType.IDLE, null, 0);
- bs.usagePowerMah = mPowerMah;
- bs.usageTimeMs = mDurationMs;
- bs.sumPower();
- sippers.add(bs);
- }
- }
-
/**
* Calculates the baseline power usage for the device when it is in suspend and idle.
* The device is drawing POWER_CPU_SUSPEND power at its lowest power state.
@@ -97,9 +79,9 @@
mPowerMah = suspendPowerMah + idlePowerMah;
if (DEBUG && mPowerMah != 0) {
Log.d(TAG, "Suspend: time=" + (batteryRealtimeUs / 1000)
- + " power=" + formatCharge(suspendPowerMah));
+ + " power=" + BatteryStats.formatCharge(suspendPowerMah));
Log.d(TAG, "Idle: time=" + (batteryUptimeUs / 1000)
- + " power=" + formatCharge(idlePowerMah));
+ + " power=" + BatteryStats.formatCharge(idlePowerMah));
}
mDurationMs = batteryRealtimeUs / 1000;
}
diff --git a/core/java/com/android/internal/os/MediaPowerCalculator.java b/core/java/com/android/internal/os/MediaPowerCalculator.java
deleted file mode 100644
index fff96da..0000000
--- a/core/java/com/android/internal/os/MediaPowerCalculator.java
+++ /dev/null
@@ -1,68 +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 com.android.internal.os;
-
-import android.os.BatteryConsumer;
-import android.os.BatteryStats;
-
-/**
- * A {@link PowerCalculator} to calculate power consumed by audio and video hardware.
- *
- * Also see {@link PowerProfile#POWER_AUDIO} and {@link PowerProfile#POWER_VIDEO}.
- */
-public class MediaPowerCalculator extends PowerCalculator {
- private static final int MS_IN_HR = 1000 * 60 * 60;
- private final double mAudioAveragePowerMa;
- private final double mVideoAveragePowerMa;
-
- public MediaPowerCalculator(PowerProfile profile) {
- mAudioAveragePowerMa = profile.getAveragePower(PowerProfile.POWER_AUDIO);
- mVideoAveragePowerMa = profile.getAveragePower(PowerProfile.POWER_VIDEO);
- }
-
- @Override
- public boolean isPowerComponentSupported(@BatteryConsumer.PowerComponent int powerComponent) {
- return powerComponent == BatteryConsumer.POWER_COMPONENT_VIDEO
- || powerComponent == BatteryConsumer.POWER_COMPONENT_AUDIO;
- }
-
- @Override
- protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
- long rawUptimeUs, int statsType) {
- // Calculate audio power usage, an estimate based on the average power routed to different
- // components like speaker, bluetooth, usb-c, earphone, etc.
- final BatteryStats.Timer audioTimer = u.getAudioTurnedOnTimer();
- if (audioTimer == null) {
- app.audioTimeMs = 0;
- app.audioPowerMah = 0;
- } else {
- final long totalTime = audioTimer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000;
- app.audioTimeMs = totalTime;
- app.audioPowerMah = (totalTime * mAudioAveragePowerMa) / MS_IN_HR;
- }
-
- // Calculate video power usage.
- final BatteryStats.Timer videoTimer = u.getVideoTurnedOnTimer();
- if (videoTimer == null) {
- app.videoTimeMs = 0;
- app.videoPowerMah = 0;
- } else {
- final long totalTime = videoTimer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000;
- app.videoTimeMs = totalTime;
- app.videoPowerMah = (totalTime * mVideoAveragePowerMa) / MS_IN_HR;
- }
- }
-}
diff --git a/core/java/com/android/internal/os/MemoryPowerCalculator.java b/core/java/com/android/internal/os/MemoryPowerCalculator.java
index 0440a58..0d3040c 100644
--- a/core/java/com/android/internal/os/MemoryPowerCalculator.java
+++ b/core/java/com/android/internal/os/MemoryPowerCalculator.java
@@ -4,11 +4,7 @@
import android.os.BatteryStats;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
-import android.os.UserHandle;
import android.util.LongSparseArray;
-import android.util.SparseArray;
-
-import java.util.List;
public class MemoryPowerCalculator extends PowerCalculator {
public static final String TAG = "MemoryPowerCalculator";
@@ -41,20 +37,6 @@
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_MEMORY, powerMah);
}
- @Override
- public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
- long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
- final long durationMs = calculateDuration(batteryStats, rawRealtimeUs, statsType);
- final double powerMah = calculatePower(batteryStats, rawRealtimeUs, statsType);
- BatterySipper memory = new BatterySipper(BatterySipper.DrainType.MEMORY, null, 0);
- memory.usageTimeMs = durationMs;
- memory.usagePowerMah = powerMah;
- memory.sumPower();
- if (memory.totalPowerMah > 0) {
- sippers.add(memory);
- }
- }
-
private long calculateDuration(BatteryStats batteryStats, long rawRealtimeUs, int statsType) {
long usageDurationMs = 0;
LongSparseArray<? extends BatteryStats.Timer> timers = batteryStats.getKernelMemoryStats();
diff --git a/core/java/com/android/internal/os/MobileRadioPowerCalculator.java b/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
index 3a50b73..f4624de 100644
--- a/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
+++ b/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
@@ -20,13 +20,10 @@
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import android.os.UidBatteryConsumer;
-import android.os.UserHandle;
import android.telephony.CellSignalStrength;
import android.util.Log;
import android.util.SparseArray;
-import java.util.List;
-
public class MobileRadioPowerCalculator extends PowerCalculator {
private static final String TAG = "MobRadioPowerCalculator";
private static final boolean DEBUG = PowerCalculator.DEBUG;
@@ -170,65 +167,6 @@
}
}
- @Override
- public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
- long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
- PowerAndDuration total = new PowerAndDuration();
- for (int i = sippers.size() - 1; i >= 0; i--) {
- final BatterySipper app = sippers.get(i);
- if (app.drainType == BatterySipper.DrainType.APP) {
- final BatteryStats.Uid u = app.uidObj;
- calculateApp(app, u, statsType, total);
- }
- }
-
- BatterySipper radio = new BatterySipper(BatterySipper.DrainType.CELL, null, 0);
- final long consumptionUC = batteryStats.getMobileRadioMeasuredBatteryConsumptionUC();
- final int powerModel = getPowerModel(consumptionUC);
- calculateRemaining(total, powerModel, batteryStats, rawRealtimeUs, consumptionUC);
- if (total.remainingPowerMah != 0) {
- if (total.signalDurationMs != 0) {
- radio.noCoveragePercent =
- total.noCoverageDurationMs * 100.0 / total.signalDurationMs;
- }
- radio.mobileActive = total.durationMs;
- radio.mobileActiveCount = batteryStats.getMobileRadioActiveUnknownCount(statsType);
- radio.mobileRadioPowerMah = total.remainingPowerMah;
- radio.sumPower();
- }
- if (radio.totalPowerMah > 0) {
- sippers.add(radio);
- }
- }
-
- private void calculateApp(BatterySipper app, BatteryStats.Uid u, int statsType,
- PowerAndDuration total) {
- app.mobileActive = calculateDuration(u, statsType);
-
- final long consumptionUC = u.getMobileRadioMeasuredBatteryConsumptionUC();
- final int powerModel = getPowerModel(consumptionUC);
- app.mobileRadioPowerMah = calculatePower(u, powerModel, app.mobileActive, consumptionUC);
- total.totalAppDurationMs += app.mobileActive;
-
- // Add cost of mobile traffic.
- app.mobileRxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_RX_DATA,
- statsType);
- app.mobileTxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_TX_DATA,
- statsType);
- app.mobileActiveCount = u.getMobileRadioActiveCount(statsType);
- app.mobileRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_RX_DATA,
- statsType);
- app.mobileTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_TX_DATA,
- statsType);
-
- if (DEBUG && app.mobileRadioPowerMah != 0) {
- Log.d(TAG, "UID " + u.getUid() + ": mobile packets "
- + (app.mobileRxPackets + app.mobileTxPackets)
- + " active time " + app.mobileActive
- + " power=" + formatCharge(app.mobileRadioPowerMah));
- }
- }
-
private long calculateDuration(BatteryStats.Uid u, int statsType) {
return u.getMobileRadioActiveTime(statsType) / 1000;
}
@@ -262,7 +200,7 @@
final double p = calcIdlePowerAtSignalStrengthMah(strengthTimeMs, i);
if (DEBUG && p != 0) {
Log.d(TAG, "Cell strength #" + i + ": time=" + strengthTimeMs + " power="
- + formatCharge(p));
+ + BatteryStats.formatCharge(p));
}
powerMah += p;
}
@@ -281,8 +219,8 @@
if (powerModel == BatteryConsumer.POWER_MODEL_POWER_PROFILE) {
final double p = calcScanTimePowerMah(scanningTimeMs);
if (DEBUG && p != 0) {
- Log.d(TAG, "Cell radio scanning: time=" + scanningTimeMs + " power=" + formatCharge(
- p));
+ Log.d(TAG, "Cell radio scanning: time=" + scanningTimeMs
+ + " power=" + BatteryStats.formatCharge(p));
}
powerMah += p;
diff --git a/core/java/com/android/internal/os/PhonePowerCalculator.java b/core/java/com/android/internal/os/PhonePowerCalculator.java
index 7310314..cb893de 100644
--- a/core/java/com/android/internal/os/PhonePowerCalculator.java
+++ b/core/java/com/android/internal/os/PhonePowerCalculator.java
@@ -20,10 +20,6 @@
import android.os.BatteryStats;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
-import android.os.UserHandle;
-import android.util.SparseArray;
-
-import java.util.List;
/**
* Estimates power consumed by telephony.
@@ -54,18 +50,4 @@
.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnTimeMs);
}
}
-
- @Override
- public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
- long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
- final long phoneOnTimeMs = batteryStats.getPhoneOnTime(rawRealtimeUs, statsType) / 1000;
- final double phoneOnPower = mPowerEstimator.calculatePower(phoneOnTimeMs);
- if (phoneOnPower != 0) {
- BatterySipper bs = new BatterySipper(BatterySipper.DrainType.PHONE, null, 0);
- bs.usagePowerMah = phoneOnPower;
- bs.usageTimeMs = phoneOnTimeMs;
- bs.sumPower();
- sippers.add(bs);
- }
- }
}
diff --git a/core/java/com/android/internal/os/PowerCalculator.java b/core/java/com/android/internal/os/PowerCalculator.java
index 28c0f5a..ec785b8 100644
--- a/core/java/com/android/internal/os/PowerCalculator.java
+++ b/core/java/com/android/internal/os/PowerCalculator.java
@@ -21,12 +21,9 @@
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import android.os.UidBatteryConsumer;
-import android.os.UserHandle;
import android.util.SparseArray;
import java.io.PrintWriter;
-import java.util.List;
-import java.util.Locale;
/**
* Calculates power use of a device subsystem for an app.
@@ -43,34 +40,6 @@
public abstract boolean isPowerComponentSupported(
@BatteryConsumer.PowerComponent int powerComponent);
-
- /**
- * Attributes the total amount of power used by this subsystem to various consumers such
- * as apps.
- *
- * @param sippers A list of battery sippers that contains battery attribution data.
- * The calculator may modify the list.
- * @param batteryStats The recorded battery stats.
- * @param rawRealtimeUs The raw system realtime in microseconds.
- * @param rawUptimeUs The raw system uptime in microseconds.
- * @param statsType The type of stats. As of {@link android.os.Build.VERSION_CODES#Q}, this
- * can only be {@link BatteryStats#STATS_SINCE_CHARGED}, since
- * {@link BatteryStats#STATS_CURRENT} and
- * {@link BatteryStats#STATS_SINCE_UNPLUGGED} are deprecated.
- * @param asUsers An array of users for which the attribution is requested. It may
- * contain {@link UserHandle#USER_ALL} to indicate that the attribution
- * should be performed for all users.
- */
- public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
- long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
- for (int i = sippers.size() - 1; i >= 0; i--) {
- final BatterySipper app = sippers.get(i);
- if (app.drainType == BatterySipper.DrainType.APP) {
- calculateApp(app, app.uidObj, rawRealtimeUs, rawUptimeUs, statsType);
- }
- }
- }
-
/**
* Attributes the total amount of power used by this subsystem to various consumers such
* as apps.
@@ -95,21 +64,6 @@
/**
* Calculate the amount of power an app used for this subsystem.
- * @param app The BatterySipper that represents the power use of an app.
- * @param u The recorded stats for the app.
- * @param rawRealtimeUs The raw system realtime in microseconds.
- * @param rawUptimeUs The raw system uptime in microseconds.
- * @param statsType The type of stats. As of {@link android.os.Build.VERSION_CODES#Q}, this can
- * only be {@link BatteryStats#STATS_SINCE_CHARGED}, since
- * {@link BatteryStats#STATS_CURRENT} and
- * {@link BatteryStats#STATS_SINCE_UNPLUGGED} are deprecated.
- */
- protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
- long rawUptimeUs, int statsType) {
- }
-
- /**
- * Calculate the amount of power an app used for this subsystem.
* @param app The UidBatteryConsumer.Builder that represents the power use of an app.
* @param u The recorded stats for the app.
* @param rawRealtimeUs The raw system realtime in microseconds.
@@ -145,38 +99,7 @@
* Prints formatted amount of power in milli-amp-hours.
*/
public static void printPowerMah(PrintWriter pw, double powerMah) {
- pw.print(formatCharge(powerMah));
- }
-
- /**
- * Converts charge in mAh to string.
- */
- public static String formatCharge(double power) {
- if (power == 0) return "0";
-
- final String format;
- if (power < .00001) {
- format = "%.8f";
- } else if (power < .0001) {
- format = "%.7f";
- } else if (power < .001) {
- format = "%.6f";
- } else if (power < .01) {
- format = "%.5f";
- } else if (power < .1) {
- format = "%.4f";
- } else if (power < 1) {
- format = "%.3f";
- } else if (power < 10) {
- format = "%.2f";
- } else if (power < 100) {
- format = "%.1f";
- } else {
- format = "%.0f";
- }
-
- // Use English locale because this is never used in UI (only in checkin and dump).
- return String.format(Locale.ENGLISH, format, power);
+ pw.print(BatteryStats.formatCharge(powerMah));
}
static double uCtoMah(long chargeUC) {
diff --git a/core/java/com/android/internal/os/ScreenPowerCalculator.java b/core/java/com/android/internal/os/ScreenPowerCalculator.java
index 110b6b6..67d3d6e 100644
--- a/core/java/com/android/internal/os/ScreenPowerCalculator.java
+++ b/core/java/com/android/internal/os/ScreenPowerCalculator.java
@@ -24,7 +24,6 @@
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import android.os.UidBatteryConsumer;
-import android.os.UserHandle;
import android.text.format.DateUtils;
import android.util.Slog;
import android.util.SparseArray;
@@ -32,8 +31,6 @@
import com.android.internal.annotations.VisibleForTesting;
-import java.util.List;
-
/**
* Estimates power consumed by the screen(s)
*/
@@ -125,48 +122,6 @@
}
/**
- * Screen power is the additional power the screen takes while the device is running.
- */
- @Override
- public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
- long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
- final PowerAndDuration totalPowerAndDuration = new PowerAndDuration();
- final long consumptionUC = batteryStats.getScreenOnMeasuredBatteryConsumptionUC();
- final int powerModel = getPowerModel(consumptionUC);
- calculateTotalDurationAndPower(totalPowerAndDuration, powerModel, batteryStats,
- rawRealtimeUs, statsType, consumptionUC);
- if (totalPowerAndDuration.powerMah == 0) {
- return;
- }
-
- // First deal with the SCREEN BatterySipper (since we need this for smearing over apps).
- final BatterySipper bs = new BatterySipper(BatterySipper.DrainType.SCREEN, null, 0);
- bs.usagePowerMah = totalPowerAndDuration.powerMah;
- bs.usageTimeMs = totalPowerAndDuration.durationMs;
- bs.sumPower();
- sippers.add(bs);
-
- // Now deal with each app's BatterySipper. The results are stored in the screenPowerMah
- // field, which is considered smeared, but the method depends on the data source.
- switch (powerModel) {
- case BatteryConsumer.POWER_MODEL_MEASURED_ENERGY:
- final PowerAndDuration appPowerAndDuration = new PowerAndDuration();
- for (int i = sippers.size() - 1; i >= 0; i--) {
- final BatterySipper app = sippers.get(i);
- if (app.drainType == BatterySipper.DrainType.APP) {
- calculateAppUsingMeasuredEnergy(appPowerAndDuration, app.uidObj,
- rawRealtimeUs);
- app.screenPowerMah = appPowerAndDuration.powerMah;
- }
- }
- break;
- case BatteryConsumer.POWER_MODEL_POWER_PROFILE:
- default:
- smearScreenBatterySipper(sippers, bs, rawRealtimeUs);
- }
- }
-
- /**
* Stores duration and power information in totalPowerAndDuration.
*/
private void calculateTotalDurationAndPower(PowerAndDuration totalPowerAndDuration,
@@ -219,7 +174,7 @@
brightnessTime) * (bin + 0.5f) / BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS;
if (DEBUG && binPowerMah != 0) {
Slog.d(TAG, "Screen bin #" + bin + ": time=" + brightnessTime
- + " power=" + formatCharge(binPowerMah));
+ + " power=" + BatteryStats.formatCharge(binPowerMah));
}
power += binPowerMah;
}
@@ -228,37 +183,8 @@
}
/**
- * Smear the screen on power usage among {@code sippers}, based on ratio of foreground activity
- * time, and store this in the {@link BatterySipper#screenPowerMah} field.
- */
- @VisibleForTesting
- public void smearScreenBatterySipper(List<BatterySipper> sippers, BatterySipper screenSipper,
- long rawRealtimeUs) {
- long totalActivityTimeMs = 0;
- final SparseLongArray activityTimeArray = new SparseLongArray();
- for (int i = sippers.size() - 1; i >= 0; i--) {
- final BatteryStats.Uid uid = sippers.get(i).uidObj;
- if (uid != null) {
- final long timeMs = getProcessForegroundTimeMs(uid, rawRealtimeUs);
- activityTimeArray.put(uid.getUid(), timeMs);
- totalActivityTimeMs += timeMs;
- }
- }
-
- if (screenSipper != null && totalActivityTimeMs >= MIN_ACTIVE_TIME_FOR_SMEARING) {
- final double totalScreenPowerMah = screenSipper.totalPowerMah;
- for (int i = sippers.size() - 1; i >= 0; i--) {
- final BatterySipper sipper = sippers.get(i);
- sipper.screenPowerMah = totalScreenPowerMah
- * activityTimeArray.get(sipper.getUid(), 0)
- / totalActivityTimeMs;
- }
- }
- }
-
- /**
- * Smear the screen on power usage among {@code sippers}, based on ratio of foreground activity
- * time, and store this in the {@link BatterySipper#screenPowerMah} field.
+ * Smear the screen on power usage among {@code UidBatteryConsumers}, based on ratio of
+ * foreground activity time.
*/
private void smearScreenBatteryDrain(
SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders,
diff --git a/core/java/com/android/internal/os/SensorPowerCalculator.java b/core/java/com/android/internal/os/SensorPowerCalculator.java
index 495a6d9..4a9c91d 100644
--- a/core/java/com/android/internal/os/SensorPowerCalculator.java
+++ b/core/java/com/android/internal/os/SensorPowerCalculator.java
@@ -72,12 +72,6 @@
return powerMah;
}
- @Override
- protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
- long rawUptimeUs, int statsType) {
- app.sensorPowerMah = calculatePowerMah(u, rawRealtimeUs, statsType);
- }
-
private long calculateDuration(BatteryStats.Uid u, long rawRealtimeUs, int statsType) {
long durationMs = 0;
final SparseArray<? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats();
diff --git a/core/java/com/android/internal/os/SystemServicePowerCalculator.java b/core/java/com/android/internal/os/SystemServicePowerCalculator.java
index d7872ba..3a3df87 100644
--- a/core/java/com/android/internal/os/SystemServicePowerCalculator.java
+++ b/core/java/com/android/internal/os/SystemServicePowerCalculator.java
@@ -22,12 +22,9 @@
import android.os.BatteryUsageStatsQuery;
import android.os.Process;
import android.os.UidBatteryConsumer;
-import android.os.UserHandle;
import android.util.Log;
import android.util.SparseArray;
-import java.util.List;
-
/**
* Estimates the amount of power consumed by the System Server handling requests from
* a given app.
@@ -121,55 +118,6 @@
systemServicePowerMah);
}
- @Override
- public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
- long rawRealtimeUs, long rawUptimeUs, int statsType,
- SparseArray<UserHandle> asUsers) {
- final BatteryStats.Uid systemUid = batteryStats.getUidStats().get(Process.SYSTEM_UID);
- if (systemUid == null) {
- return;
- }
-
- final long consumptionUC = systemUid.getCpuMeasuredBatteryConsumptionUC();
- double systemServicePowerMah;
- if (getPowerModel(consumptionUC) == BatteryConsumer.POWER_MODEL_MEASURED_ENERGY) {
- systemServicePowerMah = calculatePowerUsingMeasuredConsumption(batteryStats,
- systemUid, consumptionUC);
- } else {
- systemServicePowerMah = calculatePowerUsingPowerProfile(batteryStats);
- }
-
- BatterySipper systemServerSipper = null;
- for (int i = sippers.size() - 1; i >= 0; i--) {
- final BatterySipper app = sippers.get(i);
- if (app.drainType == BatterySipper.DrainType.APP) {
- if (app.getUid() == Process.SYSTEM_UID) {
- systemServerSipper = app;
- break;
- }
- }
- }
-
- if (systemServerSipper != null) {
- systemServicePowerMah = Math.min(systemServicePowerMah, systemServerSipper.sumPower());
-
- // The system server power needs to be adjusted because part of it got
- // distributed to applications
- systemServerSipper.powerReattributedToOtherSippersMah = -systemServicePowerMah;
- }
-
- for (int i = sippers.size() - 1; i >= 0; i--) {
- final BatterySipper app = sippers.get(i);
- if (app.drainType == BatterySipper.DrainType.APP) {
- if (app != systemServerSipper) {
- final BatteryStats.Uid uid = app.uidObj;
- app.systemServiceCpuPowerMah =
- systemServicePowerMah * uid.getProportionalSystemServiceUsage();
- }
- }
- }
- }
-
private double calculatePowerUsingMeasuredConsumption(BatteryStats batteryStats,
BatteryStats.Uid systemUid, long consumptionUC) {
// Use the PowerProfile based model to estimate the ratio between the power consumed
diff --git a/core/java/com/android/internal/os/UserPowerCalculator.java b/core/java/com/android/internal/os/UserPowerCalculator.java
index b590bf7..22cff6e 100644
--- a/core/java/com/android/internal/os/UserPowerCalculator.java
+++ b/core/java/com/android/internal/os/UserPowerCalculator.java
@@ -27,8 +27,6 @@
import com.android.internal.util.ArrayUtils;
-import java.util.List;
-
/**
* Computes power consumed by Users
*/
@@ -65,40 +63,4 @@
}
}
}
-
- @Override
- public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
- long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
- final boolean forAllUsers = (asUsers.get(UserHandle.USER_ALL) != null);
- if (forAllUsers) {
- return;
- }
-
- SparseArray<BatterySipper> userSippers = new SparseArray<>();
-
- for (int i = sippers.size() - 1; i >= 0; i--) {
- BatterySipper sipper = sippers.get(i);
- final int uid = sipper.getUid();
- final int userId = UserHandle.getUserId(uid);
- if (asUsers.get(userId) == null
- && UserHandle.getAppId(uid) >= Process.FIRST_APPLICATION_UID) {
- // We are told to just report this user's apps as one accumulated entry.
- BatterySipper userSipper = userSippers.get(userId);
- if (userSipper == null) {
- userSipper = new BatterySipper(BatterySipper.DrainType.USER, null, 0);
- userSipper.userId = userId;
- userSippers.put(userId, userSipper);
- }
- userSipper.add(sipper);
- sipper.isAggregated = true;
- }
- }
-
- for (int i = 0; i < userSippers.size(); i++) {
- BatterySipper sipper = userSippers.valueAt(i);
- if (sipper.sumPower() > 0) {
- sippers.add(sipper);
- }
- }
- }
}
diff --git a/core/java/com/android/internal/os/WakelockPowerCalculator.java b/core/java/com/android/internal/os/WakelockPowerCalculator.java
index bceb209..0251e1c 100644
--- a/core/java/com/android/internal/os/WakelockPowerCalculator.java
+++ b/core/java/com/android/internal/os/WakelockPowerCalculator.java
@@ -21,13 +21,10 @@
import android.os.BatteryUsageStatsQuery;
import android.os.Process;
import android.os.UidBatteryConsumer;
-import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseArray;
-import java.util.List;
-
public class WakelockPowerCalculator extends PowerCalculator {
private static final String TAG = "WakelockPowerCalculator";
private static final boolean DEBUG = PowerCalculator.DEBUG;
@@ -105,42 +102,6 @@
appPowerMah);
}
- @Override
- public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
- long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
- final PowerAndDuration result = new PowerAndDuration();
- BatterySipper osSipper = null;
- double osPowerMah = 0;
- long osDurationMs = 0;
- long totalAppDurationMs = 0;
- for (int i = sippers.size() - 1; i >= 0; i--) {
- final BatterySipper app = sippers.get(i);
- if (app.drainType == BatterySipper.DrainType.APP) {
- calculateApp(result, app.uidObj, rawRealtimeUs, statsType);
- app.wakeLockTimeMs = result.durationMs;
- app.wakeLockPowerMah = result.powerMah;
- totalAppDurationMs += result.durationMs;
-
- if (app.getUid() == Process.ROOT_UID) {
- osSipper = app;
- osPowerMah = result.powerMah;
- osDurationMs = result.durationMs;
- }
- }
- }
-
- // The device has probably been awake for longer than the screen on
- // time and application wake lock time would account for. Assign
- // this remainder to the OS, if possible.
- if (osSipper != null) {
- calculateRemaining(result, batteryStats, rawRealtimeUs, rawUptimeUs, statsType,
- osPowerMah, osDurationMs, totalAppDurationMs);
- osSipper.wakeLockTimeMs = result.durationMs;
- osSipper.wakeLockPowerMah = result.powerMah;
- osSipper.sumPower();
- }
- }
-
private void calculateApp(PowerAndDuration result, BatteryStats.Uid u, long rawRealtimeUs,
int statsType) {
long wakeLockTimeUs = 0;
@@ -163,7 +124,7 @@
result.powerMah = mPowerEstimator.calculatePower(result.durationMs);
if (DEBUG && result.powerMah != 0) {
Log.d(TAG, "UID " + u.getUid() + ": wake " + result.durationMs
- + " power=" + formatCharge(result.powerMah));
+ + " power=" + BatteryStats.formatCharge(result.powerMah));
}
}
@@ -175,7 +136,8 @@
if (wakeTimeMillis > 0) {
final double power = mPowerEstimator.calculatePower(wakeTimeMillis);
if (DEBUG) {
- Log.d(TAG, "OS wakeLockTime " + wakeTimeMillis + " power " + formatCharge(power));
+ Log.d(TAG, "OS wakeLockTime " + wakeTimeMillis
+ + " power " + BatteryStats.formatCharge(power));
}
result.durationMs = osDurationMs + wakeTimeMillis;
result.powerMah = osPowerMah + power;
diff --git a/core/java/com/android/internal/os/WifiPowerCalculator.java b/core/java/com/android/internal/os/WifiPowerCalculator.java
index ad291a4..8c3fb86 100644
--- a/core/java/com/android/internal/os/WifiPowerCalculator.java
+++ b/core/java/com/android/internal/os/WifiPowerCalculator.java
@@ -19,14 +19,11 @@
import android.os.BatteryStats;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
-import android.os.Process;
import android.os.UidBatteryConsumer;
-import android.os.UserHandle;
import android.util.Log;
import android.util.SparseArray;
import java.util.Arrays;
-import java.util.List;
/**
* WiFi power calculator for when BatteryStats supports energy reporting
@@ -156,62 +153,6 @@
totalAppPowerMah, powerModel);
}
- /**
- * We do per-app blaming of WiFi activity. If energy info is reported from the controller,
- * then only the WiFi process gets blamed here since we normalize power calculations and
- * assign all the power drain to apps. If energy info is not reported, we attribute the
- * difference between total running time of WiFi for all apps and the actual running time
- * of WiFi to the WiFi subsystem.
- */
- @Override
- public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
- long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
-
- final BatterySipper bs = new BatterySipper(BatterySipper.DrainType.WIFI, null, 0);
-
- long totalAppDurationMs = 0;
- double totalAppPowerMah = 0;
- final PowerDurationAndTraffic powerDurationAndTraffic = new PowerDurationAndTraffic();
- for (int i = sippers.size() - 1; i >= 0; i--) {
- final BatterySipper app = sippers.get(i);
- if (app.drainType == BatterySipper.DrainType.APP) {
- final long consumptionUC =
- app.uidObj.getWifiMeasuredBatteryConsumptionUC();
- final int powerModel = getPowerModel(consumptionUC);
- calculateApp(powerDurationAndTraffic, app.uidObj, powerModel, rawRealtimeUs,
- statsType, batteryStats.hasWifiActivityReporting(), consumptionUC);
-
- totalAppDurationMs += powerDurationAndTraffic.durationMs;
- totalAppPowerMah += powerDurationAndTraffic.powerMah;
-
- app.wifiPowerMah = powerDurationAndTraffic.powerMah;
- app.wifiRunningTimeMs = powerDurationAndTraffic.durationMs;
- app.wifiRxBytes = powerDurationAndTraffic.wifiRxBytes;
- app.wifiRxPackets = powerDurationAndTraffic.wifiRxPackets;
- app.wifiTxBytes = powerDurationAndTraffic.wifiTxBytes;
- app.wifiTxPackets = powerDurationAndTraffic.wifiTxPackets;
- if (app.getUid() == Process.WIFI_UID) {
- if (DEBUG) Log.d(TAG, "WiFi adding sipper " + app + ": cpu=" + app.cpuTimeMs);
- app.isAggregated = true;
- bs.add(app);
- }
- }
- }
-
- final long consumptionUC = batteryStats.getWifiMeasuredBatteryConsumptionUC();
- final int powerModel = getPowerModel(consumptionUC);
- calculateRemaining(powerDurationAndTraffic, powerModel, batteryStats, rawRealtimeUs,
- statsType, batteryStats.hasWifiActivityReporting(), totalAppDurationMs,
- totalAppPowerMah, consumptionUC);
-
- bs.wifiRunningTimeMs += powerDurationAndTraffic.durationMs;
- bs.wifiPowerMah += powerDurationAndTraffic.powerMah;
-
- if (bs.sumPower() > 0) {
- sippers.add(bs);
- }
- }
-
private void calculateApp(PowerDurationAndTraffic powerDurationAndTraffic,
BatteryStats.Uid u, @BatteryConsumer.PowerModel int powerModel,
long rawRealtimeUs, int statsType, boolean hasWifiActivityReporting,
@@ -251,7 +192,7 @@
if (DEBUG && powerDurationAndTraffic.powerMah != 0) {
Log.d(TAG, "UID " + u.getUid() + ": idle=" + idleTime + "ms rx=" + rxTime
- + "ms tx=" + txTime + "ms power=" + formatCharge(
+ + "ms tx=" + txTime + "ms power=" + BatteryStats.formatCharge(
powerDurationAndTraffic.powerMah));
}
@@ -306,7 +247,7 @@
}
if (DEBUG && powerDurationAndTraffic.powerMah != 0) {
- Log.d(TAG, "UID " + u.getUid() + ": power=" + formatCharge(
+ Log.d(TAG, "UID " + u.getUid() + ": power=" + BatteryStats.formatCharge(
powerDurationAndTraffic.powerMah));
}
}
@@ -353,7 +294,8 @@
powerDurationAndTraffic.powerMah = Math.max(0, totalPowerMah - totalAppPowerMah);
if (DEBUG) {
- Log.d(TAG, "left over WiFi power: " + formatCharge(powerDurationAndTraffic.powerMah));
+ Log.d(TAG, "left over WiFi power: " + BatteryStats.formatCharge(
+ powerDurationAndTraffic.powerMah));
}
}
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 611f644..3d24aa2d 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -713,7 +713,7 @@
"--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",
@@ -736,10 +736,13 @@
Zygote.applyInvokeWithSystemProperty(parsedArgs);
if (Zygote.nativeSupportsMemoryTagging()) {
- /* The system server has ASYNC MTE by default, in order to allow
- * system services to specify their own MTE level later, as you
- * can't re-enable MTE once it's disabled. */
- String mode = SystemProperties.get("arm64.memtag.process.system_server", "async");
+ String mode = SystemProperties.get("arm64.memtag.process.system_server", "");
+ if (mode.isEmpty()) {
+ /* The system server has ASYNC MTE by default, in order to allow
+ * system services to specify their own MTE level later, as you
+ * can't re-enable MTE once it's disabled. */
+ mode = SystemProperties.get("persist.arm64.memtag.default", "async");
+ }
if (mode.equals("async")) {
parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_ASYNC;
} else if (mode.equals("sync")) {
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 51eb429..46f54ce 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -308,5 +308,7 @@
/** Notifies System UI about an update to the media tap-to-transfer receiver state. */
void updateMediaTapToTransferReceiverDisplay(
int displayState,
- in MediaRoute2Info routeInfo);
+ in MediaRoute2Info routeInfo,
+ in Icon appIcon,
+ in CharSequence appName);
}
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 0c45e5b..6c17df1 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -208,5 +208,7 @@
/** Notifies System UI about an update to the media tap-to-transfer receiver state. */
void updateMediaTapToTransferReceiverDisplay(
int displayState,
- in MediaRoute2Info routeInfo);
+ in MediaRoute2Info routeInfo,
+ in Icon appIcon,
+ in CharSequence appName);
}
diff --git a/core/java/com/android/internal/util/ContrastColorUtil.java b/core/java/com/android/internal/util/ContrastColorUtil.java
index 7a712e5..ced2722 100644
--- a/core/java/com/android/internal/util/ContrastColorUtil.java
+++ b/core/java/com/android/internal/util/ContrastColorUtil.java
@@ -627,7 +627,7 @@
}
/**
- * Framework copy of functions needed from android.support.v4.graphics.ColorUtils.
+ * Framework copy of functions needed from androidx.core.graphics.ColorUtils.
*/
private static class ColorUtilsFromCompat {
private static final double XYZ_WHITE_REFERENCE_X = 95.047;
diff --git a/core/java/com/android/internal/util/dump/DumpableContainerImpl.java b/core/java/com/android/internal/util/dump/DumpableContainerImpl.java
index d391684..2e56ebf 100644
--- a/core/java/com/android/internal/util/dump/DumpableContainerImpl.java
+++ b/core/java/com/android/internal/util/dump/DumpableContainerImpl.java
@@ -24,11 +24,12 @@
import java.io.PrintWriter;
import java.util.Objects;
-// TODO(b/149254050): add unit tests
/**
* Helper class for {@link DumpableContainer} implementations - they can "implement it by
* association", i.e., by delegating the interface methods to a {@code DumpableContainerImpl}.
*
+ * <p>This class is not thread safe.
+ *
* @hide
*/
public final class DumpableContainerImpl implements DumpableContainer {
@@ -58,6 +59,38 @@
return true;
}
+ @Override
+ public boolean removeDumpable(Dumpable dumpable) {
+ Objects.requireNonNull(dumpable, "dumpable");
+ String name = dumpable.getDumpableName();
+ if (name == null) {
+ if (DEBUG) {
+ Log.d(TAG, "Tried to remove nameless dumpable: " + dumpable);
+ }
+ return false;
+ }
+
+ Dumpable candidate = mDumpables.get(name);
+ if (candidate == null) {
+ if (DEBUG) {
+ Log.d(TAG, "Dumpable with name " + name + " not found");
+ }
+ return false;
+ }
+
+ // Make sure it's the right one
+ if (candidate != dumpable) {
+ Log.w(TAG, "removeDumpable(): passed dumpable (" + dumpable + ") named " + name
+ + ", but internal dumpable with that name is " + candidate);
+ return false;
+ }
+ if (DEBUG) {
+ Log.d(TAG, "Removing dumpable named " + name);
+ }
+ mDumpables.remove(name);
+ return true;
+ }
+
/**
* Dumps the number of dumpable, without a newline.
*/
diff --git a/core/java/com/android/internal/view/IInputMethodClient.aidl b/core/java/com/android/internal/view/IInputMethodClient.aidl
index e72afdd..8430c08 100644
--- a/core/java/com/android/internal/view/IInputMethodClient.aidl
+++ b/core/java/com/android/internal/view/IInputMethodClient.aidl
@@ -24,7 +24,9 @@
*/
oneway interface IInputMethodClient {
void onBindMethod(in InputBindResult res);
+ void onBindAccessibilityService(in InputBindResult res, int id);
void onUnbindMethod(int sequence, int unbindReason);
+ void onUnbindAccessibilityService(int sequence, int id);
void setActive(boolean active, boolean fullscreen, boolean reportToImeController);
void scheduleStartInputIfNecessary(boolean fullscreen);
void reportFullscreenMode(boolean fullscreen);
diff --git a/core/java/com/android/internal/view/IInputSessionWithIdCallback.aidl b/core/java/com/android/internal/view/IInputSessionWithIdCallback.aidl
new file mode 100644
index 0000000..8fbdefe
--- /dev/null
+++ b/core/java/com/android/internal/view/IInputSessionWithIdCallback.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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 com.android.internal.view;
+
+ import com.android.internal.view.IInputMethodSession;
+
+/**
+ * Helper interface for IInputMethod to allow the input method to notify the client when a new
+ * session has been created.
+ */
+oneway interface IInputSessionWithIdCallback {
+ void sessionCreated(IInputMethodSession session, int id);
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/widget/GridLayoutManager.java b/core/java/com/android/internal/widget/GridLayoutManager.java
index 09e6a99..3873e3b 100644
--- a/core/java/com/android/internal/widget/GridLayoutManager.java
+++ b/core/java/com/android/internal/widget/GridLayoutManager.java
@@ -29,7 +29,7 @@
/**
* Note: This GridLayoutManager widget may lack of latest fix because it is ported from
- * oc-dr1-release version of android.support.v7.widget.GridLayoutManager due to compatibility
+ * oc-dr1-release version of androidx.gridlayout.widget.GridLayoutManager due to compatibility
* concern with other internal widgets, like {@link RecyclerView} and {@link LinearLayoutManager},
* and is merely used for {@link com.android.internal.app.ChooserActivity}.
*
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index c9dc6b6..1e11c6d 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -26,6 +26,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.PropertyInvalidatedCache;
import android.app.admin.DevicePolicyManager;
import android.app.admin.PasswordMetrics;
import android.app.trust.IStrongAuthTracker;
@@ -941,17 +942,53 @@
}
/**
+ * Retrieve the credential type of a user.
+ */
+ private final PropertyInvalidatedCache.QueryHandler<Integer, Integer> mCredentialTypeQuery =
+ new PropertyInvalidatedCache.QueryHandler<>() {
+ @Override
+ public Integer apply(Integer userHandle) {
+ try {
+ return getLockSettings().getCredentialType(userHandle);
+ } catch (RemoteException re) {
+ Log.e(TAG, "failed to get credential type", re);
+ return CREDENTIAL_TYPE_NONE;
+ }
+ }
+ @Override
+ public boolean shouldBypassCache(Integer userHandle) {
+ return userHandle == USER_FRP;
+ }
+ };
+
+ /**
+ * The API that is cached.
+ */
+ private final static String CREDENTIAL_TYPE_API = "getCredentialType";
+
+ /**
+ * Cache the credential type of a user.
+ */
+ private final PropertyInvalidatedCache<Integer, Integer> mCredentialTypeCache =
+ new PropertyInvalidatedCache<>(4, PropertyInvalidatedCache.MODULE_SYSTEM,
+ CREDENTIAL_TYPE_API, CREDENTIAL_TYPE_API, mCredentialTypeQuery);
+
+ /**
+ * Invalidate the credential cache
+ * @hide
+ */
+ public final static void invalidateCredentialTypeCache() {
+ PropertyInvalidatedCache.invalidateCache(PropertyInvalidatedCache.MODULE_SYSTEM,
+ CREDENTIAL_TYPE_API);
+ }
+
+ /**
* Returns the credential type of the user, can be one of {@link #CREDENTIAL_TYPE_NONE},
* {@link #CREDENTIAL_TYPE_PATTERN}, {@link #CREDENTIAL_TYPE_PIN} and
* {@link #CREDENTIAL_TYPE_PASSWORD}
*/
public @CredentialType int getCredentialTypeForUser(int userHandle) {
- try {
- return getLockSettings().getCredentialType(userHandle);
- } catch (RemoteException re) {
- Log.e(TAG, "failed to get credential type", re);
- return CREDENTIAL_TYPE_NONE;
- }
+ return mCredentialTypeCache.query(userHandle);
}
/**
diff --git a/core/java/com/android/internal/widget/PagerAdapter.java b/core/java/com/android/internal/widget/PagerAdapter.java
index 910a720..c595f5c 100644
--- a/core/java/com/android/internal/widget/PagerAdapter.java
+++ b/core/java/com/android/internal/widget/PagerAdapter.java
@@ -24,10 +24,10 @@
/**
* Base class providing the adapter to populate pages inside of
- * a {@link android.support.v4.view.ViewPager}. You will most likely want to use a more
+ * a {@link androidx.viewpager.view.ViewPager}. You will most likely want to use a more
* specific implementation of this, such as
- * {@link android.support.v4.app.FragmentPagerAdapter} or
- * {@link android.support.v4.app.FragmentStatePagerAdapter}.
+ * {@link androidx.fragment.app.FragmentPagerAdapter} or
+ * {@link androidx.fragment.app.FragmentStatePagerAdapter}.
*
* <p>When you implement a PagerAdapter, you must override the following methods
* at minimum:</p>
diff --git a/core/java/com/android/internal/widget/RecyclerView.java b/core/java/com/android/internal/widget/RecyclerView.java
index be15a9b..e27557a 100644
--- a/core/java/com/android/internal/widget/RecyclerView.java
+++ b/core/java/com/android/internal/widget/RecyclerView.java
@@ -1299,7 +1299,7 @@
* Recycled view pools allow multiple RecyclerViews to share a common pool of scrap views.
* This can be useful if you have multiple RecyclerViews with adapters that use the same
* view types, for example if you have several data sets with the same kinds of item views
- * displayed by a {@link android.support.v4.view.ViewPager ViewPager}.
+ * displayed by a {@link androidx.viewpager.view.ViewPager ViewPager}.
*
* @param pool Pool to set. If this parameter is null a new pool will be created and used.
*/
@@ -9764,13 +9764,13 @@
* Some general properties that a LayoutManager may want to use.
*/
public static class Properties {
- /** @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_android_orientation */
+ /** @attr ref androidx.recyclerview.R.styleable#RecyclerView_android_orientation */
public int orientation;
- /** @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_spanCount */
+ /** @attr ref androidx.recyclerview.R.styleable#RecyclerView_spanCount */
public int spanCount;
- /** @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_reverseLayout */
+ /** @attr ref androidx.recyclerview.R.styleable#RecyclerView_reverseLayout */
public boolean reverseLayout;
- /** @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_stackFromEnd */
+ /** @attr ref androidx.recyclerview.R.styleable#RecyclerView_stackFromEnd */
public boolean stackFromEnd;
}
}
diff --git a/core/java/com/android/internal/widget/SubtitleView.java b/core/java/com/android/internal/widget/SubtitleView.java
index 21e63c5..4d6151d 100644
--- a/core/java/com/android/internal/widget/SubtitleView.java
+++ b/core/java/com/android/internal/widget/SubtitleView.java
@@ -115,6 +115,7 @@
break;
}
}
+ a.recycle();
// Set up density-dependent properties.
// TODO: Move these to a default style.
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 955f46b..63b704c 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -252,7 +252,6 @@
"libandroid_net",
"libandroidicu",
"libbattery",
- "libbpf_android",
"libnetdutils",
"libmemtrack",
"libandroidfw",
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index 24c0d2a..2a4f812 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -67,6 +67,7 @@
### 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_app_admin_SecurityLog.cpp b/core/jni/android_app_admin_SecurityLog.cpp
index e5a13db..d197edc 100644
--- a/core/jni/android_app_admin_SecurityLog.cpp
+++ b/core/jni/android_app_admin_SecurityLog.cpp
@@ -85,10 +85,6 @@
(void*) android_app_admin_SecurityLog_isLoggingEnabled
},
{ "writeEvent",
- "(ILjava/lang/String;)I",
- (void*) SLog::writeEventString
- },
- { "writeEvent",
"(I[Ljava/lang/Object;)I",
(void*) SLog::writeEventArray
},
diff --git a/core/jni/android_graphics_BLASTBufferQueue.cpp b/core/jni/android_graphics_BLASTBufferQueue.cpp
index 55f1369..4f13a9c 100644
--- a/core/jni/android_graphics_BLASTBufferQueue.cpp
+++ b/core/jni/android_graphics_BLASTBufferQueue.cpp
@@ -30,6 +30,11 @@
namespace android {
+static struct {
+ jclass clazz;
+ jmethodID ctor;
+} gTransactionClassInfo;
+
static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring jName) {
ScopedUtfChars name(env, jName);
sp<BLASTBufferQueue> queue = new BLASTBufferQueue(name.c_str());
@@ -86,6 +91,14 @@
return queue->isSameSurfaceControl(reinterpret_cast<SurfaceControl*>(surfaceControl));
}
+static jobject nativeGatherPendingTransactions(JNIEnv* env, jclass clazz, jlong ptr,
+ jlong frameNum) {
+ sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
+ SurfaceComposerClient::Transaction* transaction = queue->gatherPendingTransactions(frameNum);
+ return env->NewObject(gTransactionClassInfo.clazz, gTransactionClassInfo.ctor,
+ reinterpret_cast<jlong>(transaction));
+}
+
static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
// clang-format off
@@ -98,6 +111,7 @@
{"nativeGetLastAcquiredFrameNum", "(J)J", (void*)nativeGetLastAcquiredFrameNum},
{"nativeApplyPendingTransactions", "(JJ)V", (void*)nativeApplyPendingTransactions},
{"nativeIsSameSurfaceControl", "(JJ)Z", (void*)nativeIsSameSurfaceControl},
+ {"nativeGatherPendingTransactions", "(JJ)Landroid/view/SurfaceControl$Transaction;", (void*)nativeGatherPendingTransactions}
// clang-format on
};
@@ -105,6 +119,11 @@
int res = jniRegisterNativeMethods(env, "android/graphics/BLASTBufferQueue",
gMethods, NELEM(gMethods));
LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
+
+ jclass transactionClazz = FindClassOrDie(env, "android/view/SurfaceControl$Transaction");
+ gTransactionClassInfo.clazz = MakeGlobalRefOrDie(env, transactionClazz);
+ gTransactionClassInfo.ctor =
+ GetMethodIDOrDie(env, gTransactionClassInfo.clazz, "<init>", "(J)V");
return 0;
}
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 2bec733..dc55c05 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -2476,37 +2476,47 @@
return 4000; // SAMPLE_RATE_HZ_MIN (for API)
}
-static jint
-android_media_AudioSystem_setAssistantUid(JNIEnv *env, jobject thiz, jint uid)
-{
- status_t status = AudioSystem::setAssistantUid(uid);
+static std::vector<uid_t> convertJIntArrayToUidVector(JNIEnv *env, jintArray jArray) {
+ std::vector<uid_t> nativeVector;
+ if (jArray != nullptr) {
+ jsize len = env->GetArrayLength(jArray);
+
+ if (len > 0) {
+ int *nativeArray = nullptr;
+ nativeArray = env->GetIntArrayElements(jArray, 0);
+ if (nativeArray != nullptr) {
+ for (size_t i = 0; i < len; i++) {
+ nativeVector.push_back(nativeArray[i]);
+ }
+ env->ReleaseIntArrayElements(jArray, nativeArray, 0);
+ }
+ }
+ }
+ return nativeVector;
+}
+
+static jint android_media_AudioSystem_setAssistantServicesUids(JNIEnv *env, jobject thiz,
+ jintArray uids) {
+ std::vector<uid_t> nativeUidsVector = convertJIntArrayToUidVector(env, uids);
+
+ status_t status = AudioSystem::setAssistantServicesUids(nativeUidsVector);
+
return (jint)nativeToJavaStatus(status);
}
-static jint android_media_AudioSystem_setHotwordDetectionServiceUid(JNIEnv *env, jobject thiz,
- jint uid) {
- status_t status = AudioSystem::setHotwordDetectionServiceUid(uid);
+static jint android_media_AudioSystem_setActiveAssistantServicesUids(JNIEnv *env, jobject thiz,
+ jintArray activeUids) {
+ std::vector<uid_t> nativeActiveUidsVector = convertJIntArrayToUidVector(env, activeUids);
+
+ status_t status = AudioSystem::setActiveAssistantServicesUids(nativeActiveUidsVector);
+
return (jint)nativeToJavaStatus(status);
}
static jint
android_media_AudioSystem_setA11yServicesUids(JNIEnv *env, jobject thiz, jintArray uids) {
- std::vector<uid_t> nativeUidsVector;
+ std::vector<uid_t> nativeUidsVector = convertJIntArrayToUidVector(env, uids);
- if (uids != nullptr) {
- jsize len = env->GetArrayLength(uids);
-
- if (len > 0) {
- int *nativeUids = nullptr;
- nativeUids = env->GetIntArrayElements(uids, 0);
- if (nativeUids != nullptr) {
- for (size_t i = 0; i < len; i++) {
- nativeUidsVector.push_back(nativeUids[i]);
- }
- env->ReleaseIntArrayElements(uids, nativeUids, 0);
- }
- }
- }
status_t status = AudioSystem::setA11yServicesUids(nativeUidsVector);
return (jint)nativeToJavaStatus(status);
}
@@ -3000,9 +3010,10 @@
(void *)android_media_AudioSystem_getReportedSurroundFormats},
{"setSurroundFormatEnabled", "(IZ)I",
(void *)android_media_AudioSystem_setSurroundFormatEnabled},
- {"setAssistantUid", "(I)I", (void *)android_media_AudioSystem_setAssistantUid},
- {"setHotwordDetectionServiceUid", "(I)I",
- (void *)android_media_AudioSystem_setHotwordDetectionServiceUid},
+ {"setAssistantServicesUids", "([I)I",
+ (void *)android_media_AudioSystem_setAssistantServicesUids},
+ {"setActiveAssistantServicesUids", "([I)I",
+ (void *)android_media_AudioSystem_setActiveAssistantServicesUids},
{"setA11yServicesUids", "([I)I", (void *)android_media_AudioSystem_setA11yServicesUids},
{"isHapticPlaybackSupported", "()Z",
(void *)android_media_AudioSystem_isHapticPlaybackSupported},
diff --git a/core/jni/android_os_HwRemoteBinder.cpp b/core/jni/android_os_HwRemoteBinder.cpp
index 3af55fe..d2d7213 100644
--- a/core/jni/android_os_HwRemoteBinder.cpp
+++ b/core/jni/android_os_HwRemoteBinder.cpp
@@ -81,27 +81,37 @@
void binderDied(const wp<hardware::IBinder>& who)
{
- if (mObject != NULL) {
- JNIEnv* env = javavm_to_jnienv(mVM);
+ JNIEnv* env = javavm_to_jnienv(mVM);
- env->CallStaticVoidMethod(gProxyOffsets.proxy_class, gProxyOffsets.sendDeathNotice, mObject, mCookie);
+ // 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;
+
+ 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 @@
}
}
- bool matches(jobject obj) {
+ bool matchesLocked(jobject obj) {
bool result;
JNIEnv* env = javavm_to_jnienv(mVM);
@@ -129,7 +139,7 @@
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 @@
AutoMutex _l(mLock);
for (const sp<HwBinderDeathRecipient>& deathRecipient : mList) {
- deathRecipient->warnIfStillLive();
+ deathRecipient->warnIfStillLiveLocked();
}
}
@@ -201,7 +211,7 @@
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_util_Process.cpp b/core/jni/android_util_Process.cpp
index a6fbf09..7c67cbc 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -235,7 +235,9 @@
void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jint grp)
{
ALOGV("%s pid=%d grp=%" PRId32, __func__, pid, grp);
+ DIR *d;
char proc_path[255];
+ struct dirent *de;
if (!verifyGroup(env, grp)) {
return;
@@ -275,8 +277,84 @@
}
}
- if (!SetProcessProfilesCached(0, pid, {get_cpuset_policy_profile_name((SchedPolicy)grp)}))
- signalExceptionForGroupError(env, errno ? errno : EPERM, pid);
+ sprintf(proc_path, "/proc/%d/task", pid);
+ if (!(d = opendir(proc_path))) {
+ // If the process exited on us, don't generate an exception
+ if (errno != ENOENT)
+ signalExceptionForGroupError(env, errno, pid);
+ return;
+ }
+
+ while ((de = readdir(d))) {
+ int t_pid;
+ int t_pri;
+ std::string taskprofile;
+
+ if (de->d_name[0] == '.')
+ continue;
+ t_pid = atoi(de->d_name);
+
+ if (!t_pid) {
+ ALOGE("Error getting pid for '%s'\n", de->d_name);
+ continue;
+ }
+
+ t_pri = getpriority(PRIO_PROCESS, t_pid);
+
+ if (t_pri <= ANDROID_PRIORITY_AUDIO) {
+ int scheduler = sched_getscheduler(t_pid) & ~SCHED_RESET_ON_FORK;
+ if ((scheduler == SCHED_FIFO) || (scheduler == SCHED_RR)) {
+ // This task wants to stay in its current audio group so it can keep its budget
+ // don't update its cpuset or cgroup
+ continue;
+ }
+ }
+
+ errno = 0;
+ // grp == SP_BACKGROUND. Set background cpuset policy profile for all threads.
+ if (grp == SP_BACKGROUND) {
+ if (!SetTaskProfiles(t_pid, {"CPUSET_SP_BACKGROUND"}, true)) {
+ signalExceptionForGroupError(env, errno ? errno : EPERM, t_pid);
+ break;
+ }
+ continue;
+ }
+
+ // grp != SP_BACKGROUND. Only change the cpuset cgroup for low priority thread, so it could
+ // preserve it sched policy profile setting.
+ if (t_pri >= ANDROID_PRIORITY_BACKGROUND) {
+ switch (grp) {
+ case SP_SYSTEM:
+ taskprofile = "ServiceCapacityLow";
+ break;
+ case SP_RESTRICTED:
+ taskprofile = "ServiceCapacityRestricted";
+ break;
+ case SP_FOREGROUND:
+ case SP_AUDIO_APP:
+ case SP_AUDIO_SYS:
+ taskprofile = "ProcessCapacityHigh";
+ break;
+ case SP_TOP_APP:
+ taskprofile = "ProcessCapacityMax";
+ break;
+ default:
+ taskprofile = "ProcessCapacityNormal";
+ break;
+ }
+ if (!SetTaskProfiles(t_pid, {taskprofile}, true)) {
+ signalExceptionForGroupError(env, errno ? errno : EPERM, t_pid);
+ break;
+ }
+ // Change the cpuset policy profile for non-low priority thread according to the grp
+ } else {
+ if (!SetTaskProfiles(t_pid, {get_cpuset_policy_profile_name((SchedPolicy)grp)}, true)) {
+ signalExceptionForGroupError(env, errno ? errno : EPERM, t_pid);
+ break;
+ }
+ }
+ }
+ closedir(d);
}
void android_os_Process_setProcessFrozen(
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 2488b57..336161c 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -245,6 +245,13 @@
jmethodID onTransactionCommitted;
} gTransactionCommittedListenerClassInfo;
+static struct {
+ jclass clazz;
+ jmethodID ctor;
+ jfieldID format;
+ jfieldID alphaInterpretation;
+} gDisplayDecorationSupportInfo;
+
class JNamedColorSpace {
public:
// ColorSpace.Named.SRGB.ordinal() = 0;
@@ -1792,13 +1799,29 @@
client->setGlobalShadowSettings(ambientColor, spotColor, lightPosY, lightPosZ, lightRadius);
}
-static jboolean nativeGetDisplayDecorationSupport(JNIEnv* env, jclass clazz,
- jobject displayTokenObject) {
+static jobject nativeGetDisplayDecorationSupport(JNIEnv* env, jclass clazz,
+ jobject displayTokenObject) {
sp<IBinder> displayToken(ibinderForJavaObject(env, displayTokenObject));
if (displayToken == nullptr) {
- return JNI_FALSE;
+ return nullptr;
}
- return static_cast<jboolean>(SurfaceComposerClient::getDisplayDecorationSupport(displayToken));
+ const auto support = SurfaceComposerClient::getDisplayDecorationSupport(displayToken);
+ if (!support) {
+ return nullptr;
+ }
+
+ jobject jDisplayDecorationSupport =
+ env->NewObject(gDisplayDecorationSupportInfo.clazz, gDisplayDecorationSupportInfo.ctor);
+ if (jDisplayDecorationSupport == nullptr) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", nullptr);
+ return nullptr;
+ }
+
+ env->SetIntField(jDisplayDecorationSupport, gDisplayDecorationSupportInfo.format,
+ static_cast<jint>(support.value().format));
+ env->SetIntField(jDisplayDecorationSupport, gDisplayDecorationSupportInfo.alphaInterpretation,
+ static_cast<jint>(support.value().alphaInterpretation));
+ return jDisplayDecorationSupport;
}
static jlong nativeGetHandle(JNIEnv* env, jclass clazz, jlong nativeObject) {
@@ -2131,7 +2154,8 @@
(void*)nativeMirrorSurface },
{"nativeSetGlobalShadowSettings", "([F[FFFF)V",
(void*)nativeSetGlobalShadowSettings },
- {"nativeGetDisplayDecorationSupport", "(Landroid/os/IBinder;)Z",
+ {"nativeGetDisplayDecorationSupport",
+ "(Landroid/os/IBinder;)Landroid/hardware/graphics/common/DisplayDecorationSupport;",
(void*)nativeGetDisplayDecorationSupport},
{"nativeGetHandle", "(J)J",
(void*)nativeGetHandle },
@@ -2390,6 +2414,17 @@
gTransactionCommittedListenerClassInfo.onTransactionCommitted =
GetMethodIDOrDie(env, transactionCommittedListenerClazz, "onTransactionCommitted",
"()V");
+
+ jclass displayDecorationSupportClazz =
+ FindClassOrDie(env, "android/hardware/graphics/common/DisplayDecorationSupport");
+ gDisplayDecorationSupportInfo.clazz = MakeGlobalRefOrDie(env, displayDecorationSupportClazz);
+ gDisplayDecorationSupportInfo.ctor =
+ GetMethodIDOrDie(env, displayDecorationSupportClazz, "<init>", "()V");
+ gDisplayDecorationSupportInfo.format =
+ GetFieldIDOrDie(env, displayDecorationSupportClazz, "format", "I");
+ gDisplayDecorationSupportInfo.alphaInterpretation =
+ GetFieldIDOrDie(env, displayDecorationSupportClazz, "alphaInterpretation", "I");
+
return err;
}
diff --git a/core/proto/android/content/package_item_info.proto b/core/proto/android/content/package_item_info.proto
index 5c6116a..279a5d0 100644
--- a/core/proto/android/content/package_item_info.proto
+++ b/core/proto/android/content/package_item_info.proto
@@ -115,4 +115,5 @@
}
optional Detail detail = 17;
repeated string overlay_paths = 18;
+ repeated string known_activity_embedding_certs = 19;
}
diff --git a/core/proto/android/internal/binder_latency.proto b/core/proto/android/internal/binder_latency.proto
index 8b11f5b..edd9b71 100644
--- a/core/proto/android/internal/binder_latency.proto
+++ b/core/proto/android/internal/binder_latency.proto
@@ -35,6 +35,7 @@
SYSTEM_SERVER = 1;
TELEPHONY = 2;
BLUETOOTH = 3;
+ WIFI = 4;
}
enum ServiceClassName {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 2736ba63..68c8143 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -199,6 +199,8 @@
<protected-broadcast
android:name="android.bluetooth.headsetclient.profile.action.LAST_VTAG" />
<protected-broadcast
+ android:name="android.bluetooth.headsetclient.profile.action.NETWORK_SERVICE_STATE_CHANGED" />
+ <protected-broadcast
android:name="android.bluetooth.hearingaid.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
android:name="android.bluetooth.hearingaid.profile.action.PLAYING_STATE_CHANGED" />
@@ -721,6 +723,7 @@
<protected-broadcast android:name="android.app.action.DEVICE_POLICY_RESOURCE_UPDATED" />
<protected-broadcast android:name="android.intent.action.SHOW_FOREGROUND_SERVICE_MANAGER" />
<protected-broadcast android:name="android.service.autofill.action.DELAYED_FILL" />
+ <protected-broadcast android:name="android.app.action.PROVISIONING_COMPLETED" />
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
@@ -1895,13 +1898,20 @@
android:label="@string/permlab_changeWifiState"
android:protectionLevel="normal" />
- <!-- @SystemApi @hide Allows applications to enable/disable wifi auto join. This permission
+ <!-- Allows applications to enable/disable wifi auto join. This permission
is used to let OEMs grant their trusted app access to a subset of privileged wifi APIs
to improve wifi performance.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.MANAGE_WIFI_AUTO_JOIN"
android:protectionLevel="signature|privileged" />
+ <!-- Allows applications to get notified when a Wi-Fi interface request cannot
+ be satisfied without tearing down one or more other interfaces, and provide a decision
+ whether to approve the request or reject it.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.MANAGE_WIFI_INTERFACES"
+ android:protectionLevel="signature|privileged" />
+
<!-- @SystemApi @hide Allows apps to create and manage IPsec tunnels.
<p>Only granted to applications that are currently bound by the
system for creating and managing IPsec-based interfaces.
@@ -1933,7 +1943,7 @@
<permission android:name="android.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE"
android:protectionLevel="signature|privileged" />
- <!-- @SystemApi @hide Allows an application to modify any wifi configuration, even if created
+ <!-- Allows an application to modify any wifi configuration, even if created
by another application. Once reconfigured the original creator cannot make any further
modifications.
<p>Not for use by third-party applications. -->
@@ -4400,6 +4410,16 @@
<permission android:name="android.permission.SCHEDULE_EXACT_ALARM"
android:protectionLevel="normal|appop"/>
+ <!-- Allows apps to use exact alarms just like with SCHEDULE_EXACT_ALARM but without needing
+ to request this permission from the user.
+ <p><b>This is only for apps that rely on exact alarms for their core functionality.</b>
+ App stores may enforce policies to audit and review the use of this permission. Any app that
+ requests this but is found to not require exact alarms for its primary function may be
+ removed from the app store.
+ -->
+ <permission android:name="android.permission.USE_EXACT_ALARM"
+ android:protectionLevel="normal"/>
+
<!-- Allows an application to query tablet mode state and monitor changes
in it.
<p>Not for use by third-party applications.
@@ -5897,10 +5917,9 @@
<!-- @SystemApi Allows an application to manage the wallpaper effects
generation service.
- @hide <p>Not for use by third-party applications.</p> -->
+ @hide <p>Not for use by third-party applications.</p> -->
<permission android:name="android.permission.MANAGE_WALLPAPER_EFFECTS_GENERATION"
- android:protectionLevel="signature" />
-
+ android:protectionLevel="signature|role" />
<!-- Allows an app to set the theme overlay in /vendor/overlay
being used.
@@ -6236,7 +6255,10 @@
android:protectionLevel="signature|privileged" />
<!-- Allows an application to read nearby streaming policy. The policy controls
- whether to allow the device to stream its notifications and apps to nearby devices. -->
+ whether to allow the device to stream its notifications and apps to nearby devices.
+ Applications that are not the device owner will need this permission to call
+ {@link android.app.admin.DevicePolicyManager#getNearbyNotificationStreamingPolicy} or
+ {@link android.app.admin.DevicePolicyManager#getNearbyAppStreamingPolicy}. -->
<permission android:name="android.permission.READ_NEARBY_STREAMING_POLICY"
android:protectionLevel="normal" />
@@ -6358,6 +6380,11 @@
<permission android:name="android.permission.TIS_EXTENSION_INTERFACE"
android:protectionLevel="signature|privileged|vendorPrivileged" />
+ <!-- @SystemApi Allows an application to write to the security log buffer in logd.
+ @hide -->
+ <permission android:name="android.permission.WRITE_SECURITY_LOG"
+ android:protectionLevel="signature|privileged" />
+
<!-- Attribution for Geofencing service. -->
<attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/>
<!-- Attribution for Country Detector. -->
diff --git a/core/res/res/anim/popup_enter_material.xml b/core/res/res/anim/popup_enter_material.xml
index 79de26b..ef5b7c0 100644
--- a/core/res/res/anim/popup_enter_material.xml
+++ b/core/res/res/anim/popup_enter_material.xml
@@ -16,7 +16,14 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false" >
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
- android:interpolator="@interpolator/decelerate_cubic"
- android:duration="@android:integer/config_activityShortDur" />
+ <alpha
+ android:fromAlpha="0.0"
+ android:toAlpha="1.0"
+ android:interpolator="@interpolator/standard"
+ android:duration="@android:integer/config_activityDefaultDur" />
+ <translate
+ android:fromYDelta="20dp"
+ android:toYDelta="0"
+ android:interpolator="@interpolator/standard"
+ android:duration="@android:integer/config_activityDefaultDur" />
</set>
diff --git a/core/res/res/anim/popup_exit_material.xml b/core/res/res/anim/popup_exit_material.xml
index 7d7d5c5..1efa702 100644
--- a/core/res/res/anim/popup_exit_material.xml
+++ b/core/res/res/anim/popup_exit_material.xml
@@ -16,7 +16,14 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false" >
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
- android:interpolator="@interpolator/decelerate_cubic"
- android:duration="@android:integer/config_activityShortDur"/>
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="0.0"
+ android:interpolator="@interpolator/standard_accelerate"
+ android:duration="@android:integer/config_activityShortDur" />
+ <translate
+ android:fromYDelta="0"
+ android:toYDelta="-10dp"
+ android:interpolator="@interpolator/standard_accelerate"
+ android:duration="@android:integer/config_activityShortDur" />
</set>
diff --git a/core/res/res/drawable/toast_frame.xml b/core/res/res/drawable/toast_frame.xml
index 44c00c0..a8cdef6 100644
--- a/core/res/res/drawable/toast_frame.xml
+++ b/core/res/res/drawable/toast_frame.xml
@@ -17,7 +17,7 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
- <solid android:color="?android:attr/colorBackground" />
+ <solid android:color="?android:attr/colorSurface" />
<corners android:radius="28dp" />
</shape>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index d2cf1d7..50f6a42 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -304,10 +304,8 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"by jou kalender in te gaan"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS-boodskappe te stuur en te bekyk"</string>
- <!-- no translation found for permgrouplab_storage (9173334109512154196) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (8352226729501080525) -->
- <skip />
+ <string name="permgrouplab_storage" msgid="9173334109512154196">"Lêers en dokumente"</string>
+ <string name="permgroupdesc_storage" msgid="8352226729501080525">"kry toegang tot lêers en dokumente op jou toestel"</string>
<string name="permgrouplab_readMediaAural" msgid="5885210465560755316">"Musiek en ander oudio"</string>
<string name="permgroupdesc_readMediaAural" msgid="1170143315714662822">"kry toegang tot oudiolêers op jou toestel"</string>
<string name="permgrouplab_readMediaVisual" msgid="9137695801926624061">"Foto\'s en video\'s"</string>
@@ -588,8 +586,9 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Voer jou skermslot in om voort te gaan"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Gedeeltelike vingerafdruk is bespeur"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Kon nie vingerafdruk verwerk nie. Probeer asseblief weer."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Maak die sensor skoon"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Hou \'n bietjie langer"</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Maak vingerafdruksensor skoon en probeer weer"</string>
+ <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Maak sensor skoon en probeer weer"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Druk ferm op sensor"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Vinger is te stadig beweer. Probeer asseblief weer."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Probeer \'n ander vingerafdruk"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Te helder"</string>
@@ -597,6 +596,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Verander elke keer die posisie van jou vinger so effens"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"Vingerafdruk word nie herken nie"</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="4709197752023550709">"Druk ferm op sensor"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Vingerafdruk is gestaaf"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Gesig is gestaaf"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Gesig is gestaaf; druk asseblief bevestig"</string>
@@ -1500,7 +1501,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Slaan oor"</string>
<string name="no_matches" msgid="6472699895759164599">"Geen passings nie"</string>
<string name="find_on_page" msgid="5400537367077438198">"Vind op bladsy"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# passing }other{# van {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Klaar"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Vee tans gedeelde berging uit …"</string>
<string name="share" msgid="4157615043345227321">"Deel"</string>
@@ -1928,6 +1930,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Skakel aan"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Program is nie beskikbaar nie"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is nie op die oomblik beskikbaar nie."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> is nie beskikbaar nie"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Jy kan nie nou toegang hiertoe op jou <xliff:g id="DEVICE">%1$s</xliff:g> kry nie. Probeer eerder op jou Android TV-toestel."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Jy kan nie nou toegang hiertoe op jou <xliff:g id="DEVICE">%1$s</xliff:g> kry nie. Probeer eerder op jou tablet."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Jy kan nie nou toegang hiertoe op jou <xliff:g id="DEVICE">%1$s</xliff:g> kry nie. Probeer eerder op jou foon."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Hierdie program is vir \'n ouer weergawe van Android gebou en sal dalk nie behoorlik werk nie. Probeer kyk vir opdaterings, of kontak die ontwikkelaar."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Kyk vir opdatering"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Jy het nuwe boodskappe"</string>
@@ -2017,16 +2023,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"DEΪNSTALLEER"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"MAAK TOG OOP"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Skadelike program is bespeur"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Stelselloglêertoegangsversoek"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Net hierdie keer"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Moenie toelaat nie"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> versoek stelselloglêers vir funksionele ontfouting. Hierdie loglêers bevat dalk inligting wat programme en dienste op jou toestel geskryf het."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Moenie weer wys nie"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wil <xliff:g id="APP_2">%2$s</xliff:g>-skyfies wys"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Wysig"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Oproepe en kennisgewings sal vibreer"</string>
@@ -2089,22 +2090,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Kragdialoog"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Sluitskerm"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skermkiekie"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Kopstuk haak"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Toeganklikheidkortpad op skerm"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Toeganklikheidkortpadkieser op skerm"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Toeganklikheidkortpad"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Maak kennisgewingskerm toe"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"D-paneel op"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"D-paneel af"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"D-paneel links"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"D-paneel regs"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"D-paneel middel"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> se onderskrifbalk."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> is in die BEPERK-groep geplaas"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2120,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Tik om aan te skakel"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Geen werkprogramme nie"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Geen persoonlike programme nie"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Maak <xliff:g id="APP">%s</xliff:g> in jou persoonlike profiel oop?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Maak <xliff:g id="APP">%s</xliff:g> in jou werkprofiel oop?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Gebruik persoonlike blaaier"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Gebruik werkblaaier"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM se netwerkontsluiting-PIN"</string>
@@ -2263,4 +2256,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> werk tans op die agtergrond en gebruik batterykrag. Tik om na te gaan."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> werk al vir \'n lang tyd op die agtergrond. Tik om na te gaan."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Gaan aktiewe programme na"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 240e615..2e6f3e0 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -304,10 +304,8 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"የእርስዎን ቀን መቁጠሪያ ይድረሱበት"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"ኤስኤምኤስ"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"የኤስኤምኤስ መልዕክቶችን ይላኩና ይመልከቱ"</string>
- <!-- no translation found for permgrouplab_storage (9173334109512154196) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (8352226729501080525) -->
- <skip />
+ <string name="permgrouplab_storage" msgid="9173334109512154196">"ፋይሎች እና ሰነዶች"</string>
+ <string name="permgroupdesc_storage" msgid="8352226729501080525">"ፋይሎች እና ሰነዶች ዘንድ በመሳሪያዎ ላይ ይድረሱ"</string>
<string name="permgrouplab_readMediaAural" msgid="5885210465560755316">"ሙዚቃ እና ሌላ ኦዲዮ"</string>
<string name="permgroupdesc_readMediaAural" msgid="1170143315714662822">"በመሳሪያዎ ላይ የድምጽ ፋይሎችን ይድረሱ"</string>
<string name="permgrouplab_readMediaVisual" msgid="9137695801926624061">"ፎቶዎች እና ቪዲዮዎች"</string>
@@ -588,8 +586,9 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"ለመቀጠል የማያ ገጽ ቁልፍዎን ያስገቡ"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"ከፊል የጣት አሻራ ተገኝቷል"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ጣት አሻራን መስራት አልተቻለም። እባክዎ እንደገና ይሞክሩ።"</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"ዳሳሹን ያጽዱ"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"ትንሽ ረዘም ላለ ጊዜ ይያዙ"</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"የጣት አሻራ ዳሳሽን ያጽዱ እና እንደገና ይሞክሩ"</string>
+ <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"ዳሳሹን ያጽዱ እና እንደገና ይሞክሩ"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"ዳሳሹን ጠበቅ አድርገው ይጫኑት"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"ጣት ከልክ በላይ ተንቀራፎ ተንቀሳቅሷል። እባክዎ እንደገና ይሞክሩ።"</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"ሌላ የጣት አሻራ ይሞክሩ"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"በጣም ብርሃናማ"</string>
@@ -597,6 +596,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"በእያንዳንዱ ጊዜ የጣትዎን ቦታ በትንሹ ይለዋውጡ"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"የጣት አሻራ አልታወቀም"</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="4709197752023550709">"ዳሳሹን ጠበቅ አድርገው ይጫኑት"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"የጣት አሻራ ትክክለኛነት ተረጋግጧል"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"ፊት ተረጋግጧል"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"ፊት ተረጋግጧል፣ እባክዎ አረጋግጥን ይጫኑ"</string>
@@ -1500,7 +1501,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"ዝለል"</string>
<string name="no_matches" msgid="6472699895759164599">"ምንም ተመሳሳይ የለም።"</string>
<string name="find_on_page" msgid="5400537367077438198">"በገፅ ላይ አግኝ"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# ተዛማጅ}one{# ከ{total}}other{# ከ{total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"ተከናውኗል"</string>
<string name="progress_erasing" msgid="6891435992721028004">"የተጋራ ማከማቻን በመደምሰስ ላይ…"</string>
<string name="share" msgid="4157615043345227321">"አጋራ"</string>
@@ -1928,6 +1930,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"አብራ"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"መተግበሪያ አይገኝም"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> አሁን አይገኝም።"</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> አይገኝም"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"ይህ በዚህ ጊዜ በእርስዎ <xliff:g id="DEVICE">%1$s</xliff:g> ላይ ሊደረስበት አይችልም። በምትኩ በAndroid TV መሣሪያዎ ላይ ይሞክሩ።"</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"ይህ በዚህ ጊዜ በእርስዎ <xliff:g id="DEVICE">%1$s</xliff:g> ላይ ሊደረስበት አይችልም። በምትኩ በጡባዊዎ ላይ ይሞክሩ።"</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"ይህ በዚህ ጊዜ በእርስዎ <xliff:g id="DEVICE">%1$s</xliff:g> ላይ ሊደረስበት አይችልም። በምትኩ በስልክዎ ላይ ይሞክሩ።"</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ይህ መተግበሪያ ለቆየ የAndroid ስሪት ነው የተገነባው፣ እና በአግባቡ ላይሰራ ይችላል። ዝማኔዎች ካሉ ለመመልከት ይሞክሩ፣ ወይም ደግሞ ገንቢውን ያነጋግሩ።"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"ዝማኔ ካለ አረጋግጥ"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"አዲስ መልዕክቶች አለዎት"</string>
@@ -2017,16 +2023,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"አራግፍ"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"ለማንኛውም ክፈት"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"ጎጂ መተግበሪያ ተገኝቷል"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"የስርዓት ምዝግብ ማስታወሻ መዳረሻ ጥያቄ"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"አሁን ብቻ"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"አትፍቀድ"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ለተግባራዊ ስህተት ማረሚያ የስርዓት ምዝግብ ማስታወሻዎችን ይጠይቃል። እነዚህ ምዝግብ ማስታወሻዎች በመሣሪያዎ ላይ ያሉ መተግበሪያዎች እና አገልግሎቶች የጻፉትን መረጃ ሊይዙ ይችላሉ።"</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"ዳግም አታሳይ"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> የ<xliff:g id="APP_2">%2$s</xliff:g> ቁራጮችን ማሳየት ይፈልጋል"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"አርትዕ"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"ጥሪዎች እና ማሳወቂያዎች ይነዝራሉ"</string>
@@ -2089,22 +2090,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"የኃይል መገናኛ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"የማያ ገጽ ቁልፍ"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ቅጽበታዊ ገጽ እይታ"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"የማዳመጫ መንጠቆ"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"የማያ ገጽ ላይ ተደራሽነት አቋራጭ"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"የማያ ገጽ ላይ ተደራሽነት አቋራጭ መራጭ"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"የተደራሽነት አቋራጭ"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"የማሳወቂያ ጥላን አሰናብት"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"ከDpad በላይ"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"ከDpad በታች"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"ከDpad በስተግራ"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"ከDpad በስተቀኝ"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"የDpad ማዕከል"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"የ<xliff:g id="APP_NAME">%1$s</xliff:g> የሥዕል ገላጭ ጽሑፍ አሞሌ።"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ወደ የRESTRICTED ባልዲ ተከትቷል"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>፦"</string>
@@ -2125,10 +2120,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"ለማብራት መታ ያድርጉ"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"ምንም የሥራ መተግበሪያዎች የሉም"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"ምንም የግል መተግበሪያዎች የሉም"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"<xliff:g id="APP">%s</xliff:g> በግል መገለጫዎ ውስጥ ይከፈት?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"<xliff:g id="APP">%s</xliff:g> በስራ መገለጫዎ ውስጥ ይከፈት?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"የግል አሳሽ ተጠቀም"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"የስራ አሳሽ ተጠቀም"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"የሲም አውታረ መረብ መክፈቻ ፒን"</string>
@@ -2263,4 +2256,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> ከበስተጀርባ በማሄድ ላይ ነው እና ባትሪ እየጨረሰ ነው። ለመገምገም መታ ያድርጉ።"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> ከበስተጀርባ ለረጅም ጊዜ በማሄድ ላይ ነው። ለመገምገም መታ ያድርጉ።"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"ንቁ መተግበሪያዎችን ይፈትሹ"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 05afc30..e2234e4 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -592,8 +592,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"أدخِل قفل الشاشة للمتابعة"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"تم اكتشاف بصمة إصبع جزئية."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"تعذرت معالجة بصمة الإصبع. يُرجى إعادة المحاولة."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"عليك تنظيف جهاز الاستشعار."</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"ثبِّت إصبعك أطول من ذلك قليلاً."</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"تم تحريك الإصبع ببطء شديد. يُرجى إعادة المحاولة."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"يمكنك تجربة بصمة إصبع أخرى."</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"الصورة ساطعة للغاية."</string>
@@ -601,6 +605,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"غيِّر موضع إصبعك قليلاً في كل مرة."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"تم مصادقة بصمة الإصبع"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"تمّت مصادقة الوجه"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"تمّت مصادقة الوجه، يُرجى الضغط على \"تأكيد\"."</string>
@@ -1504,7 +1512,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"التخطي"</string>
<string name="no_matches" msgid="6472699895759164599">"ليس هناك أي مطابقات"</string>
<string name="find_on_page" msgid="5400537367077438198">"بحث في الصفحة"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{مطابقة واحدة}zero{# من إجمالي {total}}two{# من إجمالي {total}}few{# من إجمالي {total}}many{# من إجمالي {total}}other{# من إجمالي {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"تم"</string>
<string name="progress_erasing" msgid="6891435992721028004">"جارٍ محو بيانات مساحة التخزين المشتركة…"</string>
<string name="share" msgid="4157615043345227321">"مشاركة"</string>
@@ -1932,6 +1941,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"تفعيل"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"التطبيق غير متاح"</string>
<string name="app_blocked_message" msgid="542972921087873023">"تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> غير متاح الآن."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"تطبيق <xliff:g id="ACTIVITY">%1$s</xliff:g> غير متاح"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"لا يمكن الوصول إلى هذا التطبيق على <xliff:g id="DEVICE">%1$s</xliff:g> في الوقت الحالي. حاوِل الوصول إليه على جهاز Android TV بدلاً من ذلك."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"لا يمكن الوصول إلى هذا التطبيق على <xliff:g id="DEVICE">%1$s</xliff:g> في الوقت الحالي. حاوِل الوصول إليه على جهازك اللوحي بدلاً من ذلك."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"لا يمكن الوصول إلى هذا التطبيق على <xliff:g id="DEVICE">%1$s</xliff:g> في الوقت الحالي. حاوِل الوصول إليه على هاتفك بدلاً من ذلك."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"تمّ إنشاء هذا التطبيق لإصدار قديم من Android وقد لا يعمل بشكل صحيح. جرِّب البحث عن تحديثات أو الاتصال بمطوّر البرامج."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"البحث عن تحديث"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"لديك رسائل جديدة"</string>
@@ -2021,16 +2034,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"إلغاء التثبيت"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"الفتح على أي حال"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"تم العثور على تطبيق ضار"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"طلب الوصول إلى سجّل النظام"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"هذه المرَّة فقط"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"عدم السماح"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"يطلب تطبيق <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> سجّلات النظام لعملية تصحيح أخطاء وظيفية. قد تحتوي هذه السجّلات على معلومات تمت كتابتها من خلال التطبيقات والخدمات المتاحة على جهازك."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"عدم الإظهار مرة أخرى"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"يريد تطبيق <xliff:g id="APP_0">%1$s</xliff:g> عرض شرائح تطبيق <xliff:g id="APP_2">%2$s</xliff:g>."</string>
<string name="screenshot_edit" msgid="7408934887203689207">"تعديل"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"سيهتز الهاتف عند تلقّي المكالمات والإشعارات."</string>
@@ -2093,22 +2101,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"مربّع حوار الطاقة"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"شاشة القفل"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"لقطة شاشة"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"خطّاف تعليق سمّاعة الرأس"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"اختصار أدوات تمكين الوصول على الشاشة"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"أداة اختيار اختصارات أدوات تمكين الوصول على الشاشة"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"اختصارات أدوات تمكين الوصول"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"إغلاق مركز الإشعارات"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"زرّ الاتجاه للأعلى"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"زرّ الاتجاه للأسفل"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"زرّ الاتجاه لليسار"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"زرّ الاتجاه لليمين"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"الزرّ المركزي"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"شريط الشرح لتطبيق <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"تم وضع <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> في الحزمة \"محظورة\"."</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2129,10 +2131,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"انقر لتفعيل الميزة"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"ما مِن تطبيقات عمل."</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"ما مِن تطبيقات شخصية."</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"هل تريد فتح <xliff:g id="APP">%s</xliff:g> في ملفك الشخصي؟"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"هل تريد فتح <xliff:g id="APP">%s</xliff:g> في ملفك الشخصي للعمل؟"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"استخدام المتصفّح الشخصي"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"استخدام متصفّح العمل"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"رقم التعريف الشخصي لإلغاء قفل شبكة شريحة SIM"</string>
@@ -2267,4 +2267,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"يعمل تطبيق <xliff:g id="APP">%1$s</xliff:g> في الخلفية ويستنفد شحن البطارية. انقر لمراجعة الإعدادات."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"يعمل تطبيق <xliff:g id="APP">%1$s</xliff:g> في الخلفية لفترة طويلة. انقر لمراجعة الإعدادات."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"التحقّق من التطبيقات النشطة"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 8828ed5..90f6fca 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -304,10 +304,8 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"আপোনাৰ কেলেণ্ডাৰ ব্যৱহাৰ কৰিব পাৰে"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"এছএমএছ"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"এছএমএছ বার্তা পঠিয়াব আৰু চাব পাৰে"</string>
- <!-- no translation found for permgrouplab_storage (9173334109512154196) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (8352226729501080525) -->
- <skip />
+ <string name="permgrouplab_storage" msgid="9173334109512154196">"ফাইল আৰু নথি"</string>
+ <string name="permgroupdesc_storage" msgid="8352226729501080525">"আপোনাৰ ডিভাইচত থকা ফাইল আৰু নথি এক্সেছ কৰে"</string>
<string name="permgrouplab_readMediaAural" msgid="5885210465560755316">"সংগীত আৰু অন্যান্য অডিঅ’"</string>
<string name="permgroupdesc_readMediaAural" msgid="1170143315714662822">"আপোনাৰ ডিভাইচত অডিঅ’ ফাইলসমূহ এক্সেছ কৰক"</string>
<string name="permgrouplab_readMediaVisual" msgid="9137695801926624061">"ফট’ আৰু ভিডিঅ’"</string>
@@ -588,8 +586,9 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"অব্যাহত ৰাখিবলৈ আপোনাৰ স্ক্ৰীন লক দিয়ক"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"আংশিক ফিংগাৰপ্ৰিণ্ট চিনাক্ত কৰা হৈছে"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ফিগাৰপ্ৰিণ্টৰ প্ৰক্ৰিয়া সম্পাদন কৰিবপৰা নগ\'ল। অনুগ্ৰহ কৰি আকৌ চেষ্টা কৰক৷"</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"ছেন্সৰটো চাফা কৰক"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"আৰু অলপ সময় ধৰি ৰাখক"</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"ফিংগাৰপ্ৰিণ্ট ছেন্সৰটো মচি পুনৰ চেষ্টা কৰক"</string>
+ <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"ছেন্সৰটো মচি পুনৰ চেষ্টা কৰক"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"ছেন্সৰটোত ভালকৈ টিপক"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"আঙুলিৰ গতি অতি মন্থৰ আছিল। অনুগ্ৰহ কৰি আকৌ চেষ্টা কৰক৷"</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"অন্য এটা ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰি চাওক"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"অতি উজ্জ্বল"</string>
@@ -597,6 +596,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"প্ৰতিবাৰতে আপোনাৰ আঙুলিটোৰ স্থান সামান্য সলনি কৰক"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"ফিংগাৰপ্ৰিণ্ট চিনাক্ত কৰিব পৰা নাই"</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="4709197752023550709">"ছেন্সৰটোত ভালকৈ টিপক"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ফিংগাৰপ্ৰিণ্টৰ সত্যাপন কৰা হ’ল"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"মুখমণ্ডলৰ বিশ্বাসযোগ্যতা প্ৰমাণীকৰণ কৰা হ’ল"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"মুখমণ্ডলৰ বিশ্বাসযোগ্যতা প্ৰমাণীকৰণ কৰা হ’ল, অনুগ্ৰহ কৰি ‘নিশ্চিত কৰক’ বুটামটো টিপক"</string>
@@ -1500,7 +1501,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"এৰি যাওক"</string>
<string name="no_matches" msgid="6472699895759164599">"কোনো মিল নাই"</string>
<string name="find_on_page" msgid="5400537367077438198">"পৃষ্ঠাত বিচাৰক"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# মিল{total}ৰ }one{# {total}ৰ }other{# }} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"সম্পন্ন হ’ল"</string>
<string name="progress_erasing" msgid="6891435992721028004">"শ্বেয়াৰ কৰি থোৱা ষ্ট’ৰেজ মচি থকা হৈছে…"</string>
<string name="share" msgid="4157615043345227321">"শ্বেয়াৰ কৰক"</string>
@@ -1928,6 +1930,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"অন কৰক"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"এপ্টো উপলব্ধ নহয়"</string>
<string name="app_blocked_message" msgid="542972921087873023">"এই মুহূৰ্তত <xliff:g id="APP_NAME">%1$s</xliff:g> উপলব্ধ নহয়।"</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> উপলব্ধ নহয়"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"এইটো এতিয়া আপোনাৰ <xliff:g id="DEVICE">%1$s</xliff:g>ত এক্সেছ কৰিব পৰা নাযায়। তাৰ পৰিৱৰ্তে আপোনাৰ Android TVত চেষ্টা কৰি চাওক।"</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"এইটো এতিয়া আপোনাৰ <xliff:g id="DEVICE">%1$s</xliff:g>ত এক্সেছ কৰিব পৰা নাযায়। তাৰ পৰিৱৰ্তে আপোনাৰ টেবলেটটোত চেষ্টা কৰি চাওক।"</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"এইটো এতিয়া আপোনাৰ <xliff:g id="DEVICE">%1$s</xliff:g>ত এক্সেছ কৰিব পৰা নাযায়। তাৰ পৰিৱৰ্তে আপোনাৰ ফ’নত চেষ্টা কৰি চাওক।"</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"এই এপটো Androidৰ এটা পুৰণা সংস্কৰণৰ বাবে প্ৰস্তুত কৰা হৈছিল, আৰু ই বিচৰাধৰণে কাম নকৰিবও পাৰে। ইয়াৰ আপডে’ট আছে নেকি চাওক, বা বিকাশকৰ্তাৰ সৈতে যোগাযোগ কৰক।"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"আপডে’ট আছে নেকি চাওক"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"আপুনি নতুন বার্তা লাভ কৰিছে"</string>
@@ -2017,16 +2023,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"আনইনষ্টল কৰক"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"যিহ\'লেও খোলক"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"ক্ষতিকাৰক এপ্ চিনাক্ত কৰা হৈছে"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"ছিষ্টেমৰ লগ এক্সেছ কৰাৰ অনুৰোধ"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"কেৱল এইবাৰৰ বাবে"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"অনুমতি নিদিব"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>এ কাৰ্যক্ষম ডিবাগিঙৰ বাবে ছিষ্টেমৰ লগসমূহ অনুৰোধ কৰে। এই লগসমূহত আপোনাৰ ডিভাইচত থকা এপ্ আৰু সেৱাসমূহে লিখা তথ্য থাকিব পাৰে।"</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"পুনৰ নেদেখুৱাব"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g>এ <xliff:g id="APP_2">%2$s</xliff:g>ৰ অংশ দেখুওৱাব খুজিছে"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"সম্পাদনা কৰক"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"কল আৰু জাননীসমূহে কম্পন কৰিব"</string>
@@ -2089,22 +2090,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"পাৱাৰ ডায়লগ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"লক স্ক্ৰীন"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"স্ক্ৰীণশ্বট"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"হেডছেটৰ হুক"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"স্ক্ৰীনত সাধ্য সুবিধাৰ শ্বৰ্টকাট"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"স্ক্ৰীনত সাধ্য সুবিধাসমূহৰ শ্বৰ্টকাট বাছনি কৰাৰ সুবিধা"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"সাধ্য সুবিধাৰ শ্বৰ্টকাট"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"জাননী পেনেল অগ্ৰাহ্য কৰক"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"ডিপেডৰ ওপৰফালৰ বুটাম"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"ডিপেডৰ তলফালৰ বুটাম"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"ডিপেডৰ বাওঁফালৰ বুটাম"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"ডিপেডৰ সোঁফালৰ বুটাম"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"ডিপেডৰ মাজৰ বুটাম"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ কেপশ্বন বাৰ।"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>ক সীমাবদ্ধ বাকেটটোত ৰখা হৈছে"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2120,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"অন কৰিবলৈ টিপক"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"কোনো কৰ্মস্থানৰ এপ্ নাই"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"কোনো ব্যক্তিগত এপ্ নাই"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"আপোনাৰ ব্যক্তিগত প্ৰ’ফাইলত <xliff:g id="APP">%s</xliff:g> খুলিবনে?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"আপোনাৰ কর্মস্থানৰ প্ৰ\'ফাইলত <xliff:g id="APP">%s</xliff:g> খুলিবনে?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"ব্যক্তিগত ব্ৰাউজাৰ ব্যৱহাৰ কৰক"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"কৰ্মস্থানৰ ব্ৰাউজাৰ ব্যৱহাৰ কৰক"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"ছিম নেটৱৰ্ক আনলক কৰা পিন"</string>
@@ -2263,4 +2256,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> নেপথ্যত চলি আছে আৰু অত্যধিক বেটাৰী খৰচ কৰিছে। পৰ্যালোচনা কৰিবলৈ টিপক।"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> নেপথ্যত দীৰ্ঘ সময় ধৰি চলি আছে। পৰ্যালোচনা কৰিবলৈ টিপক।"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"সক্ৰিয় এপ্সমূহ পৰীক্ষা কৰক"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index b6627af..8c4f0b6 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Davam etmək üçün ekran kilidinizi daxil edin"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Barmaq izinin bir hissəsi aşkarlanıb"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Barmaq izi tanınmadı. Lütfən, yenidən cəhd edin."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Sensoru silin"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Azca daha saxlayın"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Barmağınızı çox yavaş hərəkət etdirdiniz. Lütfən, yenidən cəhd edin."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Başqa bir barmaq izini sınayın"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Çox işıqlıdır"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Hər dəfə barmağınızın yerini bir az dəyişdirin"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Barmaq izi doğrulandı"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Üz doğrulandı"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Üz təsdiq edildi, təsdiq düyməsinə basın"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Keç"</string>
<string name="no_matches" msgid="6472699895759164599">"Uyğunluq yoxdur"</string>
<string name="find_on_page" msgid="5400537367077438198">"Səhifədə tap"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# uyğunluq}other{#/{total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Hazırdır"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Paylaşılan yaddaş silinir…"</string>
<string name="share" msgid="4157615043345227321">"Paylaşın"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aktivləşdirin"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Tətbiq əlçatan deyil"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> hazırda əlçatan deyil."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> əlçatan deyil"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Hazırda <xliff:g id="DEVICE">%1$s</xliff:g> cihazınızda buna giriş mümkün deyil. Android TV cihazınızda sınayın."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Hazırda <xliff:g id="DEVICE">%1$s</xliff:g> cihazınızda buna giriş mümkün deyil. Planşetinizdə sınayın."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Hazırda <xliff:g id="DEVICE">%1$s</xliff:g> cihazınızda buna giriş mümkün deyil. Telefonunuzda sınayın."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Bu tətbiq köhnə Android versiyası üçün hazırlanıb və düzgün işləməyə bilər. Güncəlləməni yoxlayın və ya developer ilə əlaqə saxlayın."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Güncəllənmə olmasını yoxlayın"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Yeni mesajlarınız var"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"SİSTEMDƏN SİLİN"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"İSTƏNİLƏN HALDA AÇIN"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Zərərli tətbiq aşkarlandı"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Sistem qeydinə giriş sorğusu"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Yalnız bu dəfə"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"İcazə verməyin"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> funksional sazlama üçün sistem qeydlərini tələb edir. Bu qeydlərə cihazınızda tətbiqlər və xidmətlərin yazdığı məlumatlar daxil ola bilər."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Daha göstərməyin"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> <xliff:g id="APP_2">%2$s</xliff:g> tətbiqindən bölmələr göstərmək istəyir"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Redaktə edin"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Zəng və bildirişlər vibrasiya verəcək"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Yandırıb-söndürmə dialoqu"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Kilid Ekranı"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skrinşot"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Qulaqlıq Qarmağı"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Ekranda Əlçatımlılıq Qısayolu"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Ekranda Əlçatımlılıq Qısayolu Seçicisi"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Əlçatımlılıq Qısayolu"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Bildiriş Göstərişini qapadın"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Dpad Yuxarı"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Dpad Aşağı"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad Sola"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad Sağa"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad Mərkəzə"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> başlıq paneli."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> MƏHDUDLAŞDIRILMIŞ səbətinə yerləşdirilib"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Aktiv etmək üçün toxunun"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"İş tətbiqi yoxdur"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Şəxsi tətbiq yoxdur"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Şəxsi profilinizdə <xliff:g id="APP">%s</xliff:g> tətbiqi açılsın?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"İş profilinizdə <xliff:g id="APP">%s</xliff:g> tətbiqi açılsın?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Şəxsi brauzerdən istifadə edin"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"İş brauzerindən istifadə edin"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM şəbəkəsi kilidaçma PİN\'i"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> arxa fonda işləyir və enerjini tükədir. Nəzərdən keçirmək üçün toxunun."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> uzun müddət arxa fonda işləyir. Nəzərdən keçirmək üçün toxunun."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Aktiv tətbiqləri yoxlayın"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 7831bd0..0c3b88c 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -77,7 +77,7 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"ID pozivaoca podrazumevano nije ograničen. Sledeći poziv: Nije ograničen."</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Usluga nije dobavljena."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Ne možete da promenite podešavanje ID-a korisnika."</string>
- <string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Nema usluge prenosa podataka preko mobilnog operatera"</string>
+ <string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Nema usluge mobilnih podataka"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Hitni pozivi nisu dostupni"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Nema glasovne usluge"</string>
<string name="RestrictedOnAllVoiceTitle" msgid="3982069078579103087">"Nema glasovne usluge ni hitnih poziva"</string>
@@ -589,8 +589,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Upotrebite zaključavanje ekrana da biste nastavili"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Otkriven je delimičan otisak prsta"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Nije uspela obrada otiska prsta. Probajte ponovo."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Obrišite senzor"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Zadržite malo duže"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Previše sporo ste pomerili prst. Probajte ponovo."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Probajte sa drugim otiskom prsta"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Previše je svetlo"</string>
@@ -598,6 +602,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Svaki put lagano promenite položaj prsta"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Otisak prsta je potvrđen"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Lice je potvrđeno"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Lice je potvrđeno. Pritisnite Potvrdi"</string>
@@ -1501,7 +1509,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Preskoči"</string>
<string name="no_matches" msgid="6472699895759164599">"Nema podudaranja"</string>
<string name="find_on_page" msgid="5400537367077438198">"Pronađi na stranici"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# podudaranje}one{# od {total}}few{# od {total}}other{# of {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Gotovo"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Briše se deljeni memorijski prostor…"</string>
<string name="share" msgid="4157615043345227321">"Deli"</string>
@@ -1929,6 +1938,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Uključi"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija nije dostupna"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutno nije dostupna."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> – nije dostupno"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Ovoj aplikaciji trenutno ne može da se pristupi sa uređaja <xliff:g id="DEVICE">%1$s</xliff:g>. Probajte na Android TV uređaju."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Ovoj aplikaciji trenutno ne može da se pristupi sa uređaja <xliff:g id="DEVICE">%1$s</xliff:g>. Probajte na tabletu."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Ovoj aplikaciji trenutno ne može da se pristupi sa uređaja <xliff:g id="DEVICE">%1$s</xliff:g>. Probajte na telefonu."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ova aplikacija je napravljena za stariju verziju Android-a, pa možda neće raditi ispravno. Potražite ažuriranja ili kontaktirajte programera."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Potraži ažuriranje"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Imate nove poruke"</string>
@@ -2018,16 +2031,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"DEINSTALIRAJ"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"IPAK OTVORI"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Otkrivena je štetna aplikacija"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Zahtev za pristup sistemskoj evidenciji"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Samo ovaj put"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ne dozvoli"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> zahteva evidencije sistema radi otklanjanja grešaka u funkcijama. Te evidencije mogu da sadrže informacije koje su aplikacije i usluge na uređaju zapisale."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne prikazuj ponovo"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Aplikacija <xliff:g id="APP_0">%1$s</xliff:g> želi da prikazuje isečke iz aplikacije <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Izmeni"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Vibracija za pozive i obaveštenja je uključena"</string>
@@ -2090,22 +2098,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dijalog napajanja"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Zaključani ekran"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snimak ekrana"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Kuka za slušalice"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Prečica za pristupačnost na ekranu"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Alatka za biranje prečica za pristupačnost na ekranu"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Prečica za pristupačnost"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Odbaci traku sa obaveštenjima"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"nagore na D-pad-u"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"nadole na D-pad-u"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"nalevo na D-pad-u"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"nadesno na D-pad-u"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"centar na D-pad-u"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Traka sa naslovima aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je dodat u segment OGRANIČENO"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2126,10 +2128,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Dodirnite da biste uključili"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Nema poslovnih aplikacija"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Nema ličnih aplikacija"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Želite da na ličnom profilu otvorite: <xliff:g id="APP">%s</xliff:g>?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Želite da na poslovnom profilu otvorite: <xliff:g id="APP">%s</xliff:g>?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Koristi lični pregledač"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Koristi poslovni pregledač"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"PIN za otključavanje SIM mreže"</string>
@@ -2264,4 +2264,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> je pokrenuta u pozadini i troši bateriju. Dodirnite da biste pregledali."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> je predugo pokrenuta u pozadini. Dodirnite da biste pregledali."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Proverite aktivne aplikacije"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 6bc7a7c..cf8c2dd 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -590,8 +590,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Каб працягнуць, скарыстайце свой сродак блакіроўкі экрана"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Адбітак пальца адсканіраваны не цалкам"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Не атрымалася апрацаваць адбітак пальца. Паспрабуйце яшчэ раз."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Ачысціце сканер"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Утрымлівайце палец крыху даўжэй"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Палец рухаўся занадта павольна. Паспрабуйце яшчэ раз."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Паспрабуйце іншы адбітак пальца"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Занадта светла"</string>
@@ -599,6 +603,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Кожны раз крыху мяняйце пазіцыю пальца"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Адбітак пальца распазнаны"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Твар распазнаны"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Твар распазнаны. Націсніце, каб пацвердзіць"</string>
@@ -1502,7 +1510,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Прапусціць"</string>
<string name="no_matches" msgid="6472699895759164599">"Няма супадзенняў"</string>
<string name="find_on_page" msgid="5400537367077438198">"Знайсці на старонцы"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# супадзенне}one{# з{total}}few{# з {total}}many{# з {total}}other{# з {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Гатова"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Сціраюцца даныя абагуленага сховішча…"</string>
<string name="share" msgid="4157615043345227321">"Абагуліць"</string>
@@ -1930,6 +1939,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Уключыць"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Праграма недаступная"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" цяпер недаступная."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"Недаступна: <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Не ўдаецца атрымаць доступ з вашай прылады \"<xliff:g id="DEVICE">%1$s</xliff:g>\". Паспрабуйце скарыстаць прыладу Android TV."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Не ўдаецца атрымаць доступ з вашай прылады \"<xliff:g id="DEVICE">%1$s</xliff:g>\". Паспрабуйце скарыстаць планшэт."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Не ўдаецца атрымаць доступ з вашай прылады \"<xliff:g id="DEVICE">%1$s</xliff:g>\". Паспрабуйце скарыстаць тэлефон."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Гэта праграма была створана для больш старой версіі Android і можа не працаваць належным чынам. Праверце наяўнасць абнаўленняў або звярніцеся да распрацоўшчыка."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Праверыць на наяўнасць абнаўленняў"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"У вас ёсць новыя паведамленні"</string>
@@ -2019,16 +2032,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ВЫДАЛІЦЬ"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"УСЁ РОЎНА АДКРЫЦЬ"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Выяўлена шкодная праграма"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Запыт на доступ да сістэмных журналаў"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Толькі ў гэты раз"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Не дазваляць"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> запытвае доступ да сістэмных журналаў з мэтай функцыянальнай адладкі. У гэтых журналах можа ўтрымлівацца інфармацыя, запісаная праграмамі і сэрвісамі вашай прылады."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Больш не паказваць"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Праграма <xliff:g id="APP_0">%1$s</xliff:g> запытвае дазвол на паказ зрэзаў праграмы <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Рэдагаваць"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Для выклікаў і апавяшчэнняў уключаны вібрасігнал"</string>
@@ -2091,22 +2099,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Дыялогавае акно сілкавання"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Экран блакіроўкі"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Здымак экрана"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Кручок для гарнітуры"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Хуткі доступ да спецыяльных магчымасцей на экране"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Налада хуткага доступу да спецыяльных магчымасцей на экране"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Хуткі доступ"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Закрыць шчыток апавяшчэнняў"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Уверх на панэлі кіравання"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Уніз на панэлі кіравання"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Улева на панэлі кіравання"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Управа на панэлі кіравання"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"У цэнтр на панэлі кіравання"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Панэль субцітраў праграмы \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" дададзены ў АБМЕЖАВАНУЮ групу"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2127,10 +2129,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Націсніце, каб уключыць"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Няма працоўных праграм"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Няма асабістых праграм"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Адкрыць праграму \"<xliff:g id="APP">%s</xliff:g>\" з выкарыстаннем асабістага профілю?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Адкрыць праграму \"<xliff:g id="APP">%s</xliff:g>\" з выкарыстаннем працоўнага профілю?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Скарыстаць асабісты браўзер"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Скарыстаць працоўны браўзер"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"PIN-код разблакіроўкі сеткі для SIM-карты"</string>
@@ -2265,4 +2265,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> працуе ў фонавым рэжыме і расходуе зарад акумулятара. Націсніце, каб праглядзець."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> працуе ў фонавым рэжыме працяглы час. Націсніце, каб праглядзець."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Праверце актыўныя праграмы"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 2428387..7183dce 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Въведете опцията си за заключване на екрана, за да продължите"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Установен е частичен отпечатък"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Отпечатъкът не бе обработен. Моля, опитайте отново."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Почистете сензора"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Задръжте пръста си малко по-дълго"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Преместихте пръста си твърде бавно. Моля, опитайте отново."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Опитайте с друг отпечатък"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Твърде светло е"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Всеки път променяйте леко позицията на пръста си"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Отпечатъкът е удостоверен"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Лицето е удостоверено"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Лицето е удостоверено. Моля, натиснете „Потвърждаване“"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Пропускане"</string>
<string name="no_matches" msgid="6472699895759164599">"Няма съответствия"</string>
<string name="find_on_page" msgid="5400537367077438198">"Намиране в страницата"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# съответствие}other{# от {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Готово"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Споделеното хранилище се изтрива…"</string>
<string name="share" msgid="4157615043345227321">"Споделяне"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Включване"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Приложението не е достъпно"</string>
<string name="app_blocked_message" msgid="542972921087873023">"В момента няма достъп до <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> не е налице"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Понастоящем не може да се осъществи достъп от устройството ви <xliff:g id="DEVICE">%1$s</xliff:g>. Вместо това опитайте от устройството си с Android TV."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Понастоящем не може да се осъществи достъп от устройството ви <xliff:g id="DEVICE">%1$s</xliff:g>. Вместо това опитайте от таблета си."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Понастоящем не може да се осъществи достъп от устройството ви <xliff:g id="DEVICE">%1$s</xliff:g>. Вместо това опитайте от телефона си."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Това приложение бе създадено за по-стара версия на Android и може да не работи правилно. Опитайте да проверите за актуализации или се свържете с програмиста."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Проверка за актуализация"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Имате нови съобщения"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ДЕИНСТАЛИРАНЕ"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"ОТВАРЯНЕ"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Открито е опасно приложение"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Заявка за достъп до сист. рег. файлове"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Само този път"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Забраняване"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> иска достъп до системните регистрационни файлове с цел отстраняване на грешки с функциите. Тези файлове трябва да съдържат информация, записана от приложенията и услугите на устройството ви."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Да не се показва пак"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> иска да показва части от <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Редактиране"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"При обаждания и известия устройството ще вибрира"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Диалогов прозорец за захранването"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заключен екран"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Екранна снимка"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Кукичка на слушалките"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Пряк път към достъпността на екрана"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Инструмент за избор на пряк път към достъпността на екрана"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Пряк път за достъпност"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Отхвърляне на падащия панел с известия"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Контролен пад – горе"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Контролен пад – долу"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Контролен пад – ляво"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Контролен пад – дясно"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Контролен пад – център"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Лента за надписи на <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакетът <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> е поставен в ОГРАНИЧЕНИЯ контейнер"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Докоснете за включване"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Няма подходящи служебни приложения"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Няма подходящи лични приложения"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Искате ли да отворите <xliff:g id="APP">%s</xliff:g> в личния си потребителски профил?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Искате ли да отворите <xliff:g id="APP">%s</xliff:g> в служебния си потребителски профил?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Използване на личния браузър"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Използване на служебния браузър"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"ПИН за отключване на мрежата за SIM"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> работи на заден план и изразходва батерията. Докоснете за преглед."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> работи на заден план от дълго време. Докоснете за преглед."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Проверете активните приложения"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index c8e800d..82932dc 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -304,10 +304,8 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"আপনার ক্যালেন্ডারে অ্যাক্সেস"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"এসএমএসগুলি পাঠাতে এবং দেখতে"</string>
- <!-- no translation found for permgrouplab_storage (9173334109512154196) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (8352226729501080525) -->
- <skip />
+ <string name="permgrouplab_storage" msgid="9173334109512154196">"ফাইল ও ডকুমেন্ট"</string>
+ <string name="permgroupdesc_storage" msgid="8352226729501080525">"আপনার ডিভাইসে ফাইল ও ডকুমেন্ট অ্যাক্সেস করুন"</string>
<string name="permgrouplab_readMediaAural" msgid="5885210465560755316">"মিউজিক ও অন্যান্য অডিও"</string>
<string name="permgroupdesc_readMediaAural" msgid="1170143315714662822">"আপনার ডিভাইসে অডিও ফাইল অ্যাক্সেস করুন"</string>
<string name="permgrouplab_readMediaVisual" msgid="9137695801926624061">"ফটো ও ভিডিও"</string>
@@ -588,8 +586,9 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"চালিয়ে যেতে আপনার স্ক্রিন লক ব্যবহার করুন"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"আংশিক আঙ্গুলের ছাপ শনাক্ত করা হয়েছে"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"আঙ্গুলের ছাপ প্রক্রিয়া করা যায়নি৷ অনুগ্রহ করে আবার চেষ্টা করুন৷"</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"সেন্সর পরিষ্কার করুন"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"একটু বেশি সময় ধরে সেন্সরে আঙ্গুল রাখুন"</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"আঙ্গুলের ছাপের সেন্সর পরিষ্কার করে আবার চেষ্টা করুন"</string>
+ <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"সেন্সর পরিষ্কার করে আবার চেষ্টা করুন"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"সেন্সর জোরে প্রেস করুন"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"আঙ্গুল খুব ধীরে সরানো হয়েছে৷ অনুগ্রহ করে আবার চেষ্টা করুন৷"</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"অন্য আঙ্গুলের ছাপ দিয়ে চেষ্টা করুন"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"অত্যন্ত উজ্জ্বল"</string>
@@ -597,6 +596,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"প্রতিবার আঙ্গুলের ছাপ সেটআপ করার সময় আপনার আঙ্গুলের অবস্থান সামান্য পরিবর্তন করুন"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"আঙ্গুলের ছাপ শনাক্ত করা যায়নি"</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="4709197752023550709">"সেন্সর জোরে প্রেস করুন"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"আঙ্গুলের ছাপ যাচাই করা হয়েছে"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"ফেস যাচাই করা হয়েছে"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"ফেস যাচাই করা হয়েছে, \'কনফার্ম করুন\' বোতাম প্রেস করুন"</string>
@@ -1500,7 +1501,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"এড়িয়ে যান"</string>
<string name="no_matches" msgid="6472699895759164599">"কোনো মিল নেই"</string>
<string name="find_on_page" msgid="5400537367077438198">"পৃষ্ঠায় খুঁজুন"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{#টি ম্যাচ}one{{total}-এর মধ্যে #টি}other{{total}-এর মধ্যে #টি}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"সম্পন্ন হয়েছে"</string>
<string name="progress_erasing" msgid="6891435992721028004">"শেয়ার করা স্টোরেজ মুছে ফেলা হচ্ছে…"</string>
<string name="share" msgid="4157615043345227321">"শেয়ার করুন"</string>
@@ -1928,6 +1930,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"চালু করুন"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"অ্যাপ পাওয়া যাচ্ছে না"</string>
<string name="app_blocked_message" msgid="542972921087873023">"এই মুহূর্তে <xliff:g id="APP_NAME">%1$s</xliff:g> অ্যাপ পাওয়া যাচ্ছে না।"</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> উপলভ্য নেই"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"এই সময়ে আপনার <xliff:g id="DEVICE">%1$s</xliff:g>-এ এটি অ্যাক্সেস করা যাবে না। পরিবর্তে আপনার Android TV ডিভাইস ব্যবহার করে দেখুন।"</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"এই সময়ে আপনার <xliff:g id="DEVICE">%1$s</xliff:g>-এ এটি অ্যাক্সেস করা যাবে না। পরিবর্তে আপনার ট্যাবলেটে ব্যবহার করে দেখুন।"</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"এই সময়ে আপনার <xliff:g id="DEVICE">%1$s</xliff:g>-এ এটি অ্যাক্সেস করা যাবে না। পরিবর্তে আপনার ফোনে ব্যবহার করে দেখুন।"</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"এই অ্যাপটি Android এর একটি পুরনো ভার্সনের জন্য তৈরি করা হয়েছিল, তাই এখানে সেটি ঠিকমতো কাজ নাও করতে পারে। আপডেট পাওয়া যাচ্ছে কিনা দেখুন বা ডেভেলপারের সাথে যোগাযোগ করুন।"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"আপডেট পাওয়া যাচ্ছে কিনা দেখুন"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"আপনার নতুন মেসেজ আছে"</string>
@@ -2017,16 +2023,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"আন-ইনস্টল করুন"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"যাই হোক, খুলতে চাই"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"ক্ষতিকর অ্যাপ শনাক্ত করা হয়েছে"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"সিস্টেম লগ অ্যাক্সেস করার অনুরোধ"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"শুধুমাত্র এখন"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"অনুমতি দেবেন না"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"ফাংশনাল ডিবাগিংয়ের জন্য <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> সিস্টেম লগ অ্যাক্সেস করার অনুরোধ জানিয়েছে। আপনার ডিভাইসে থাকা অ্যাপ এবং পরিষেবার থেকে আসা বিভিন্ন তথ্য এইসব লগে লেখা থাকতে পারে।"</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"আর দেখতে চাই না"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> অ্যাপটি <xliff:g id="APP_2">%2$s</xliff:g> এর অংশ দেখাতে চায়"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"এডিট করুন"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"কল এবং বিজ্ঞপ্তি আসলে ভাইব্রেট হবে"</string>
@@ -2089,22 +2090,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"পাওয়ার ডায়লগ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"লক স্ক্রিন"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"স্ক্রিনশট নিন"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"হেডসেট হুক"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"অন-স্ক্রিন অ্যাক্সেসিবিলিটি শর্টকাট"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"অন-স্ক্রিন অ্যাক্সেসিবিলিটি শর্টকাট বেছে নেওয়ার বিকল্প"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"অ্যাক্সেসিবিলিটি শর্টকাট"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"বিজ্ঞপ্তি শেড বাতিল করুন"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"ডিপ্যাড (Dpad)-এর উপরে"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"ডিপ্যাড (Dpad)-এর নিচে"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"ডিপ্যাড (Dpad)-এর বাঁদিকে"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"ডিপ্যাড (Dpad)-এর ডানদিকে"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"ডিপ্যাড (Dpad)-এর মাঝখানে"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এর ক্যাপশন বার।"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> সীমাবদ্ধ গ্রুপে অন্তর্ভুক্ত করা হয়েছে"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2120,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"চালু করতে ট্যাপ করুন"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"এর জন্য কোনও অফিস অ্যাপ নেই"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"ব্যক্তিগত অ্যাপে দেখা যাবে না"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"আপনার ব্যক্তিগত প্রোফাইল থেকে <xliff:g id="APP">%s</xliff:g> খুলবেন?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"আপনার অফিস প্রোফাইল থেকে <xliff:g id="APP">%s</xliff:g> খুলবেন?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"ব্যক্তিগত ব্রাউজার ব্যবহার করুন"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"অফিস ব্রাউজার ব্যবহার করুন"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"সিম নেটওয়ার্ক আনলক পিন"</string>
@@ -2263,4 +2256,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> ব্যাকগ্রাউন্ডে চলছে এবং এর ফলে ব্যাটারির চার্জ কমে যাচ্ছে। পর্যালোচনা করতে ট্যাপ করুন।"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> অনেকক্ষণ ধরে ব্যাকগ্রাউন্ডে চলছে। পর্যালোচনা করতে ট্যাপ করুন।"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"অ্যাক্টিভ অ্যাপ চেক করুন"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index c25d86f..4f4f7d6 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -305,10 +305,8 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"pristupa vašem kalendaru"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"šalje i pregleda SMS poruke"</string>
- <!-- no translation found for permgrouplab_storage (9173334109512154196) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (8352226729501080525) -->
- <skip />
+ <string name="permgrouplab_storage" msgid="9173334109512154196">"Datoteke i dokumenti"</string>
+ <string name="permgroupdesc_storage" msgid="8352226729501080525">"pristup datotekama i dokumentima na vašem uređaju"</string>
<string name="permgrouplab_readMediaAural" msgid="5885210465560755316">"Muzika i drugi zvučni zapisi"</string>
<string name="permgroupdesc_readMediaAural" msgid="1170143315714662822">"pristup audio fajlovima na vašem uređaju"</string>
<string name="permgrouplab_readMediaVisual" msgid="9137695801926624061">"Fotografije i videozapisi"</string>
@@ -589,8 +587,9 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Unesite zaključavanje ekrana da nastavite"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Otkriven je djelimični otisak prsta"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Obrada otiska prsta nije uspjela. Pokušajte ponovo."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Očistite senzor"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Zadržite malo duže"</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Očistite senzor za otisak prsta i pokušajte ponovo"</string>
+ <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Očistite senzor i pokušajte ponovo"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Čvrsto pritisnite senzor"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Presporo ste pomjerili prst. Pokušajte ponovo."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Pokušajte s drugim otiskom prsta"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Presvijetlo"</string>
@@ -598,6 +597,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Svaki put blago promijenite položaj prsta"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"Otisak prsta nije prepoznat"</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="4709197752023550709">"Čvrsto pritisnite senzor"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Otisak prsta je potvrđen"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Lice je provjereno"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Lice je provjereno, pritisnite dugme za potvrdu"</string>
@@ -1501,7 +1502,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Preskoči"</string>
<string name="no_matches" msgid="6472699895759164599">"Nema podudaranja"</string>
<string name="find_on_page" msgid="5400537367077438198">"Pronađi na stranici"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# podudaranje}one{# od {total}}few{# od {total}}other{# od {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Gotovo"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Brisanje dijeljene pohrane…"</string>
<string name="share" msgid="4157615043345227321">"Dijeli"</string>
@@ -1929,6 +1931,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Uključi"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija nije dostupna"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutno nije dostupna."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"Nedostupno: <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Trenutno ne možete pristupiti ovoj aplikaciji na uređaju <xliff:g id="DEVICE">%1$s</xliff:g>. Umjesto toga pokušajte na uređaju Android TV."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Trenutno ne možete pristupiti ovoj aplikaciji na uređaju <xliff:g id="DEVICE">%1$s</xliff:g>. Umjesto toga pokušajte na tabletu."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Trenutno ne možete pristupiti ovoj aplikaciji na uređaju <xliff:g id="DEVICE">%1$s</xliff:g>. Umjesto toga pokušajte na telefonu."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ova aplikacija je pravljena za stariju verziju Androida i možda neće ispravno raditi. Provjerite jesu li dostupna ažuriranja ili kontaktirajte programera."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Provjeri je li dostupno ažuriranje"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Imate nove poruke"</string>
@@ -2018,16 +2024,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"DEINSTALIRAJ"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"IPAK OTVORI"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Otkrivena je štetna aplikacija"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Zahtjev za pristup sistemskom zapisniku"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Samo ovaj put"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nemoj dozvoliti"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"Aplikacija <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> traži zapisnike sistema za funkcionalno otklanjanje grešaka. Ti zapisnici mogu sadržavati informacije koje su zabilježile aplikacije i usluge na vašem uređaju."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne prikazuj ponovo"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Aplikacija <xliff:g id="APP_0">%1$s</xliff:g> želi prikazati isječke aplikacije <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Uredi"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Pozivi i obavještenja će vibrirati"</string>
@@ -2090,22 +2091,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dijaloški okvir za napajanje"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Zaključavanje ekrana"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snimak ekrana"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Kuka za slušalice"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Prečica za pristupačnost na ekranu"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Okvir za odabir prečice za pristupačnost na ekranu"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Prečica za pristupačnost"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Odbacite lokaciju za obavještenja"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Upravljač gore"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Upravljač dolje"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Upravljač lijevo"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Upravljač desno"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Upravljač sredina"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Traka za natpis aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je stavljen u odjeljak OGRANIČENO"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2126,10 +2121,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Dodirnite da uključite"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Nema poslovnih aplikacija"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Nema ličnih aplikacija"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Otvoriti aplikaciju <xliff:g id="APP">%s</xliff:g> na ličnom profilu?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Otvoriti aplikaciju <xliff:g id="APP">%s</xliff:g> na radnom profilu?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Koristi lični preglednik"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Koristi poslovni preglednik"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"PIN za otključavanje mreže na SIM-u"</string>
@@ -2264,4 +2257,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> je pokrenuta u pozadini i troši bateriju. Dodirnite da pregledate."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> dugo radi u pozadini. Dodirnite da pregledate."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Provjerite aktivne aplikacije"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 35373ee..fa531ad 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Introdueix el teu bloqueig de pantalla per continuar"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"S\'ha detectat una empremta digital parcial"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"No s\'ha pogut processar l\'empremta digital. Torna-ho a provar."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Neteja el sensor"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Mantén premut una estona més"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"El dit s\'ha mogut massa lentament. Torna-ho a provar."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Prova una altra empremta digital"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Hi ha massa llum"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Canvia lleugerament la posició del dit en cada intent"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"L\'empremta digital s\'ha autenticat"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Cara autenticada"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Cara autenticada; prem el botó per confirmar"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Omet"</string>
<string name="no_matches" msgid="6472699895759164599">"No s\'ha trobat cap coincidència"</string>
<string name="find_on_page" msgid="5400537367077438198">"Troba-ho a la pàgina"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# coincidència}other{# de {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Fet"</string>
<string name="progress_erasing" msgid="6891435992721028004">"S\'està esborrant l\'emmagatzematge compartit…"</string>
<string name="share" msgid="4157615043345227321">"Comparteix"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activa"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"L\'aplicació no està disponible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Ara mateix, <xliff:g id="APP_NAME">%1$s</xliff:g> no està disponible."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> no està disponible"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"En aquests moments, no es pot accedir a aquesta aplicació al dispositiu <xliff:g id="DEVICE">%1$s</xliff:g>. Prova-ho al dispositiu Android TV."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"En aquests moments, no es pot accedir a aquesta aplicació al dispositiu <xliff:g id="DEVICE">%1$s</xliff:g>. Prova-ho a la tauleta."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"En aquests moments, no es pot accedir a aquesta aplicació al dispositiu <xliff:g id="DEVICE">%1$s</xliff:g>. Prova-ho al telèfon."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Aquesta aplicació es va crear per a una versió antiga d\'Android i pot ser que no funcioni correctament. Prova de cercar actualitzacions o contacta amb el desenvolupador."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Cerca actualitzacions"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Tens missatges nous"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"DESINSTAL·LA"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"OBRE IGUALMENT"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"S\'ha detectat una aplicació perjudicial"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Sol·licitud d\'accés a registre del sistema"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Només aquesta vegada"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"No permetis"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> sol·licita registres del sistema per dur a terme una depuració funcional. Aquests registres poden contenir informació escrita per les aplicacions i els serveis del teu dispositiu."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"No tornis a mostrar"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> vol mostrar porcions de l\'aplicació <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Edita"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Les trucades i les notificacions vibraran"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Quadre de diàleg d\'engegada"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Pantalla de bloqueig"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de pantalla"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Ganxo per a auriculars amb micro"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Drecera d\'accessibilitat en pantalla"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Selector de dreceres d\'accessibilitat en pantalla"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Drecera d\'accessibilitat"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Ignora l\'àrea de notificacions"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Creu direccional: amunt"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Creu direccional: avall"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Creu direccional: esquerra"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Creu direccional: dreta"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Creu direccional: centre"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de títol de l\'aplicació <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> s\'ha transferit al segment RESTRINGIT"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Toca per activar"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Cap aplicació de treball"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Cap aplicació personal"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Vols obrir <xliff:g id="APP">%s</xliff:g> al teu perfil personal?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Vols obrir <xliff:g id="APP">%s</xliff:g> al teu perfil de treball?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Utilitza el navegador personal"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Utilitza el navegador de treball"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"PIN de desbloqueig de la xarxa SIM"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> s\'està executant en segon pla i consumeix bateria. Toca per revisar-ho."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"Fa molta estona que <xliff:g id="APP">%1$s</xliff:g> s\'està executant en segon pla. Toca per revisar-ho."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Consulta les aplicacions actives"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 94e9038..ee9d7bc 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -590,8 +590,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Pokračujte zadáním zámku obrazovky"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Byla zjištěna jen část otisku prstu"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Zpracování otisku prstu se nezdařilo. Zkuste to znovu."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Očistěte senzor"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Ještě vydržte"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Pohyb prstem byl příliš pomalý. Zkuste to znovu."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Zkuste jiný otisk prstu"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Je příliš světlo"</string>
@@ -599,6 +603,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Pokaždé lehce změňte polohu prstu"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Otisk byl ověřen"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Obličej byl ověřen"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Obličej byl ověřen, stiskněte tlačítko pro potvrzení"</string>
@@ -1502,7 +1510,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Přeskočit"</string>
<string name="no_matches" msgid="6472699895759164599">"Žádné shody"</string>
<string name="find_on_page" msgid="5400537367077438198">"Hledat na stránce"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# shoda}few{# ze {total}}many{# z {total}}other{# z {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Hotovo"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Mazání sdíleného úložiště…"</string>
<string name="share" msgid="4157615043345227321">"Sdílet"</string>
@@ -1930,6 +1939,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Zapnout"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikace není k dispozici"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> v tuto chvíli není k dispozici."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> není k dispozici"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Tato položka na vašem zařízení <xliff:g id="DEVICE">%1$s</xliff:g> v tuto chvíli není k dispozici. Zkuste to na zařízení Android TV."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Tato položka na vašem zařízení <xliff:g id="DEVICE">%1$s</xliff:g> v tuto chvíli není k dispozici. Zkuste to na tabletu."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Tato položka na vašem zařízení <xliff:g id="DEVICE">%1$s</xliff:g> v tuto chvíli není k dispozici. Zkuste to na telefonu."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Tato aplikace byla vytvořena pro starší verzi systému Android a nemusí fungovat správně. Zkuste vyhledat aktualizace, případně kontaktujte vývojáře."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Zkontrolovat aktualizace"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Máte nové zprávy"</string>
@@ -2019,16 +2032,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ODINSTALOVAT"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"PŘESTO OTEVŘÍT"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Byla zjištěna škodlivá aplikace"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Žádost o přístup k systémovým protokolům"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Pouze tentokrát"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nepovolovat"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"Aplikace <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> k funkčnímu ladění požaduje systémové protokoly. Tyto protokoly mohou zahrnovat informace zapsané do zařízení aplikacemi a službami."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Příště nezobrazovat"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Aplikace <xliff:g id="APP_0">%1$s</xliff:g> chce zobrazovat ukázky z aplikace <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Upravit"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Volání a oznámení budou vibrovat"</string>
@@ -2091,22 +2099,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialogové okno k napájení"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Obrazovka uzamčení"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snímek obrazovky"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Tlačítko na náhlavní soupravě"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Zkratka přístupnosti na obrazovce"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Výběr zkratky přístupnosti na obrazovce"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Zkratka přístupnosti"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Zavřít panel oznámení"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Dpad nahoru"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Dpad dolů"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad doleva"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad doprava"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad střed"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Popisek aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Balíček <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> byl vložen do sekce OMEZENO"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2127,10 +2129,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Klepnutím ho zapnete"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Žádné pracovní aplikace"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Žádné osobní aplikace"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Otevřít aplikaci <xliff:g id="APP">%s</xliff:g> v osobním profilu?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Otevřít aplikaci <xliff:g id="APP">%s</xliff:g> v pracovním profilu?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Použít osobní prohlížeč"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Použít pracovní prohlížeč"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"Kód PIN odblokování sítě pro SIM kartu"</string>
@@ -2265,4 +2265,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"Aplikace <xliff:g id="APP">%1$s</xliff:g> je spuštěna na pozadí a vybíjí baterii. Klepnutím ji zkontrolujete."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"Aplikace <xliff:g id="APP">%1$s</xliff:g> je už dlouhou dobu spuštěna na pozadí. Klepnutím ji zkontrolujete."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Zkontrolujte aktivní aplikace"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 26557da..66a31e7 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Angiv din skærmlås for at fortsætte"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Et delvist fingeraftryk blev registreret"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Fingeraftrykket kunne ikke behandles. Prøv igen."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Rengør sensoren"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Hold fingeren stille lidt længere"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Du bevægede fingeren for langsomt. Prøv igen."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Prøv med et andet fingeraftryk"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Der er for lyst"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Flyt fingeren en smule hver gang"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingeraftrykket blev godkendt"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Ansigtet er godkendt"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Ansigtet er godkendt. Tryk på Bekræft."</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Spring over"</string>
<string name="no_matches" msgid="6472699895759164599">"Der er ingen matches"</string>
<string name="find_on_page" msgid="5400537367077438198">"Find på siden"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# match}one{# ud af {total}}other{# ud af {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Udfør"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Sletter delt lagerplads…"</string>
<string name="share" msgid="4157615043345227321">"Del"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Slå til"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Appen er ikke tilgængelig"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> er ikke tilgængelig lige nu."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> er ikke understøttet"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Du har ikke adgang til denne app på din <xliff:g id="DEVICE">%1$s</xliff:g> på nuværende tidspunkt. Prøv på din Android TV-enhed i stedet."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Du har ikke adgang til denne app på din <xliff:g id="DEVICE">%1$s</xliff:g> på nuværende tidspunkt. Prøv på din tablet i stedet."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Du har ikke adgang til denne app på din <xliff:g id="DEVICE">%1$s</xliff:g> på nuværende tidspunkt. Prøv på din telefon i stedet."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Denne app er lavet til en ældre version af Android og fungerer muligvis ikke korrekt. Prøv at søge efter opdateringer, eller kontakt udvikleren."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Søg efter opdatering"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Du har nye beskeder"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"AFINSTALLER"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"ÅBN ALLIGEVEL"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Der er registreret en skadelig app"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Anmodning om adgang til systemlogs"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Kun denne gang"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Tillad ikke"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> anmoder om adgang til systemlogs med henblik på funktionel fejlretning. Disse logs indeholder muligvis oplysninger, som apps og tjenester på din enhed har genereret."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Vis ikke igen"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> anmoder om tilladelse til at vise eksempler fra <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Rediger"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Telefonen vibrerer ved opkald og notifikationer"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialogboks om strøm"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Låseskærm"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Headset, hook"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Genvej til hjælpefunktioner på skærmen"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Valg af genvej til hjælpefunktioner på skærmen"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Genvej til hjælpefunktioner"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Luk notifikationspanel"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"D-pad, op"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"D-pad, ned"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"D-pad, venstre"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"D-pad, højre"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"D-pad, midten"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Titellinje for <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> er blevet placeret i samlingen BEGRÆNSET"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Tryk for at aktivere"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Der er ingen arbejdsapps"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Der er ingen personlige apps"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Vil du åbne <xliff:g id="APP">%s</xliff:g> på din personlige profil?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Vil du åbne <xliff:g id="APP">%s</xliff:g> på din arbejdsprofil?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Brug personlig browser"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Brug arbejdsbrowser"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"Pinkode til oplåsning af SIM-netværket"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> kører i baggrunden og dræner batteriet. Tryk for at gennemgå."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> har kørt i baggrunden i lang tid. Tryk for at gennemgå."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Tjek aktive apps"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 091542d..781dd99 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Displaysperre eingeben, um fortzufahren"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Fingerabdruck wurde nur teilweise erkannt"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Fingerabdruck konnte nicht verarbeitet werden. Bitte versuche es noch einmal."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Sensor reinigen"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Lass den Finger bitte etwas länger liegen"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Finger zu langsam bewegt. Bitte versuche es noch einmal."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Anderen Fingerabdruck verwenden"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Zu hell"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Ändere jedes Mal die Position deines Fingers"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingerabdruck wurde authentifiziert"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Gesicht authentifiziert"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Gesicht authentifiziert, bitte bestätigen"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Überspringen"</string>
<string name="no_matches" msgid="6472699895759164599">"Keine Treffer"</string>
<string name="find_on_page" msgid="5400537367077438198">"Auf Seite suchen"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# Übereinstimmung}other{# von {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Fertig"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Freigegebener Speicher wird gelöscht…"</string>
<string name="share" msgid="4157615043345227321">"Teilen"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aktivieren"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"App ist nicht verfügbar"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ist derzeit nicht verfügbar."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nicht verfügbar"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Auf deinem <xliff:g id="DEVICE">%1$s</xliff:g> ist derzeit kein Zugriff möglich. Versuche es stattdessen auf deinem Android TV-Gerät."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Auf deinem <xliff:g id="DEVICE">%1$s</xliff:g> ist derzeit kein Zugriff möglich. Versuche es stattdessen auf deinem Tablet."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Auf deinem <xliff:g id="DEVICE">%1$s</xliff:g> ist derzeit kein Zugriff möglich. Versuche es stattdessen auf deinem Smartphone."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Diese App wurde für eine ältere Android-Version entwickelt und funktioniert möglicherweise nicht mehr richtig. Prüfe, ob Updates verfügbar sind oder kontaktiere den Entwickler."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Auf Updates prüfen"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Du hast neue Nachrichten"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"DEINSTALLIEREN"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"TROTZDEM ÖFFNEN"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Schädliche App erkannt"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Zugriffsanforderung für Systemprotokolle"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Nur dieses Mal"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nicht zulassen"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> fordert Systemprotokolle für die funktionale Fehlerbehebung an. Diese Protokolle können Informationen enthalten, die von Apps und Diensten auf deinem Gerät gespeichert wurden."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Nicht mehr anzeigen"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> möchte Teile von <xliff:g id="APP_2">%2$s</xliff:g> anzeigen"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Bearbeiten"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Gerät vibriert bei Anrufen und Benachrichtigungen"</string>
@@ -2119,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Zum Aktivieren tippen"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Keine geschäftlichen Apps"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Keine privaten Apps"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"<xliff:g id="APP">%s</xliff:g> in deinem privaten Profil öffnen?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"<xliff:g id="APP">%s</xliff:g> in deinem Arbeitsprofil öffnen?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Privaten Browser verwenden"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Arbeitsbrowser verwenden"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"Entsperr-PIN für netzgebundenes Gerät"</string>
@@ -2257,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> wird im Hintergrund ausgeführt und belastet den Akku. Zum Prüfen tippen."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> wird schon längere Zeit im Hintergrund ausgeführt. Zum Prüfen tippen."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Aktive Apps prüfen"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 76484fb..c9716d6 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Χρησιμοποιήστε το κλείδωμα οθόνης για να συνεχίσετε"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Εντοπίστηκε μέρους του δακτυλικού αποτυπώματος"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Δεν ήταν δυνατή η επεξεργασία του δακτυλικού αποτυπώματος. Δοκιμάστε ξανά."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Καθαρίστε τον αισθητήρα"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Κρατήστε για λίγο ακόμη"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Πολύ αργή κίνηση δαχτύλου. Δοκιμάστε ξανά."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Δοκιμάστε άλλο δακτυλικό αποτύπωμα"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Υπερβολικά έντονος φωτισμός"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Αλλάζετε ελαφρώς τη θέση του δακτύλου σας κάθε φορά."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Η ταυτότητα του δακτυλικού αποτυπώματος ελέγχθηκε"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Έγινε έλεγχος ταυτότητας προσώπου"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Έγινε έλεγχος ταυτότητας προσώπου, πατήστε \"Επιβεβαίωση\""</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Παράβλεψη"</string>
<string name="no_matches" msgid="6472699895759164599">"Δεν υπάρχουν αποτελέσματα"</string>
<string name="find_on_page" msgid="5400537367077438198">"Εύρεση στη σελίδα"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# αντιστοίχιση}other{# από {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Τέλος"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Διαγραφή κοινόχρηστου αποθηκευτικού χώρου…"</string>
<string name="share" msgid="4157615043345227321">"Κοινή χρ."</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Ενεργοποίηση"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Η εφαρμογή δεν είναι διαθέσιμη"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> δεν είναι διαθέσιμη αυτήν τη στιγμή."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> δεν διατίθεται"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Δεν είναι δυνατή η πρόσβαση στη συγκεκριμένη εφαρμογή από τη συσκευή <xliff:g id="DEVICE">%1$s</xliff:g> αυτήν τη στιγμή. Δοκιμάστε στη συσκευή Android TV."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Δεν είναι δυνατή η πρόσβαση στη συγκεκριμένη εφαρμογή από τη συσκευή <xliff:g id="DEVICE">%1$s</xliff:g> αυτήν τη στιγμή. Δοκιμάστε στο tablet σας."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Δεν είναι δυνατή η πρόσβαση στη συγκεκριμένη εφαρμογή από τη συσκευή <xliff:g id="DEVICE">%1$s</xliff:g> αυτήν τη στιγμή. Δοκιμάστε στο τηλέφωνό σας."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Αυτή η εφαρμογή δημιουργήθηκε για παλαιότερη έκδοση του Android και μπορεί να μην λειτουργεί σωστά. Δοκιμάστε να ελέγξετε εάν υπάρχουν ενημερώσεις ή επικοινωνήστε με τον προγραμματιστή."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Έλεγχος για ενημέρωση"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Έχετε νέα μηνύματα"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ΑΠΕΓΚΑΤΑΣΤΑΣΗ"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"ΑΝΟΙΓΜΑ"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Εντοπίστηκε επιβλαβής εφαρμογή"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Αίτημα πρόσβ. σε αρχ. καταγρ. συστήματος"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Μόνο αυτήν τη φορά"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Να μην επιτραπεί"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"Η εφαρμογή <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ζητάει τα αρχεία καταγραφής συστήματος για τον εντοπισμό σφαλμάτων λειτουργικότητας. Αυτά τα αρχεία καταγραφής ενδέχεται να περιέχουν πληροφορίες που έχουν γράψει οι εφαρμογές και οι υπηρεσίες στη συσκευή σας."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Να μην εμφανισ. ξανά"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Η εφαρμογή <xliff:g id="APP_0">%1$s</xliff:g> θέλει να εμφανίζει τμήματα της εφαρμογής <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Επεξεργασία"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Θα υπάρχει δόνηση για κλήσεις και ειδοποιήσεις"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Παράθυρο διαλόγου λειτουργίας συσκευής"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Οθόνη κλειδώματος"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Στιγμιότυπο οθόνης"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Άγκιστρο ακουστικών"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Συντόμευση οθόνης για την προσβασιμότητα"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Επιλογέας συντόμευσης οθόνης για την προσβασιμότητα"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Συντόμευση προσβασιμότητας"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Παράβλεψη πλαισίου σκίασης ειδοποιήσεων"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Dpad επάνω"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Dpad κάτω"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad αριστερά"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad δεξιά"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad κέντρο"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Γραμμή υποτίτλων για την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Το πακέτο <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> τοποθετήθηκε στον κάδο ΠΕΡΙΟΡΙΣΜΕΝΗΣ ΠΡΟΣΒΑΣΗΣ."</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Πατήστε για ενεργοποίηση"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Δεν υπάρχουν εφαρμογές εργασιών"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Δεν υπάρχουν προσωπικές εφαρμογές"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Θέλετε να ανοίξετε την εφαρμογή <xliff:g id="APP">%s</xliff:g> στο προσωπικό σας προφίλ;"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Θέλετε να ανοίξετε την εφαρμογή <xliff:g id="APP">%s</xliff:g> στο προφίλ σας εργασίας;"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Χρήση προσωπικού προγράμματος περιήγησης"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Χρήση προγράμματος περιήγησης εργασίας"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"PIN ξεκλειδώματος δικτύου κάρτας SIM"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"Η εφαρμογή <xliff:g id="APP">%1$s</xliff:g> εκτελείται στο παρασκήνιο και καταναλώνει μπαταρία. Πατήστε για έλεγχο."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"Η εφαρμογή <xliff:g id="APP">%1$s</xliff:g> εκτελείται στο παρασκήνιο για πολύ ώρα. Πατήστε για έλεγχο."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Έλεγχος ενεργών εφαρμογών"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 83c345c..79a2e38 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -304,10 +304,8 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"access your calendar"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"send and view SMS messages"</string>
- <!-- no translation found for permgrouplab_storage (9173334109512154196) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (8352226729501080525) -->
- <skip />
+ <string name="permgrouplab_storage" msgid="9173334109512154196">"Files & documents"</string>
+ <string name="permgroupdesc_storage" msgid="8352226729501080525">"access files and documents on your device"</string>
<string name="permgrouplab_readMediaAural" msgid="5885210465560755316">"Music & other audio"</string>
<string name="permgroupdesc_readMediaAural" msgid="1170143315714662822">"access audio files on your device"</string>
<string name="permgrouplab_readMediaVisual" msgid="9137695801926624061">"Photos & videos"</string>
@@ -588,8 +586,9 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Enter your screen lock to continue"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Partial fingerprint detected"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Couldn\'t process fingerprint. Please try again."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Clean the sensor"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Hold a little longer"</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Clean fingerprint sensor and try again"</string>
+ <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Clean sensor and try again"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Press firmly on the sensor"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Finger moved too slow. Please try again."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Try another fingerprint"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Too bright"</string>
@@ -597,6 +596,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Change the position of your finger slightly each time"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"Fingerprint not recognised"</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="4709197752023550709">"Press firmly on the sensor"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingerprint authenticated"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Face authenticated"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Face authenticated. Please press confirm"</string>
@@ -1500,7 +1501,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Skip"</string>
<string name="no_matches" msgid="6472699895759164599">"No matches"</string>
<string name="find_on_page" msgid="5400537367077438198">"Find on page"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# match}other{# of {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Done"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Erasing shared storage…"</string>
<string name="share" msgid="4157615043345227321">"Share"</string>
@@ -1928,6 +1930,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Turn on"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> unavailable"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your Android TV device instead."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your tablet instead."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your phone instead."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"This app was built for an older version of Android and may not work properly. Try checking for updates or contact the developer."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Check for update"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"You have new messages"</string>
@@ -2017,16 +2023,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"UNINSTALL"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"OPEN ANYWAY"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Harmful app detected"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"System log access request"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Only this time"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Don’t allow"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> requests system logs for functional debugging. These logs might contain information that apps and services on your device have written."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Don’t show again"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wants to show <xliff:g id="APP_2">%2$s</xliff:g> slices"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Calls and notifications will vibrate"</string>
@@ -2119,10 +2120,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Tap to turn on"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"No work apps"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"No personal apps"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Open <xliff:g id="APP">%s</xliff:g> in your personal profile?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Open <xliff:g id="APP">%s</xliff:g> in your work profile?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Use personal browser"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Use work browser"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM network unlock PIN"</string>
@@ -2257,4 +2256,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> is running in the background and draining battery. Tap to review."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> is running in the background for a long time. Tap to review."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Check active apps"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 4128944..da99fdd 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -304,10 +304,8 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"access your calendar"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"send and view SMS messages"</string>
- <!-- no translation found for permgrouplab_storage (9173334109512154196) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (8352226729501080525) -->
- <skip />
+ <string name="permgrouplab_storage" msgid="9173334109512154196">"Files & documents"</string>
+ <string name="permgroupdesc_storage" msgid="8352226729501080525">"access files and documents on your device"</string>
<string name="permgrouplab_readMediaAural" msgid="5885210465560755316">"Music & other audio"</string>
<string name="permgroupdesc_readMediaAural" msgid="1170143315714662822">"access audio files on your device"</string>
<string name="permgrouplab_readMediaVisual" msgid="9137695801926624061">"Photos & videos"</string>
@@ -588,8 +586,9 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Enter your screen lock to continue"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Partial fingerprint detected"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Couldn\'t process fingerprint. Please try again."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Clean the sensor"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Hold a little longer"</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Clean fingerprint sensor and try again"</string>
+ <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Clean sensor and try again"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Press firmly on the sensor"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Finger moved too slow. Please try again."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Try another fingerprint"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Too bright"</string>
@@ -597,6 +596,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Change the position of your finger slightly each time"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"Fingerprint not recognised"</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="4709197752023550709">"Press firmly on the sensor"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingerprint authenticated"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Face authenticated"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Face authenticated. Please press confirm"</string>
@@ -1500,7 +1501,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Skip"</string>
<string name="no_matches" msgid="6472699895759164599">"No matches"</string>
<string name="find_on_page" msgid="5400537367077438198">"Find on page"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# match}other{# of {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Done"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Erasing shared storage…"</string>
<string name="share" msgid="4157615043345227321">"Share"</string>
@@ -1928,6 +1930,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Turn on"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> unavailable"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your Android TV device instead."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your tablet instead."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your phone instead."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"This app was built for an older version of Android and may not work properly. Try checking for updates or contact the developer."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Check for update"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"You have new messages"</string>
@@ -2017,16 +2023,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"UNINSTALL"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"OPEN ANYWAY"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Harmful app detected"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"System log access request"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Only this time"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Don’t allow"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> requests system logs for functional debugging. These logs might contain information that apps and services on your device have written."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Don’t show again"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wants to show <xliff:g id="APP_2">%2$s</xliff:g> slices"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Calls and notifications will vibrate"</string>
@@ -2119,10 +2120,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Tap to turn on"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"No work apps"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"No personal apps"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Open <xliff:g id="APP">%s</xliff:g> in your personal profile?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Open <xliff:g id="APP">%s</xliff:g> in your work profile?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Use personal browser"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Use work browser"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM network unlock PIN"</string>
@@ -2257,4 +2256,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> is running in the background and draining battery. Tap to review."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> is running in the background for a long time. Tap to review."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Check active apps"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 9be3de0..f01b9af 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -304,10 +304,8 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"access your calendar"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"send and view SMS messages"</string>
- <!-- no translation found for permgrouplab_storage (9173334109512154196) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (8352226729501080525) -->
- <skip />
+ <string name="permgrouplab_storage" msgid="9173334109512154196">"Files & documents"</string>
+ <string name="permgroupdesc_storage" msgid="8352226729501080525">"access files and documents on your device"</string>
<string name="permgrouplab_readMediaAural" msgid="5885210465560755316">"Music & other audio"</string>
<string name="permgroupdesc_readMediaAural" msgid="1170143315714662822">"access audio files on your device"</string>
<string name="permgrouplab_readMediaVisual" msgid="9137695801926624061">"Photos & videos"</string>
@@ -588,8 +586,9 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Enter your screen lock to continue"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Partial fingerprint detected"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Couldn\'t process fingerprint. Please try again."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Clean the sensor"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Hold a little longer"</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Clean fingerprint sensor and try again"</string>
+ <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Clean sensor and try again"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Press firmly on the sensor"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Finger moved too slow. Please try again."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Try another fingerprint"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Too bright"</string>
@@ -597,6 +596,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Change the position of your finger slightly each time"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"Fingerprint not recognised"</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="4709197752023550709">"Press firmly on the sensor"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingerprint authenticated"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Face authenticated"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Face authenticated. Please press confirm"</string>
@@ -1500,7 +1501,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Skip"</string>
<string name="no_matches" msgid="6472699895759164599">"No matches"</string>
<string name="find_on_page" msgid="5400537367077438198">"Find on page"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# match}other{# of {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Done"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Erasing shared storage…"</string>
<string name="share" msgid="4157615043345227321">"Share"</string>
@@ -1928,6 +1930,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Turn on"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> unavailable"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your Android TV device instead."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your tablet instead."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your phone instead."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"This app was built for an older version of Android and may not work properly. Try checking for updates or contact the developer."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Check for update"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"You have new messages"</string>
@@ -2017,16 +2023,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"UNINSTALL"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"OPEN ANYWAY"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Harmful app detected"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"System log access request"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Only this time"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Don’t allow"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> requests system logs for functional debugging. These logs might contain information that apps and services on your device have written."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Don’t show again"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wants to show <xliff:g id="APP_2">%2$s</xliff:g> slices"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Calls and notifications will vibrate"</string>
@@ -2119,10 +2120,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Tap to turn on"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"No work apps"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"No personal apps"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Open <xliff:g id="APP">%s</xliff:g> in your personal profile?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Open <xliff:g id="APP">%s</xliff:g> in your work profile?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Use personal browser"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Use work browser"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM network unlock PIN"</string>
@@ -2257,4 +2256,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> is running in the background and draining battery. Tap to review."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> is running in the background for a long time. Tap to review."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Check active apps"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index ed72a07..e509c70 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -304,10 +304,8 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"access your calendar"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"send and view SMS messages"</string>
- <!-- no translation found for permgrouplab_storage (9173334109512154196) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (8352226729501080525) -->
- <skip />
+ <string name="permgrouplab_storage" msgid="9173334109512154196">"Files & documents"</string>
+ <string name="permgroupdesc_storage" msgid="8352226729501080525">"access files and documents on your device"</string>
<string name="permgrouplab_readMediaAural" msgid="5885210465560755316">"Music & other audio"</string>
<string name="permgroupdesc_readMediaAural" msgid="1170143315714662822">"access audio files on your device"</string>
<string name="permgrouplab_readMediaVisual" msgid="9137695801926624061">"Photos & videos"</string>
@@ -588,8 +586,9 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Enter your screen lock to continue"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Partial fingerprint detected"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Couldn\'t process fingerprint. Please try again."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Clean the sensor"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Hold a little longer"</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Clean fingerprint sensor and try again"</string>
+ <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Clean sensor and try again"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Press firmly on the sensor"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Finger moved too slow. Please try again."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Try another fingerprint"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Too bright"</string>
@@ -597,6 +596,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Change the position of your finger slightly each time"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"Fingerprint not recognised"</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="4709197752023550709">"Press firmly on the sensor"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingerprint authenticated"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Face authenticated"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Face authenticated. Please press confirm"</string>
@@ -1500,7 +1501,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Skip"</string>
<string name="no_matches" msgid="6472699895759164599">"No matches"</string>
<string name="find_on_page" msgid="5400537367077438198">"Find on page"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# match}other{# of {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Done"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Erasing shared storage…"</string>
<string name="share" msgid="4157615043345227321">"Share"</string>
@@ -1928,6 +1930,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Turn on"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> unavailable"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your Android TV device instead."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your tablet instead."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your phone instead."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"This app was built for an older version of Android and may not work properly. Try checking for updates or contact the developer."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Check for update"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"You have new messages"</string>
@@ -2017,16 +2023,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"UNINSTALL"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"OPEN ANYWAY"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Harmful app detected"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"System log access request"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Only this time"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Don’t allow"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> requests system logs for functional debugging. These logs might contain information that apps and services on your device have written."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Don’t show again"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wants to show <xliff:g id="APP_2">%2$s</xliff:g> slices"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Calls and notifications will vibrate"</string>
@@ -2119,10 +2120,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Tap to turn on"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"No work apps"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"No personal apps"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Open <xliff:g id="APP">%s</xliff:g> in your personal profile?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Open <xliff:g id="APP">%s</xliff:g> in your work profile?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Use personal browser"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Use work browser"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM network unlock PIN"</string>
@@ -2257,4 +2256,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> is running in the background and draining battery. Tap to review."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> is running in the background for a long time. Tap to review."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Check active apps"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 7380d7d..ec6400c 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -304,18 +304,12 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"access your calendar"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"send and view SMS messages"</string>
- <!-- no translation found for permgrouplab_storage (9173334109512154196) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (8352226729501080525) -->
- <skip />
- <!-- no translation found for permgrouplab_readMediaAural (5885210465560755316) -->
- <skip />
- <!-- no translation found for permgroupdesc_readMediaAural (1170143315714662822) -->
- <skip />
- <!-- no translation found for permgrouplab_readMediaVisual (9137695801926624061) -->
- <skip />
- <!-- no translation found for permgroupdesc_readMediaVisual (173787212014117477) -->
- <skip />
+ <string name="permgrouplab_storage" msgid="9173334109512154196">"Files & documents"</string>
+ <string name="permgroupdesc_storage" msgid="8352226729501080525">"access files and documents on your device"</string>
+ <string name="permgrouplab_readMediaAural" msgid="5885210465560755316">"Music & other audio"</string>
+ <string name="permgroupdesc_readMediaAural" msgid="1170143315714662822">"access audio files on your device"</string>
+ <string name="permgrouplab_readMediaVisual" msgid="9137695801926624061">"Photos & videos"</string>
+ <string name="permgroupdesc_readMediaVisual" msgid="173787212014117477">"access images and video files on your device"</string>
<string name="permgrouplab_microphone" msgid="2480597427667420076">"Microphone"</string>
<string name="permgroupdesc_microphone" msgid="1047786732792487722">"record audio"</string>
<string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"Physical activity"</string>
@@ -592,8 +586,9 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Enter your screen lock to continue"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Partial fingerprint detected"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Couldn\'t process fingerprint. Please try again."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Clean the sensor"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Hold a little longer"</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Clean fingerprint sensor and try again"</string>
+ <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Clean sensor and try again"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Press firmly on the sensor"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Finger moved too slow. Please try again."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Try another fingerprint"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Too bright"</string>
@@ -601,6 +596,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Change the position of your finger slightly each time"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"Fingerprint not recognized"</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="4709197752023550709">"Press firmly on the sensor"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingerprint authenticated"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Face authenticated"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Face authenticated, please press confirm"</string>
@@ -687,18 +684,12 @@
<string name="permdesc_readSyncStats" msgid="3867809926567379434">"Allows an app to read the sync stats for an account, including the history of sync events and how much data is synced."</string>
<string name="permlab_sdcardRead" msgid="5791467020950064920">"read the contents of your shared storage"</string>
<string name="permdesc_sdcardRead" msgid="6872973242228240382">"Allows the app to read the contents of your shared storage."</string>
- <!-- no translation found for permlab_readMediaAudio (8723513075731763810) -->
- <skip />
- <!-- no translation found for permdesc_readMediaAudio (5299772574434619399) -->
- <skip />
- <!-- no translation found for permlab_readMediaVideo (7768003311260655007) -->
- <skip />
- <!-- no translation found for permdesc_readMediaVideo (3846400073770403528) -->
- <skip />
- <!-- no translation found for permlab_readMediaImage (1507059005825769856) -->
- <skip />
- <!-- no translation found for permdesc_readMediaImage (8328052622292457588) -->
- <skip />
+ <string name="permlab_readMediaAudio" msgid="8723513075731763810">"read audio files from shared storage"</string>
+ <string name="permdesc_readMediaAudio" msgid="5299772574434619399">"Allows the app to read audio files from your shared storage."</string>
+ <string name="permlab_readMediaVideo" msgid="7768003311260655007">"read video files from shared storage"</string>
+ <string name="permdesc_readMediaVideo" msgid="3846400073770403528">"Allows the app to read video files from your shared storage."</string>
+ <string name="permlab_readMediaImage" msgid="1507059005825769856">"read image files from shared storage"</string>
+ <string name="permdesc_readMediaImage" msgid="8328052622292457588">"Allows the app to read image files from your shared storage."</string>
<string name="permlab_sdcardWrite" msgid="4863021819671416668">"modify or delete the contents of your shared storage"</string>
<string name="permdesc_sdcardWrite" msgid="8376047679331387102">"Allows the app to write the contents of your shared storage."</string>
<string name="permlab_use_sip" msgid="8250774565189337477">"make/receive SIP calls"</string>
@@ -1510,7 +1501,7 @@
<string name="skip_button_label" msgid="3566599811326688389">"Skip"</string>
<string name="no_matches" msgid="6472699895759164599">"No matches"</string>
<string name="find_on_page" msgid="5400537367077438198">"Find on page"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# match}other{# of {total}}} }"</string>
+ <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# match}other{# of {total}}}"</string>
<string name="action_mode_done" msgid="2536182504764803222">"Done"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Erasing shared storage…"</string>
<string name="share" msgid="4157615043345227321">"Share"</string>
@@ -1938,6 +1929,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Turn on"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> unavailable"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your Android TV device instead."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your tablet instead."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your phone instead."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"This app was built for an older version of Android and may not work properly. Try checking for updates, or contact the developer."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Check for update"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"You have new messages"</string>
@@ -2260,4 +2255,5 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> is running in the background and draining battery. Tap to review."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> is running in the background for a long time. Tap to review."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Check active apps"</string>
+ <string name="vdm_camera_access_denied" msgid="6345652513729130490">"Cannot access camera from this device"</string>
</resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 5be2b28..23531ea 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Ingresa tu bloqueo de pantalla para continuar"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Detección parcial de una huella dactilar"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"No se pudo procesar la huella dactilar. Vuelve a intentarlo."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Limpia el sensor"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Mantén presionado un poco más"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Moviste el dedo muy lento. Vuelve a intentarlo."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Prueba con otra huella dactilar"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Demasiada luz"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Cambia un poco la posición del dedo cada vez"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Se autenticó la huella dactilar"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Se autenticó el rostro"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Se autenticó el rostro; presiona Confirmar"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Omitir"</string>
<string name="no_matches" msgid="6472699895759164599">"Sin coincidencias"</string>
<string name="find_on_page" msgid="5400537367077438198">"Buscar en la página"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# coincidencia}other{# de {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Listo"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Borrando almacenamiento compartido…"</string>
<string name="share" msgid="4157615043345227321">"Compartir"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activar"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"La app no está disponible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> no está disponible en este momento."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> no disponible"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Por el momento, no se puede acceder a esto en tu <xliff:g id="DEVICE">%1$s</xliff:g>. Inténtalo en tu dispositivo Android TV."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Por el momento, no se puede acceder a esto en tu <xliff:g id="DEVICE">%1$s</xliff:g>. Inténtalo en tu tablet."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Por el momento, no se puede acceder a esto en tu <xliff:g id="DEVICE">%1$s</xliff:g>. Inténtalo en tu teléfono."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Esta app se creó para una versión anterior de Android y es posible que no funcione correctamente. Busca actualizaciones o comunícate con el programador."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Buscar actualización"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Tienes mensajes nuevos"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"DESINSTALAR"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"ABRIR DE TODOS MODOS"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Se detectó una app dañina"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Solicitud de acceso a registro de sist."</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Solo esta vez"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"No permitir"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> requiere registros del sistema para una depuración correcta. Es posible que estos registros contengan información que hayan escrito apps y servicios en tu dispositivo."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"No volver a mostrar"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> quiere mostrar fragmentos de <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Editar"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Vibrarán las llamadas y notificaciones"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Diálogo de encendido"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Bloquear pantalla"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de pantalla"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Gancho para auriculares"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Acceso directo de accesibilidad en pantalla"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Selector del acceso directo de accesibilidad en pantalla"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Acceso directo de accesibilidad"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Descartar panel de notificaciones"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Pad direccional: arriba"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Pad direccional: abajo"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Pad direccional: izquierda"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Pad direccional: derecha"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Pad direccional: centro"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de subtítulos de <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Se colocó <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> en el bucket RESTRICTED"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Presionar para activar"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"El contenido no es compatible con apps de trabajo"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"El contenido no es compatible con apps personales"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"¿Quieres abrir <xliff:g id="APP">%s</xliff:g> en tu perfil personal?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"¿Quieres abrir <xliff:g id="APP">%s</xliff:g> en tu perfil de trabajo?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Usar un navegador personal"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Usar un navegador de trabajo"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"PIN de desbloqueo del dispositivo para la red de tarjeta SIM"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> se está ejecutando en segundo plano y está agotando la batería. Presiona para revisar esta actividad."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"Hace mucho tiempo que <xliff:g id="APP">%1$s</xliff:g> se está ejecutando en segundo plano. Presiona para revisar esta actividad."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Consulta las apps activas"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 4316d02..7c0d36b 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Introduce tu bloqueo de pantalla para continuar"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Huella digital parcial detectada"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"No se ha podido procesar la huella digital. Vuelve a intentarlo."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Limpia el sensor"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Mantén pulsado un poco más"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Has movido el dedo demasiado despacio. Vuelve a intentarlo."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Prueba con otra huella digital"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Demasiada luz"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Cambia ligeramente el dedo de posición cada vez"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Se ha autenticado la huella digital"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Cara autenticada"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Se ha autenticado la cara, pulsa para confirmar"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Saltar"</string>
<string name="no_matches" msgid="6472699895759164599">"No hay coincidencias."</string>
<string name="find_on_page" msgid="5400537367077438198">"Buscar en la página"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# coincidencia}other{# de {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Hecho"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Borrando almacenamiento compartido…"</string>
<string name="share" msgid="4157615043345227321">"Compartir"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activar"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"La aplicación no está disponible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"En estos momentos, <xliff:g id="APP_NAME">%1$s</xliff:g> no está disponible."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> no disponible"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"En estos momentos, no se puede acceder a este contenido en tu <xliff:g id="DEVICE">%1$s</xliff:g>. Prueba en tu dispositivo Android TV."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"En estos momentos, no se puede acceder a este contenido en tu <xliff:g id="DEVICE">%1$s</xliff:g>. Prueba en tu tablet."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"En estos momentos, no se puede acceder a este contenido en tu <xliff:g id="DEVICE">%1$s</xliff:g>. Prueba en tu teléfono."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Esta aplicación se ha diseñado para una versión anterior de Android y es posible que no funcione correctamente. Busca actualizaciones o ponte en contacto con el desarrollador."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Buscar actualizaciones"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Tienes mensajes nuevos"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"DESINSTALAR"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"ABRIR IGUALMENTE"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Se ha detectado una aplicación dañina"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Solicitud de acceso a registro del sistema"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Solo esta vez"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"No permitir"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> necesita los registros del sistema para hacer depuraciones funcionales. Es posible que estos registros contengan información introducida por las aplicaciones y los servicios de tu dispositivo."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"No volver a mostrar"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> quiere mostrar fragmentos de <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Editar"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Las llamadas y las notificaciones vibrarán"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Abrir cuadro de diálogo"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Pantalla de bloqueo"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de pantalla"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Gancho de los auriculares"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Acceso directo de accesibilidad en pantalla"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Menú de acceso directo de accesibilidad en pantalla"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Acceso directo de accesibilidad"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Cerrar pantalla de notificaciones"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Cruceta: arriba"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Cruceta: abajo"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Cruceta: izquierda"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Cruceta: derecha"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Cruceta: centro"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de subtítulos de <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> se ha incluido en el grupo de restringidos"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Toca para activar"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Ninguna aplicación de trabajo"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Ninguna aplicación personal"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"¿Abrir <xliff:g id="APP">%s</xliff:g> en tu perfil personal?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"¿Abrir <xliff:g id="APP">%s</xliff:g> en tu perfil de trabajo?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Usar navegador personal"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Usar navegador de trabajo"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"PIN de desbloqueo de red de tarjeta SIM"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> se está ejecutando en segundo plano y consumiendo batería. Toca para revisarlo."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> lleva mucho tiempo ejecutándose en segundo plano. Toca para revisarlo."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Consultar aplicaciones activas"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index b7e7a20..8c2e458 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Jätkamiseks sisestage oma ekraanilukk"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Tuvastati osaline sõrmejälg"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Sõrmejälge ei õnnestunud töödelda. Proovige uuesti."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Puhastage andur"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Hoidke veidi kauem"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Sõrm liikus liiga aeglaselt. Proovige uuesti."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Proovige teist sõrmejälge"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Liiga ere"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Muutke iga kord pisut oma sõrme asendit"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Sõrmejälg autenditi"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Nägu on autenditud"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Nägu on autenditud, vajutage käsku Kinnita"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Jäta vahele"</string>
<string name="no_matches" msgid="6472699895759164599">"Vasted puuduvad"</string>
<string name="find_on_page" msgid="5400537367077438198">"Otsige lehelt"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# vaste}other{#/{total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Valmis"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Jagatud salvestusruumi tühjendamine …"</string>
<string name="share" msgid="4157615043345227321">"Jaga"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Lülita sisse"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Rakendus ei ole saadaval"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei ole praegu saadaval."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ei ole saadaval"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Sellele ei pääse praegu teie seadmega (<xliff:g id="DEVICE">%1$s</xliff:g>) juurde. Proovige juurde pääseda oma Android TV seadmega."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Sellele ei pääse praegu teie seadmega (<xliff:g id="DEVICE">%1$s</xliff:g>) juurde. Proovige juurde pääseda oma tahvelarvutiga."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Sellele ei pääse praegu teie seadmega (<xliff:g id="DEVICE">%1$s</xliff:g>) juurde. Proovige juurde pääseda oma telefoniga."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"See rakendus on loodud Androidi vanema versiooni jaoks ega pruugi õigesti töötada. Otsige värskendusi või võtke ühendust arendajaga."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Otsi värskendust"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Teile on uusi sõnumeid"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"DESINSTALLI"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"AVA IKKA"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Tuvastati kahjulik rakendus"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Süsteemilogi juurdepääsutaotlus"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Ainult see kord"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ära luba"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> taotleb funktsionaalseks silumiseks süsteemilogisid. Need logid võivad sisaldada teavet, mille teie seadmes olevad rakendused ja teenused on kirjutanud."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ära kuva uuesti"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Rakendus <xliff:g id="APP_0">%1$s</xliff:g> soovib näidata rakenduse <xliff:g id="APP_2">%2$s</xliff:g> lõike"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Muuda"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Kõnede ja märguannete puhul seade vibreerib"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Energiasäästja dialoog"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lukustuskuva"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekraanipilt"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Peakomplekti haak"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Ekraanil kuvatav juurdepääsetavuse otsetee"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Ekraanil kuvatav juurdepääsetavuse otsetee valija"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Juurdepääsetavuse otsetee"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Loobu märguandealast"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Suunaklahvistiku ülesnool"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Suunaklahvistiku allanool"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Suunaklahvistiku vasaknool"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Suunaklahvistiku paremnool"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Suunaklahvistiku keskmine nupp"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> pealkirjariba."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> on lisatud salve PIIRANGUTEGA"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Puudutage sisselülitamiseks"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Töörakendusi pole"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Isiklikke rakendusi pole"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Kas avada <xliff:g id="APP">%s</xliff:g> teie isiklikul profiilil?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Kas avada <xliff:g id="APP">%s</xliff:g> teie tööprofiilil?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Kasuta isiklikku brauserit"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Kasuta tööbrauserit"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM-kaardi võrgu avamise PIN-kood"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> töötab taustal ja kulutab akut. Puudutage ülevaatamiseks."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> on taustal töötanud kaua aega. Puudutage ülevaatamiseks."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Vaadake aktiivseid rakendusi"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 9d37e97..4c07e40 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Aurrera egiteko, desblokeatu pantailaren blokeoa"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Hatz-marka ez da osorik hauteman"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Ezin izan da prozesatu hatz-marka. Saiatu berriro."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Garbitu sentsorea"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Azkarregi altxatu duzu hatza"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Mantsoegi mugitu duzu hatza. Saiatu berriro."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Erabili beste hatz-marka bat"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Argi gehiegi dago"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Aldi bakoitzean, aldatu hatzaren posizioa apur bat"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Autentifikatu da hatz-marka"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Autentifikatu da aurpegia"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Autentifikatu da aurpegia; sakatu Berretsi"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Saltatu"</string>
<string name="no_matches" msgid="6472699895759164599">"Ez dago emaitzarik"</string>
<string name="find_on_page" msgid="5400537367077438198">"Aurkitu orri honetan"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# partida}other{#/{total} partida}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Eginda"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Biltegi partekatuko eduki guztia ezabatzen…"</string>
<string name="share" msgid="4157615043345227321">"Partekatu"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aktibatu"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikazioa ez dago erabilgarri"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ez dago erabilgarri une honetan."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ez dago erabilgarri"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Une honetan, aplikazioa ezin da <xliff:g id="DEVICE">%1$s</xliff:g> erabilita atzitu. Gailu horren ordez, erabili Android TV gailua."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Une honetan, aplikazioa ezin da <xliff:g id="DEVICE">%1$s</xliff:g> erabilita atzitu. Gailu horren ordez, erabili tableta."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Une honetan, aplikazioa ezin da <xliff:g id="DEVICE">%1$s</xliff:g> erabilita atzitu. Gailu horren ordez, erabili telefonoa."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Aplikazioa Android-en bertsio zaharrago baterako sortu zenez, baliteke behar bezala ez funtzionatzea. Bilatu eguneratzerik baden, edo jarri garatzailearekin harremanetan."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Bilatu eguneratzeak"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Mezu berriak dituzu"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"DESINSTALATU"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"IREKI, HALA ERE"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Aplikazio kaltegarri bat hauteman da"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Sistemaren erregistroak atzitzeko eskaera"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Oraingoan soilik"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ez eman baimenik"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> aplikazioak sistemaren erregistroak atzitu behar ditu funtzioak arazteko. Litekeena da gailuko aplikazio eta zerbitzuek idatzitako informazioa agertzea erregistro horietan."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ez erakutsi berriro"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> aplikazioak <xliff:g id="APP_2">%2$s</xliff:g> aplikazioaren zatiak erakutsi nahi ditu"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Editatu"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Dar-dar egingo du deiak eta jakinarazpenak jasotzean"</string>
@@ -2119,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Sakatu aktibatzeko"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Ez dago laneko aplikaziorik"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Ez dago aplikazio pertsonalik"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Profil pertsonalean ireki nahi duzu <xliff:g id="APP">%s</xliff:g>?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Laneko profilean ireki nahi duzu <xliff:g id="APP">%s</xliff:g>?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Erabili arakatzaile pertsonala"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Erabili laneko arakatzailea"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIMaren sarearen bidez desblokeatzeko PINa"</string>
@@ -2257,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> atzeko planoan exekutatzen eta bateria xahutzen ari da. Sakatu berrikusteko."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> aplikazioak denbora asko darama atzeko planoan exekutatzen. Sakatu berrikusteko."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Ikusi zer aplikazio dauden aktibo"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 2cba13c..9b35e07 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"برای ادامه، قفل صفحهتان را وارد کنید"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"بخشی از اثر انگشت شناسایی شد"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"اثرانگشت پردازش نشد. لطفاً دوباره امتحان کنید."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"حسگر را پاک کنید"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"کمی بیشتر نگه دارید"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"حرکت انگشت خیلی آهسته بود. لطفاً دوباره امتحان کنید."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"اثر انگشت دیگری را امتحان کنید"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"خیلی روشن است"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"هربار موقعیت انگشتتان را کمی تغییر دهید"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"اثر انگشت اصالتسنجی شد"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"چهره اصالتسنجی شد"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"چهره اصالتسنجی شد، لطفاً تأیید را فشار دهید"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"رد شدن"</string>
<string name="no_matches" msgid="6472699895759164599">"مورد منطبقی موجود نیست"</string>
<string name="find_on_page" msgid="5400537367077438198">"یافتن در صفحه"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# مورد منطبق}one{# از {total}}other{# از {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"تمام"</string>
<string name="progress_erasing" msgid="6891435992721028004">"درحال پاک کردن فضای ذخیرهسازی همرسانیشده…"</string>
<string name="share" msgid="4157615043345227321">"همرسانی"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"روشن کردن"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"برنامه در دسترس نیست"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> درحالحاضر در دسترس نیست."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> دردسترس نیست"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"درحالحاضر نمیتوان در <xliff:g id="DEVICE">%1$s</xliff:g> شما به این برنامه دسترسی داشت. دسترسی به آن را در دستگاه Android TV امتحان کنید."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"درحالحاضر نمیتوان در <xliff:g id="DEVICE">%1$s</xliff:g> شما به این برنامه دسترسی داشت. دسترسی به آن را در رایانه لوحیتان امتحان کنید."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"درحالحاضر نمیتوان در <xliff:g id="DEVICE">%1$s</xliff:g> شما به این برنامه دسترسی داشت. دسترسی به آن را در تلفنتان امتحان کنید."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"این برنامه برای نسخه قدیمیتری از Android ساخته شده است و ممکن است درست کار نکند. وجود بهروزرسانی را بررسی کنید یا با برنامهنویس تماس بگیرید."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"بررسی وجود بهروزرسانی"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"پیامهای جدیدی دارید"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"حذف نصب"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"درهرصورت باز شود"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"برنامه مضر شناسایی شد"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"درخواست دسترسی به گزارش سیستم"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"فقط این بار"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"مجاز نیست"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> گزارشهای سیستم را برای اشکالزدایی عملکردی درخواست میکند. این گزارشها ممکن است حاوی اطلاعاتی باشد که برنامهها و سرویسهای موجود در دستگاهتان نوشتهاند."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"دوباره نشان داده نشود"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> میخواهد تکههای <xliff:g id="APP_2">%2$s</xliff:g> را نشان دهد"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"ویرایش"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"دستگاهتان برای تماسها و اعلانها میلرزد"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"کادر گفتگوی روشن/خاموش"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"صفحه قفل"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"نماگرفت"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"قلاب هدست"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"میانبر دسترسپذیری روی صفحه"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"انتخابگر میانبر دسترسپذیری روی صفحه"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"میانبر دسترسیپذیری"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"رد کردن کشوی اعلانات"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"پد کنترل بالا"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"پد کنترل پایین"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"پد کنترل چپ"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"پد کنترل راست"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"پد کنترل وسط"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"نوار شرح <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> در سطل «محدودشده» قرار گرفت"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"برای روشن کردن، ضربه بزنید"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"برنامه کاریای وجود ندارد"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"برنامه شخصیای وجود ندارد"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"<xliff:g id="APP">%s</xliff:g> در نمایه شخصی باز شود؟"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"<xliff:g id="APP">%s</xliff:g> در نمایه کاری باز شود؟"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"استفاده از مرورگر شخصی"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"استفاده از مرورگر کاری"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"پین باز کردن قفل شبکه سیمکارت"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> در پسزمینه اجرا میشود و شارژ باتری را تخلیه میکند. برای مرور، ضربه بزنید."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> برای مدتی طولانی در پسزمینه اجرا میشود. برای مرور، ضربه بزنید."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"بررسی برنامههای فعال"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index a369352..10adae8 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Jatka lisäämällä näytön lukituksen avaustapa"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Osittainen sormenjälki havaittu"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Sormenjäljen prosessointi epäonnistui. Yritä uudelleen."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Puhdista anturi"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Jatka vielä hetki"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Liikutit sormea liian hitaasti. Yritä uudelleen."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Kokeile toista sormenjälkeä"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Liian kirkas"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Liikuta sormeasi hieman joka kerralla"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Sormenjälki tunnistettu"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Kasvot tunnistettu"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Kasvot tunnistettu, valitse Vahvista"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Ohita"</string>
<string name="no_matches" msgid="6472699895759164599">"Ei tuloksia"</string>
<string name="find_on_page" msgid="5400537367077438198">"Etsi sivulta"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# osumaa}other{# / {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Valmis"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Tyhjennetään jaettua tallennustilaa…"</string>
<string name="share" msgid="4157615043345227321">"Jaa"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Ota käyttöön"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Sovellus ei ole käytettävissä"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei ole nyt käytettävissä."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ei käytettävissä"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"<xliff:g id="DEVICE">%1$s</xliff:g> ei tällä hetkellä saa pääsyä sovellukseen. Kokeile striimausta Android TV ‑laitteella."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"<xliff:g id="DEVICE">%1$s</xliff:g> ei tällä hetkellä saa pääsyä sovellukseen. Kokeile striimausta tabletilla."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"<xliff:g id="DEVICE">%1$s</xliff:g> ei tällä hetkellä saa pääsyä sovellukseen. Kokeile striimausta puhelimella."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Tämä sovellus on suunniteltu vanhemmalle Android-versiolle eikä välttämättä toimi oikein. Kokeile tarkistaa päivitykset tai ottaa yhteyttä kehittäjään."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Tarkista päivitykset"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Sinulle on uusia viestejä"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"POISTA"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"AVAA SILTI"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Haitallinen sovellus havaittu"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Järjestelmälokin pääsyoikeuspyyntö"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Vain tämän kerran"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Älä salli"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> pyytää järjestelmälokeja virheenkorjausta varten. Lokeissa voi olla tietoja, jotka ovat peräisin laitteellasi olevista sovelluksista ja palveluista."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Älä näytä uudelleen"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> haluaa näyttää osia sovelluksesta <xliff:g id="APP_2">%2$s</xliff:g>."</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Muokkaa"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Puhelut ja ilmoitukset värisevät"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Virran valintaikkuna"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lukitusnäyttö"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Kuvakaappaus"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Kuulokemikrofonin koukku"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Näytöllä näkyvä esteettömyyspainike"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Näytöllä näkyvän esteettömyyspainikkeen valitsin"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Esteettömyyspainike"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Sulje ilmoitusalue"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Suuntanäppäimistö: ylös-painike"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Suuntanäppäimisto: alas-painike"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Suuntanäppäimistö: vasen painike"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Suuntanäppäimistö: oikea painike"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Suuntanäppäimistö: keskipainike"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Tekstityspalkki: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> on nyt rajoitettujen ryhmässä"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Laita päälle napauttamalla"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Ei työsovelluksia"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Ei henkilökohtaisia sovelluksia"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Avataanko <xliff:g id="APP">%s</xliff:g> henkilökohtaisessa profiilissa?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Avataanko <xliff:g id="APP">%s</xliff:g> työprofiilissa?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Käytä henkilökohtaista selainta"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Käytä työselainta"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM-kortin verkkoversion lukituksen avaamisen PIN-koodi"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> on käynnissä taustalla ja kuluttaa akkua. Tarkista napauttamalla."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> on ollut käynnissä taustalla pitkän aikaa. Tarkista napauttamalla."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Tarkista aktiiviset sovellukset"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 6884198..43b061d 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Entrez votre verrouillage d\'écran pour continuer"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Empreinte digitale partielle détectée"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Impossible de reconnaître l\'empreinte digitale. Veuillez réessayer."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Nettoyez le capteur"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Maintenez le doigt en place un peu plus longtemps"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Vous avez déplacé votre doigt trop lentement. Veuillez réessayer."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Essayez une autre empreinte digitale"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Trop lumineux"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Modifiez légèrement la position de votre doigt chaque fois"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Empreinte digitale authentifiée"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Visage authentifié"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Visage authentifié, veuillez appuyer sur le bouton Confirmer"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Ignorer"</string>
<string name="no_matches" msgid="6472699895759164599">"Aucune partie"</string>
<string name="find_on_page" msgid="5400537367077438198">"Rechercher sur la page"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# correspondance}one{# de {total}}other{# de {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Terminé"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Effacement du stockage partagé en cours…"</string>
<string name="share" msgid="4157615043345227321">"Partager"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activer"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"L\'application n\'est pas accessible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas accessible pour le moment."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> non accessible"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Impossible d\'accéder à ce contenu sur votre appareil <xliff:g id="DEVICE">%1$s</xliff:g> pour le moment. Essayez sur votre appareil Android TV à la place."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Impossible d\'accéder à ce contenu sur votre appareil <xliff:g id="DEVICE">%1$s</xliff:g> pour le moment. Essayez sur votre tablette à la place."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Impossible d\'accéder à ce contenu sur votre appareil <xliff:g id="DEVICE">%1$s</xliff:g> pour le moment. Essayez sur votre téléphone à la place."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Cette application a été conçue pour une ancienne version d\'Android et pourrait ne pas fonctionner correctement. Essayez de vérifier les mises à jour ou communiquez avec son développeur."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Vérifier la présence de mises à jour"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Vous avez de nouveaux messages"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"DÉSINSTALLER"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"OUVRIR QUAND MÊME"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Une application nuisible a été détectée"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Demande d\'accès aux journaux système"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Seulement cette fois"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ne pas autoriser"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> demande l\'accès aux journaux système aux fins de débogage fonctionnel. Ces journaux peuvent contenir des informations écrites par des applications et des services sur votre appareil."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne plus afficher"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> souhaite afficher <xliff:g id="APP_2">%2$s</xliff:g> tranches"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Modifier"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Les appels et les notifications vibreront"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Boîte de dialogue sur l\'alimentation"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Écran de verrouillage"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Capture d\'écran"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Crochet de casque d\'écoute"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Raccourci d\'accessibilité à l\'écran"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Sélecteur de raccourci d\'accessibilité à l\'écran"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Raccourci d\'accessibilité"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Ignorer le volet de notification"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Pavé directionnel – haut"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Pavé directionnel – bas"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Pavé directionnel – gauche"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Pavé directionnel – droite"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Pavé directionnel – centre"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barre de légende de l\'application <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a été placé dans le compartiment RESTREINT"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g> :"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Touchez pour activer"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Aucune application professionnelle"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Aucune application personnelle"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Ouvrir <xliff:g id="APP">%s</xliff:g> dans votre profil personnel?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Ouvrir <xliff:g id="APP">%s</xliff:g> dans votre profil professionnel?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Utiliser le navigateur du profil personnel"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Utiliser le navigateur du profil professionnel"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"NIP de déverrouillage du réseau associé au module SIM"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> s\'exécute en arrière-plan et décharge rapidement la pile. Touchez pour examiner."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> s\'exécute en arrière-plan depuis longtemps. Touchez pour examiner."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Vérifier les applications actives"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index db64970..7770aed 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -265,7 +265,7 @@
<string name="global_action_settings" msgid="4671878836947494217">"Paramètres"</string>
<string name="global_action_assist" msgid="2517047220311505805">"Assistance"</string>
<string name="global_action_voice_assist" msgid="6655788068555086695">"Assistance vocale"</string>
- <string name="global_action_lockdown" msgid="2475471405907902963">"Verrouillé"</string>
+ <string name="global_action_lockdown" msgid="2475471405907902963">"Verrouiller"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">">999"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Nouvelle notification"</string>
<string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Clavier virtuel"</string>
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Utilisez le verrouillage de l\'écran pour continuer"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Empreinte partielle détectée"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Impossible de reconnaître l\'empreinte digitale. Veuillez réessayer."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Nettoyez le lecteur"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Maintenez un peu plus longtemps"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Vous avez déplacé votre doigt trop lentement. Veuillez réessayer."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Essayez une autre empreinte"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Trop de lumière"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Changez légèrement de position chaque fois"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Empreinte digitale authentifiée"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Visage authentifié"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Visage authentifié, veuillez appuyer sur \"Confirmer\""</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Ignorer"</string>
<string name="no_matches" msgid="6472699895759164599">"Aucune correspondance"</string>
<string name="find_on_page" msgid="5400537367077438198">"Rechercher sur la page"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{ résultat }one{ sur {total}}other{ sur {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"OK"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Suppression de l\'espace de stockage partagé…"</string>
<string name="share" msgid="4157615043345227321">"Partager"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activer"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Application non disponible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas disponible pour le moment."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> indisponible"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Actuellement, vous ne pouvez pas accéder à cette application sur votre <xliff:g id="DEVICE">%1$s</xliff:g>. Essayez plutôt d\'y accéder sur votre appareil Android TV."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Actuellement, vous ne pouvez pas accéder à cette application sur votre <xliff:g id="DEVICE">%1$s</xliff:g>. Essayez plutôt d\'y accéder sur votre tablette."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Actuellement, vous ne pouvez pas accéder à cette application sur votre <xliff:g id="DEVICE">%1$s</xliff:g>. Essayez plutôt d\'y accéder sur votre téléphone."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Cette application a été conçue pour une ancienne version d\'Android et risque de ne pas fonctionner correctement. Recherchez des mises à jour ou contactez le développeur."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Rechercher une mise à jour"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Vous avez de nouveaux messages"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"DÉSINSTALLER"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"OUVRIR QUAND MÊME"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Application dangereuse détectée"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Demande d\'accès aux journaux système"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Cette fois seulement"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ne pas autoriser"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"Journaux système des demandes <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> pour le débogage fonctionnel. Ces journaux peuvent contenir des informations écrites par les applis et services de votre appareil."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne plus afficher"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> souhaite afficher des éléments de <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Modifier"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Vibreur pour les appels et les notifications"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Boîte de dialogue Marche/Arrêt"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Verrouiller l\'écran"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Capture d\'écran"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Crochet du casque"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Raccourci d\'accessibilité à l\'écran"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Outil de sélection des raccourcis d\'accessibilité à l\'écran"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Raccourci d\'accessibilité"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Fermer le volet des notifications"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Pavé directionnel - Haut"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Pavé directionnel - Bas"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Pavé directionnel - Gauche"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Pavé directionnel - Droite"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Pavé directionnel - Centre"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barre de légende de l\'application <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a été placé dans le bucket RESTRICTED"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g> :"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Appuyez pour l\'activer"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Aucune appli professionnelle"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Aucune appli personnelle"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Ouvrir <xliff:g id="APP">%s</xliff:g> dans votre profil personnel ?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Ouvrir <xliff:g id="APP">%s</xliff:g> dans votre profil professionnel ?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Utiliser le navigateur personnel"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Utiliser le navigateur professionnel"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"Code PIN de déblocage du réseau SIM"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> s\'exécute en arrière-plan et décharge la batterie. Appuyez ici pour en savoir plus."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> s\'exécute en arrière-plan depuis longtemps. Appuyez ici pour en savoir plus."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Vérifier les applis actives"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 43454c0..6db4a32 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Desbloquea a pantalla para continuar"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Detectouse unha impresión dixital parcial"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Non se puido procesar a impresión dixital. Téntao de novo."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Limpa o sensor"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Mantén o dedo no sensor un pouco máis"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"O dedo moveuse demasiado lento. Téntao de novo."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Proba con outra impresión dixital"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Hai demasiada luz"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Cambia lixeiramente a posición do dedo en cada intento"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Autenticouse a impresión dixital"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Autenticouse a cara"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Autenticouse a cara, preme Confirmar"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Omitir"</string>
<string name="no_matches" msgid="6472699895759164599">"Non hai coincidencias"</string>
<string name="find_on_page" msgid="5400537367077438198">"Buscar na páxina"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# coincidencia}other{# de {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Feito"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Borrando almacenamento compartido…"</string>
<string name="share" msgid="4157615043345227321">"Compartir"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activar"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"A aplicación non está dispoñible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"A aplicación <xliff:g id="APP_NAME">%1$s</xliff:g> non está dispoñible neste momento."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> non está dispoñible"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Nestes momentos, non podes acceder a este contido desde o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>). Proba a facelo desde o dispositivo con Android TV."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Nestes momentos, non podes acceder a este contido desde o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>). Proba a facelo desde a tableta."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Nestes momentos, non podes acceder a este contido desde o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>). Proba a facelo desde o teléfono."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Esta aplicación deseñouse para unha versión anterior de Android e quizais non funcione correctamente. Proba a buscar actualizacións ou contacta co programador."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Buscar actualización"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Tes mensaxes novas"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"DESINSTALAR"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"ABRIR IGUALMENTE"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Detectouse unha aplicación daniña"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Solicitude acceso a rexistros do sistema"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Só esta vez"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Non permitir"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> solicita rexistros do sistema para realizar unha depuración funcional. Estes rexistros poderían conter información que escribiron as aplicacións e os servizos do teu dispositivo."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Non amosar outra vez"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> quere mostrar fragmentos de aplicación de <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Editar"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"As chamadas e as notificacións vibrarán"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Cadro de diálogo de acendido/apagado"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Pantalla de bloqueo"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de pantalla"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Gancho para auriculares"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Atallo de accesibilidade en pantalla"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Selector de atallos de accesibilidade en pantalla"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Atallo de accesibilidade"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Ignorar panel despregable"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Botón direccional: arriba"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Botón direccional: abaixo"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Botón direccional: esquerda"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Botón direccional: dereita"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Botón direccional: centro"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de subtítulos de <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> incluíuse no grupo RESTRINXIDO"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Tocar para activar o perfil"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Non hai ningunha aplicación do traballo compatible"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Non hai ningunha aplicación persoal compatible"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Queres abrir <xliff:g id="APP">%s</xliff:g> no teu perfil persoal?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Queres abrir <xliff:g id="APP">%s</xliff:g> no teu perfil de traballo?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Utilizar navegador persoal"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Utilizar navegador de traballo"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"PIN de desbloqueo da rede SIM"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> está executándose en segundo plano e consumindo batería. Toca para revisalo."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> leva moito tempo executándose en segundo plano. Toca para revisalo."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Comprobar aplicacións activas"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 1f4ca30..fe1b92b 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"આગળ વધવા માટે તમારું સ્ક્રીન લૉક દાખલ કરો"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"આંશિક ફિંગરપ્રિન્ટ મળી"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ફિંગરપ્રિન્ટ પ્રક્રિયા કરી શકાઈ નથી. કૃપા કરીને ફરી પ્રયાસ કરો."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"સેન્સર સાફ કરો"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"આંગળીને થોડો વધુ સમય સેન્સર પર રાખો"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"આંગળી બહુ જ ધીમેથી ખસેડી. કૃપા કરીને ફરી પ્રયાસ કરો."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"અન્ય ફિંગરપ્રિન્ટ અજમાવી જુઓ"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"અતિશય પ્રકાશિત"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"દરેક વખતે સ્કૅનર પર તમારી આંગળીની સ્થિતિ સહેજ બદલતા રહો"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ફિંગરપ્રિન્ટ પ્રમાણિત કરી"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"ચહેરા પ્રમાણિત"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"ચહેરા પ્રમાણિત, કૃપા કરીને કન્ફર્મ કરો"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"છોડો"</string>
<string name="no_matches" msgid="6472699895759164599">"કોઈ મેળ નથી"</string>
<string name="find_on_page" msgid="5400537367077438198">"પૃષ્ઠ પર શોધો"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{{total}માંથી }one{# મેળ {total}માંથી }other{# મેળ}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"થઈ ગયું"</string>
<string name="progress_erasing" msgid="6891435992721028004">"શેર કરેલ સ્ટોરેજ ભૂસી રહ્યાં છીએ…"</string>
<string name="share" msgid="4157615043345227321">"શેર કરો"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"ચાલુ કરો"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ઍપ ઉપલબ્ધ નથી"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> હાલમાં ઉપલબ્ધ નથી."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ઉપલબ્ધ નથી"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"અત્યારે આને તમારા <xliff:g id="DEVICE">%1$s</xliff:g> પર ઍક્સેસ કરી શકાતી નથી. તેના બદલે તમારા Android TV ડિવાઇસ પર પ્રયાસ કરો."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"અત્યારે આને તમારા <xliff:g id="DEVICE">%1$s</xliff:g> પર ઍક્સેસ કરી શકાતી નથી. તેના બદલે તમારા ટૅબ્લેટ પર પ્રયાસ કરો."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"અત્યારે આને તમારા <xliff:g id="DEVICE">%1$s</xliff:g> પર ઍક્સેસ કરી શકાતી નથી. તેના બદલે તમારા ફોન પર પ્રયાસ કરો."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"આ ઍપ Androidના જૂના વર્ઝન માટે બનાવવામાં આવ્યું હતું અને તે કદાચ તે યોગ્ય રીતે કાર્ય કરી શકશે નહીં. અપડેટ માટે તપાસવાનો પ્રયાસ કરો અથવા ડેવલપરનો સંપર્ક કરો."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"અપડેટ માટે તપાસો"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"તમારી પાસે નવા સંદેશા છે"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"અનઇન્સ્ટૉલ કરો"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"કોઈપણ રીતે ખોલો"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"નુકસાનકારક ઍપ મળી આવી છે"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"સિસ્ટમ લૉગ ઍક્સેસ કરવાની વિનંતી"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"માત્ર આ વખતે"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"મંજૂરી આપશો નહીં"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"ફંક્શનલ ડિબગીંગ માટે, <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> સિસ્ટમ લૉગની વિનંતી કરે છે. તમારા ડિવાઇસ પરની ઍપ અને સેવાઓએ લખેલી માહિતી આ લૉગમાં શામેલ હોઈ શકે છે."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"ફરીથી બતાવશો નહીં"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g>એ <xliff:g id="APP_2">%2$s</xliff:g> સ્લાઇસ બતાવવા માગે છે"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"ફેરફાર કરો"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"કૉલ અને નોટિફિકેશન માટે ઉપકરણ વાઇબ્રેટ થશે"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"પાવર સંવાદ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"લૉક સ્ક્રીન"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"સ્ક્રીનશૉટ"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"હૅડસેટ હુક"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"સ્ક્રીન પરના ઍક્સેસિબિલિટી શૉર્ટકટ"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"સ્ક્રીન પરના ઍક્સેસિબિલિટી શૉર્ટકટના પસંદકર્તા"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"ઍક્સેસિબિલિટી શૉર્ટકટ"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"નોટિફિકેશન શેડ છોડી દો"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"ડી-પૅડ ઉપર"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"ડી-પૅડ નીચે"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"ડી-પૅડ ડાબે"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"ડી-પૅડ જમણે"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"ડી-પૅડ મધ્યમાં"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>નું કૅપ્શન બાર."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>ને પ્રતિબંધિત સમૂહમાં મૂકવામાં આવ્યું છે"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"ચાલુ કરવા માટે ટૅપ કરો"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"કોઈ ઑફિસ માટેની ઍપ સપોર્ટ કરતી નથી"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"કોઈ વ્યક્તિગત ઍપ સપોર્ટ કરતી નથી"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"તમારી વ્યક્તિગત પ્રોફાઇલમાં <xliff:g id="APP">%s</xliff:g> ખોલીએ?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"તમારી ઑફિસની પ્રોફાઇલમાં <xliff:g id="APP">%s</xliff:g> ખોલીએ?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"વ્યક્તિગત બ્રાઉઝરનો ઉપયોગ કરો"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"ઑફિસના બ્રાઉઝરના ઉપયોગ કરો"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"સિમ નેટવર્કને અનલૉક કરવાનો પિન"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> બૅકગ્રાઉન્ડમાં ચાલી રહી છે અને અતિશય બૅટરી વાપરી રહી છે. રિવ્યૂ કરવા માટે ટૅપ કરો."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> લાંબા સમયથી બૅકગ્રાઉન્ડમાં ચાલી રહી છે. રિવ્યૂ કરવા માટે ટૅપ કરો."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"સક્રિય ઍપ ચેક કરો"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 0a5585b..3cf2137 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"जारी रखने के लिए, अपने स्क्रीन लॉक की पुष्टि करें"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"पूरा फ़िंगरप्रिंट पहचाना नहीं जा सका"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"फ़िंगरप्रिंट प्रोसेस नहीं हो सका. कृपया दोबारा कोशिश करें."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"सेंसर को साफ़ करें"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"उंगली को थोड़ी देर और सेंसर पर रखें"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"उंगली बहुत धीरे चलाई गई. कृपया फिर से कोशिश करें."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"किसी दूसरे फ़िंगरप्रिंट से कोशिश करें"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"बहुत रोशनी है"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"फ़िंगरप्रिंट सेट अप करते समय, अपनी उंगली को हर बार थोड़ी अलग स्थिति में रखें"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"फ़िंगरप्रिंट की पुष्टि हो गई"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"चेहरे की पहचान की गई"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"चेहरे की पहचान की गई, कृपया पुष्टि बटन दबाएं"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"अभी नहीं"</string>
<string name="no_matches" msgid="6472699895759164599">"कोई मिलान नहीं"</string>
<string name="find_on_page" msgid="5400537367077438198">"पेज पर ढूंढें"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# नतीजा{total} में से }one{# {total} में से }other{# }} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"हो गया"</string>
<string name="progress_erasing" msgid="6891435992721028004">"शेयर की गई मेमोरी हमेशा के लिए मिटाई जा रही है…"</string>
<string name="share" msgid="4157615043345227321">"शेयर करें"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"चालू करें"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ऐप्लिकेशन उपलब्ध नहीं है"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> इस समय उपलब्ध नहीं है."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> उपलब्ध नहीं है"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"इस समय, आपके <xliff:g id="DEVICE">%1$s</xliff:g> पर इसे ऐक्सेस नहीं किया जा सकता. इसके बजाय, अपने Android TV डिवाइस पर कोशिश करें."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"इस समय, आपके <xliff:g id="DEVICE">%1$s</xliff:g> पर इसे ऐक्सेस नहीं किया जा सकता. इसके बजाय, अपने टैबलेट पर कोशिश करें."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"इस समय, आपके <xliff:g id="DEVICE">%1$s</xliff:g> पर इसे ऐक्सेस नहीं किया जा सकता. इसके बजाय, अपने फ़ोन पर कोशिश करें."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"यह ऐप्लिकेशन Android के पुराने वर्शन के लिए बनाया गया था, इसलिए हो सकता है कि यह सही से काम न करे. देखें कि अपडेट मौजूद हैं या नहीं, या फिर डेवलपर से संपर्क करें."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"देखें कि अपडेट मौजूद है या नहीं"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"आपके पास नए संदेश हैं"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"अनइंस्टॉल करें"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"फिर भी खोलें"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"नुकसान पहुंचाने वाले ऐप का पता चला"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"सिस्टम लॉग को ऐक्सेस करने का अनुरोध"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"सिर्फ़ इस बार"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"अनुमति न दें"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"फ़ंक्शनल डीबगिंग के लिए, <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> का सिस्टम लॉग के लिए अनुरोध. इन लॉग में आपके डिवाइस पर मौजूद ऐप्लिकेशन और सेवाओं से मिली जानकारी शामिल हो सकती है."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"फिर से न दिखाएं"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g>, <xliff:g id="APP_2">%2$s</xliff:g> के हिस्से (स्लाइस) दिखाना चाहता है"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"बदलाव करें"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"कॉल और सूचनाओं के लिए डिवाइस वाइब्रेट हाेगा"</string>
@@ -2119,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"वर्क प्रोफ़ाइल चालू करने के लिए टैप करें"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"यह कॉन्टेंट, ऑफ़िस के काम से जुड़े आपके किसी भी ऐप्लिकेशन पर खोला नहीं जा सकता"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"यह कॉन्टेंट आपके किसी भी निजी ऐप्लिकेशन पर खोला नहीं जा सकता"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"क्या <xliff:g id="APP">%s</xliff:g> को निजी प्रोफ़ाइल में खोलना है?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"क्या <xliff:g id="APP">%s</xliff:g> को वर्क प्रोफ़ाइल में खोलना है?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"निजी ब्राउज़र का इस्तेमाल करें"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"ऑफ़िस के काम से जुड़े ब्राउज़र का इस्तेमाल करें"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"सिम नेटवर्क को अनलॉक करने का पिन"</string>
@@ -2257,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> बैकग्राउंड में चल रहा है और बैटरी खर्च कर रहा है. देखने के लिए टैप करें."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> बैकग्राउंड में बहुत देर से चल रहा है. देखने के लिए टैप करें."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"चालू ऐप्लिकेशन देखें"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 50d5f68..14139ea 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -589,8 +589,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Upotrijebite zaključavanje zaslona da biste nastavili"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Otkriven je djelomični otisak prsta"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Obrada otiska prsta nije uspjela. Pokušajte ponovo."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Očistite senzor"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Zadržite još malo"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Presporo pomicanje prsta. Pokušajte ponovo."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Isprobajte drugi otisak prsta"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Presvijetlo"</string>
@@ -598,6 +602,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Svaki put lagano promijenite položaj prsta"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Autentificirano otiskom prsta"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Lice je autentificirano"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Lice je autentificirano, pritisnite Potvrdi"</string>
@@ -1501,7 +1509,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Preskoči"</string>
<string name="no_matches" msgid="6472699895759164599">"Nema rezultata"</string>
<string name="find_on_page" msgid="5400537367077438198">"Pronađi na stranici"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# podudaranje}one{# od {total}}few{# od {total}}other{# od {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Gotovo"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Brisanje dijeljene pohrane…"</string>
<string name="share" msgid="4157615043345227321">"Dijeli"</string>
@@ -1929,6 +1938,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Uključi"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija nije dostupna"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutačno nije dostupna."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> – nije dostupno"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Trenutačno toj aplikaciji nije moguće pristupiti na vašem uređaju <xliff:g id="DEVICE">%1$s</xliff:g>. Pokušajte joj pristupiti na Android TV uređaju."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Trenutačno toj aplikaciji nije moguće pristupiti na vašem uređaju <xliff:g id="DEVICE">%1$s</xliff:g>. Pokušajte joj pristupiti na svojem tabletu."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Trenutačno toj aplikaciji nije moguće pristupiti na vašem uređaju <xliff:g id="DEVICE">%1$s</xliff:g>. Pokušajte joj pristupiti na svojem telefonu."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ova je aplikacija razvijena za stariju verziju Androida i možda neće funkcionirati pravilno. Potražite ažuriranja ili se obratite razvojnom programeru."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Provjeri ažuriranja"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Imate nove poruke"</string>
@@ -2018,16 +2031,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"DEINSTALIRAJ"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"IPAK OTVORI"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Otkrivena je štetna aplikacija"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Zahtjev za pristup zapisnicima sustava"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Samo ovaj put"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nemoj dopustiti"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"Aplikacija <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> zahtijeva zapisnike sustava radi funkcionalnog otklanjanja pogrešaka. Ti zapisnici mogu sadržavati podatke koje su zabilježile aplikacije i usluge na vašem uređaju."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne prikazuj ponovo"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> želi prikazivati isječke aplikacije <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Uredi"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Uređaj će vibrirati za pozive i obavijesti"</string>
@@ -2090,22 +2098,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dijalog napajanja"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Zaključajte zaslon"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snimka zaslona"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Kuka za slušalice"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Prečac pristupačnosti na zaslonu"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Alat za odabir prečaca pristupačnosti na zaslonu"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Prečac pristupačnosti"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Odbacivanje zaslona obavijesti"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Gore na plohi za smjerove"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Dolje na plohi za smjerove"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Lijevo na plohi za smjerove"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Desno na plohi za smjerove"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"U središtu plohe za smjerove"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Traka naslova aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> premješten je u spremnik OGRANIČENO"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2126,10 +2128,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Dodirnite da biste uključili"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Poslovne aplikacije nisu dostupne"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Osobne aplikacije nisu dostupne"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Želite li otvoriti aplikaciju <xliff:g id="APP">%s</xliff:g> na osobnom profilu?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Želite li otvoriti aplikaciju <xliff:g id="APP">%s</xliff:g> na poslovnom profilu?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Koristi osobni preglednik"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Koristi poslovni preglednik"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"PIN za otključavanje SIM mreže."</string>
@@ -2264,4 +2264,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> izvodi se u pozadini i prazni bateriju. Dodirnite za pregled."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> dugo se izvodi u pozadini. Dodirnite za pregled."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Provjera aktivnih aplikacija"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 9260a7c..f94f063 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -304,10 +304,8 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"hozzáférés a naptárhoz"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS-ek küldése és megtekintése"</string>
- <!-- no translation found for permgrouplab_storage (9173334109512154196) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (8352226729501080525) -->
- <skip />
+ <string name="permgrouplab_storage" msgid="9173334109512154196">"Fájlok és dokumentumok"</string>
+ <string name="permgroupdesc_storage" msgid="8352226729501080525">"hozzáférhet fájljaihoz és dokumentumaihoz az eszközén"</string>
<string name="permgrouplab_readMediaAural" msgid="5885210465560755316">"Zenék és más audiotartalmak"</string>
<string name="permgroupdesc_readMediaAural" msgid="1170143315714662822">"hozzáférés az eszközön található hangfájlokhoz"</string>
<string name="permgrouplab_readMediaVisual" msgid="9137695801926624061">"Fotók és videók"</string>
@@ -588,8 +586,9 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"A folytatáshoz adja meg a képernyőzár hitelesítési adatait"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"A rendszer részleges ujjlenyomatot észlelt"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Nem sikerült feldolgozni az ujjlenyomatot. Próbálkozzon újra."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Tisztítsa meg az érzékelőt"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Ne mozdítsa meg az ujját még egy kicsit"</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Tisztítsa meg az ujjlenyomat-érzékelőt, majd próbálja újra"</string>
+ <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Tisztítsa meg az érzékelőt, majd próbálja újra"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Nyomja meg határozottan az érzékelőt"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Túl lassan húzta az ujját. Próbálkozzon újra."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Próbálkozzon másik ujjlenyomattal"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Túl világos"</string>
@@ -597,6 +596,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Módosítsa minden alkalommal kis mértékben ujja helyzetét."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"Az ujjlenyomat nem ismerhető fel"</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="4709197752023550709">"Nyomja meg határozottan az érzékelőt"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Ujjlenyomat hitelesítve"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Arc hitelesítve"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Arc hitelesítve; nyomja meg a Megerősítés lehetőséget"</string>
@@ -1500,7 +1501,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Kihagyás"</string>
<string name="no_matches" msgid="6472699895759164599">"Nincs találat"</string>
<string name="find_on_page" msgid="5400537367077438198">"Keresés az oldalon"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# találat {total}/}other{# }} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Kész"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Közös tárhely tartalmának törlése…"</string>
<string name="share" msgid="4157615043345227321">"Megosztás"</string>
@@ -1928,6 +1930,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Bekapcsolás"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Az alkalmazás nem hozzáférhető"</string>
<string name="app_blocked_message" msgid="542972921087873023">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> jelenleg nem hozzáférhető."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"A(z) <xliff:g id="ACTIVITY">%1$s</xliff:g> nem áll rendelkezése"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Ehhez jelenleg nem lehet hozzáférni a következő eszközön: <xliff:g id="DEVICE">%1$s</xliff:g>. Próbálja újra Android TV-eszközén."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Ehhez jelenleg nem lehet hozzáférni a következő eszközön: <xliff:g id="DEVICE">%1$s</xliff:g>. Próbálja újra a táblagépén."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Ehhez jelenleg nem lehet hozzáférni a következő eszközön: <xliff:g id="DEVICE">%1$s</xliff:g>. Próbálja újra a telefonján."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ez az alkalmazás az Android egyik korábbi verziójához készült, így elképzelhető, hogy nem működik majd megfelelően ezen a rendszeren. Keressen frissítéseket, vagy vegye fel a kapcsolatot a fejlesztővel."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Frissítés keresése"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Új üzenetei érkeztek"</string>
@@ -2017,16 +2023,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ELTÁVOLÍTÁS"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"MEGNYITÁS MÉGIS"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"A rendszer kártékony alkalmazást észlelt"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Rendszernaplókhoz való hozzáférés kérése"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Csak most"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Tiltás"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"Funkcionális hibaelhárítás céljából a(z) <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> hozzáférést kér a rendszernaplókhoz. A naplókban olyan információk lehetnek, amelyek az eszközön használt alkalmazásoktól és szolgáltatásoktól származnak."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne jelenjen meg újra"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"A(z) <xliff:g id="APP_0">%1$s</xliff:g> alkalmazás részleteket szeretne megjeleníteni a(z) <xliff:g id="APP_2">%2$s</xliff:g> alkalmazásból"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Szerkesztés"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"A hívások és az értesítések rezegnek"</string>
@@ -2089,22 +2090,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Akkumulátorral kapcsolatos párbeszédpanel"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lezárási képernyő"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Képernyőkép"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Headsetkampó"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Képernyőn megjelenő kisegítő lehetőségekre vonatkozó parancs"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Képernyőn megjelenő kisegítő lehetőségekre vonatkozó parancsválasztó"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Kisegítő lehetőségek gyorsparancsa"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Értesítési felület bezárása"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"D-pad – fel"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"D-pad – le"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"D-pad – balra"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"D-pad – jobbra"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"D-pad – középre"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazás címsora."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"A következő csomag a KORLÁTOZOTT csoportba került: <xliff:g id="PACKAGE_NAME">%1$s</xliff:g>"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2120,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Koppintson a bekapcsoláshoz"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Nincs munkahelyi alkalmazás"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Nincs személyes alkalmazás"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Megnyitja a(z) <xliff:g id="APP">%s</xliff:g> alkalmazást a személyes profil használatával?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Megnyitja a(z) <xliff:g id="APP">%s</xliff:g> alkalmazást a munkaprofil használatával?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Személyes böngésző használata"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Munkahelyi böngésző használata"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"Hálózati SIM feloldó PIN-kódja"</string>
@@ -2263,4 +2256,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"A(z) <xliff:g id="APP">%1$s</xliff:g> alkalmazás fut a háttérben, és meríti az akkumulátort. Koppintson az áttekintéshez."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"A(z) <xliff:g id="APP">%1$s</xliff:g> alkalmazás már hosszú ideje fut a háttérben. Koppintson az áttekintéshez."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Aktív alkalmazások ellenőrzése"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index ddbc9cf..ea6eddd 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Շարունակելու համար ապակողպեք էկրանը"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Մատնահետքն ամբողջությամբ չի սկանավորվել"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Չհաջողվեց մշակել մատնահետքը: Նորից փորձեք:"</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Մաքրեք մատնահետքի սկաները"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Փոքր-ինչ երկար պահեք"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Շատ դանդաղ անցկացրիք մատը: Փորձեք նորից:"</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Փորձեք մեկ այլ մատնահետք"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Շատ լուսավոր է"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Ամեն անգամ թեթևակի փոխեք մատի դիրքը"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Մատնահետքը նույնականացվեց"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Դեմքը ճանաչվեց"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Դեմքը ճանաչվեց: Սեղմեք «Հաստատել»:"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Բաց թողնել"</string>
<string name="no_matches" msgid="6472699895759164599">"Համընկնում չկա"</string>
<string name="find_on_page" msgid="5400537367077438198">"Գտեք էջում"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# համընկնում}one{#-ը՝ {total}-ից}other{#-ը՝ {total}-ից}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Պատրաստ է"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Ընդհանուր հիշողությունը ջնջվում է…"</string>
<string name="share" msgid="4157615043345227321">"Կիսվել"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Միացնել"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Հավելվածը հասանելի չէ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածն այս պահին հասանելի չէ։"</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g>՝ անհասանելի է"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Այս պահին հնարավոր չէ բացել հավելվածը <xliff:g id="DEVICE">%1$s</xliff:g> սարքում։ Փորձեք Android TV սարքում։"</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Այս պահին հնարավոր չէ բացել հավելվածը <xliff:g id="DEVICE">%1$s</xliff:g> սարքում։ Փորձեք ձեր պլանշետում։"</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Այս պահին հնարավոր չէ բացել հավելվածը <xliff:g id="DEVICE">%1$s</xliff:g> սարքում։ Փորձեք ձեր հեռախոսում։"</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Այս հավելվածը ստեղծվել է Android-ի ավելի հին տարբերակի համար և կարող է պատշաճ չաշխատել: Ստուգեք թարմացումների առկայությունը կամ դիմեք մշակողին:"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Ստուգել նոր տարբերակի առկայությունը"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Դուք ունեք նոր հաղորդագրություններ"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ԱՊԱՏԵՂԱԴՐԵԼ"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"ԲԱՑԵԼ"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Հայտնաբերվել է վնասաբեր հավելված"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Համակարգի մատյանների օգտագործման հարցում"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Միայն այս անգամ"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Չթույլատրել"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> հավելվածը համակարգի մատյաններն օգտագործելու թույլտվություն է խնդրում՝ ֆունկցիոնալ վրիպազերծում կատարելու համար։ Այս մատյանները կարող են պարունակել տեղեկություններ, որոնք գրվել են ձեր սարքի հավելվածների ու ծառայությունների կողմից։"</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Այլևս ցույց չտալ"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> հավելվածն ուզում է ցուցադրել հատվածներ <xliff:g id="APP_2">%2$s</xliff:g> հավելվածից"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Փոփոխել"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Զանգերի և ծանուցումների համար թրթռոցը միացված է"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Սնուցման պատուհան"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Կողպէկրան"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Սքրինշոթ"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Ականջակալի կարթ"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Հատուկ գործառույթների դյուրանցում"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Հատուկ գործառույթների դյուրանցման ընտրիչ"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Հատուկ գործառույթների դյուրանցում"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Փակել ծանուցումների վահանակը"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Dpad-ի «Վերև» կոճակ"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Dpad-ի «Ներքև» կոճակ"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad-ի «Ձախ» կոճակ"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad-ի «Աջ» կոճակ"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad-ի «Կենտրոն» կոճակ"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի ենթագրերի գոտին։"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> փաթեթը գցվեց ՍԱՀՄԱՆԱՓԱԿՎԱԾ զամբյուղի մեջ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>՝"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Հպեք՝ միացնելու համար"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Աշխատանքային հավելվածներ չկան"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Անձնական հավելվածներ չկան"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Բացե՞լ <xliff:g id="APP">%s</xliff:g> հավելվածը ձեր անձնական պրոֆիլում"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Բացե՞լ <xliff:g id="APP">%s</xliff:g> հավելվածը ձեր աշխատանքային պրոֆիլում"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Օգտագործել անձնական դիտարկիչը"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Օգտագործել աշխատանքային դիտարկիչը"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM Network քարտի ապակողպման PIN"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> հավելվածն աշխատում է ֆոնային ռեժիմում և սպառում է մարտկոցի լիցքը։ Հպեք՝ դիտելու համար։"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> հավելվածը երկար ժամանակ աշխատում է ֆոնային ռեժիմում։ Հպեք՝ դիտելու համար։"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Ստուգել ակտիվ հավելվածները"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 65e0cc0..de24aa5 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Masukkan kunci layar untuk melanjutkan"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Sebagian sidik jari terdeteksi"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Tidak dapat memproses sidik jari. Coba lagi."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Bersihkan sensor"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Tahan sedikit lebih lama"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Jari digerakkan terlalu lambat. Coba lagi."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Coba sidik jari lain"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Terlalu terang"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Ubah sedikit posisi jari di setiap percobaan"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Sidik jari diautentikasi"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Wajah diautentikasi"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Wajah diautentikasi, silakan tekan konfirmasi"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Lewati"</string>
<string name="no_matches" msgid="6472699895759164599">"Tidak ada kecocokan"</string>
<string name="find_on_page" msgid="5400537367077438198">"Temukan pada halaman"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# cocok}other{# dari {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Selesai"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Menghapus penyimpanan bersama…"</string>
<string name="share" msgid="4157615043345227321">"Bagikan"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aktifkan"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikasi tidak tersedia"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak tersedia saat ini."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> tidak tersedia"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Aplikasi ini tidak dapat diakses di <xliff:g id="DEVICE">%1$s</xliff:g> untuk saat ini. Coba di perangkat Android TV."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Aplikasi ini tidak dapat diakses di <xliff:g id="DEVICE">%1$s</xliff:g> untuk saat ini. Coba di tablet."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Aplikasi ini tidak dapat diakses di <xliff:g id="DEVICE">%1$s</xliff:g> untuk saat ini. Coba di ponsel."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Aplikasi ini dibuat untuk Android versi lama dan mungkin tidak berfungsi sebagaimana mestinya. Coba periksa apakah ada update, atau hubungi developer."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Periksa apakah ada update"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Ada pesan baru"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"UNINSTAL"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"TETAP BUKA"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Aplikasi berbahaya terdeteksi"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Permintaan akses log sistem"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Hanya kali ini"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Jangan izinkan"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> meminta log sistem untuk proses debug fungsional. Log ini mungkin berisi informasi yang telah ditulis oleh aplikasi dan layanan di perangkat Anda."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Jangan tampilkan lagi"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ingin menampilkan potongan <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Panggilan dan notifikasi akan bergetar"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialog Daya"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Layar Kunci"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Headset Hook"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Pintasan Aksesibilitas di layar"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Pemilih Pintasan Aksesibilitas di layar"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Pintasan Aksesibilitas"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Tutup Menu Notifikasi"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Dpad Atas"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Dpad Bawah"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad Kiri"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad Kanan"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad Tengah"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Kolom teks <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> telah dimasukkan ke dalam bucket DIBATASI"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Ketuk untuk mengaktifkan"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Tidak ada aplikasi kerja"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Tidak ada aplikasi pribadi"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Buka <xliff:g id="APP">%s</xliff:g> di profil pribadi?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Buka <xliff:g id="APP">%s</xliff:g> di profil kerja?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Gunakan browser pribadi"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Gunakan browser kerja"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"PIN pembuka kunci SIM network"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> berjalan di latar belakang dan menghabiskan daya baterai. Ketuk untuk meninjau."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> berjalan di latar belakang dalam waktu yang lama. Ketuk untuk meninjau."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Periksa aplikasi aktif"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 3a38bf8..4b2f371 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Sláðu inn skjálásinn þinn til að halda áfram"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Hluti fingrafars greindist"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Ekki var hægt að vinna úr fingrafarinu. Reyndu aftur."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Hreinsaðu lesarann"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Haltu aðeins lengur"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Fingurinn hreyfðist of hægt. Reyndu aftur."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Prófaðu annað fingrafar"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Of bjart"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Breyttu stöðu fingursins örlítið í hvert skipti"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingrafar staðfest"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Andlit staðfest"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Andlit staðfest, ýttu til að staðfesta"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Sleppa"</string>
<string name="no_matches" msgid="6472699895759164599">"Engar samsvaranir"</string>
<string name="find_on_page" msgid="5400537367077438198">"Finna á síðu"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# samsvörun}one{# af {total}}other{# af {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Lokið"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Eyðir samnýttri geymslu…"</string>
<string name="share" msgid="4157615043345227321">"Deila"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Kveikja"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Forrit er ekki tiltækt"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> er ekki tiltækt núna."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ekki í boði"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Aðgangur að þessu í <xliff:g id="DEVICE">%1$s</xliff:g> er ekki í boði eins og er. Prófaðu það í Android TV tækinu í staðinn."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Aðgangur að þessu í <xliff:g id="DEVICE">%1$s</xliff:g> er ekki í boði eins og er. Prófaðu það í spjaldtölvunni í staðinn."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Aðgangur að þessu í <xliff:g id="DEVICE">%1$s</xliff:g> er ekki í boði eins og er. Prófaðu það í símanum í staðinn."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Þetta forrit var hannað fyrir eldri útgáfu af Android og ekki er víst að það virki eðlilega. Athugaðu hvort uppfærslur séu í boði eða hafðu samband við þróunaraðilann."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Leita að uppfærslu"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Þú ert með ný skilaboð"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"FJARLÆGJA"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"OPNA SAMT"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Skaðlegt forrit fannst"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Beiðni um aðgang að kerfisannálum"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Aðeins í þetta skipti"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ekki leyfa"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> biður um kerfisannála fyrir virka villuleit. Annálarnir kunna að innihalda upplýsingar sem forrit og þjónustur í tækinu þínu hafa skrifað."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ekki sýna aftur"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> vill sýna sneiðar úr <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Breyta"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Titringur er virkur fyrir símtöl og tilkynningar"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Gluggi til að slökkva/endurræsa"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lásskjár"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skjámynd"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Höfuðtólasnagi"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Flýtileið í aðgengiseiginleika á skjánum"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Val um flýtileið í aðgengiseiginleika á skjánum"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Flýtileið aðgengisstillingar"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Loka tilkynningaglugga"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Upphnappur stýriflatar"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Niðurhnappur stýriflatar"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Vinstrihnappur stýriflatar"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Hægrihnappur stýriflatar"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Miðjuhnappur stýriflatar"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Skjátextastika <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> var sett í flokkinn TAKMARKAÐ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Ýttu til að kveikja"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Engin vinnuforrit"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Engin forrit til einkanota"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Opna <xliff:g id="APP">%s</xliff:g> í þínu eigin sniði?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Opna <xliff:g id="APP">%s</xliff:g> í vinnusniðinu þínu?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Nota einkavafra"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Nota vinnuvafra"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"PIN-númer fyrir opnun á SIM-korti netkerfis"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> keyrir í bakgrunni og eyðir rafhlöðuorku. Ýttu til að skoða."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> hefur keyrt lengi í bakgrunni. Ýttu til að skoða."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Skoða virk forrit"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 9f047b4..b246d79 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -304,10 +304,8 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"Possono accedere al calendario"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"Possono inviare e visualizzare SMS"</string>
- <!-- no translation found for permgrouplab_storage (9173334109512154196) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (8352226729501080525) -->
- <skip />
+ <string name="permgrouplab_storage" msgid="9173334109512154196">"File e documenti"</string>
+ <string name="permgroupdesc_storage" msgid="8352226729501080525">"Consente di accedere a file e documenti sul tuo dispositivo"</string>
<string name="permgrouplab_readMediaAural" msgid="5885210465560755316">"Musica e altro audio"</string>
<string name="permgroupdesc_readMediaAural" msgid="1170143315714662822">"Accesso ai file audio sul tuo dispositivo"</string>
<string name="permgrouplab_readMediaVisual" msgid="9137695801926624061">"Foto e video"</string>
@@ -588,8 +586,9 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Inserisci il blocco schermo per continuare"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Rilevata impronta parziale"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Impossibile elaborare l\'impronta. Riprova."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Pulisci il sensore"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Tieni premuto un po\' più a lungo"</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Pulisci il sensore di impronte digitali e riprova"</string>
+ <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Pulisci il sensore e riprova"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Premi con decisione sul sensore"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Movimento del dito troppo lento. Riprova."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Prova con un\'altra impronta"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Troppa luce"</string>
@@ -597,6 +596,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Cambia leggermente la posizione del dito ogni volta"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"Impronta non riconosciuta"</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="4709197752023550709">"Premi con decisione sul sensore"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Impronta autenticata"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Volto autenticato"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Volto autenticato, premi Conferma"</string>
@@ -1500,7 +1501,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Salta"</string>
<string name="no_matches" msgid="6472699895759164599">"Nessuna corrispondenza"</string>
<string name="find_on_page" msgid="5400537367077438198">"Trova nella pagina"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# corrispondenza}one{# di {total}}other{# di {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Fine"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Cancellazione archivio condiviso…"</string>
<string name="share" msgid="4157615043345227321">"Condividi"</string>
@@ -1928,6 +1930,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Attiva"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"L\'app non è disponibile"</string>
<string name="app_blocked_message" msgid="542972921087873023">"L\'app <xliff:g id="APP_NAME">%1$s</xliff:g> non è al momento disponibile."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> non disponibile"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Al momento non è possibile accedere a questa app su <xliff:g id="DEVICE">%1$s</xliff:g>. Prova a usare il dispositivo Android TV."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Al momento non è possibile accedere a questa app su <xliff:g id="DEVICE">%1$s</xliff:g>. Prova a usare il tablet."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Al momento non è possibile accedere a questa app su <xliff:g id="DEVICE">%1$s</xliff:g>. Prova a usare il telefono."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Questa app è stata realizzata per una versione precedente di Android e potrebbe non funzionare correttamente. Prova a verificare la disponibilità di aggiornamenti o contatta lo sviluppatore."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Cerca aggiornamenti"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Hai nuovi messaggi"</string>
@@ -2089,22 +2095,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Finestra di dialogo Alimentazione"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Schermata di blocco"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Hook cuffie"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Scorciatoia Accessibilità sullo schermo"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Selettore scorciatoia Accessibilità sullo schermo"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Scorciatoia Accessibilità"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Ignora area notifiche"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"D-pad - Su"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"D-pad - Giù"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"D-pad - Sinistra"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"D-pad - Destra"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"D-pad - Centro"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra del titolo di <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> è stato inserito nel bucket RESTRICTED"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> è in esecuzione in background e sta consumando la batteria. Tocca per controllare."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> è in esecuzione in background da molto tempo. Tocca per controllare."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Verifica le app attive"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 14208e4..7cd023f 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -590,8 +590,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"יש לבטל את נעילת המסך כדי להמשיך"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"זוהתה טביעת אצבע חלקית"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"לא ניתן היה לעבד את טביעת האצבע. אפשר לנסות שוב."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"יש לנקות את החיישן"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"עליך להשאיר את האצבע על החיישן קצת יותר זמן"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"הזזת את האצבע לאט מדי. יש לנסות שוב."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"יש להשתמש בטביעת אצבע אחרת"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"בהיר מדי"</string>
@@ -599,6 +603,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"צריך לשנות מעט את תנוחת האצבע בכל פעם"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"טביעת האצבע אומתה"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"זיהוי הפנים בוצע"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"זיהוי הפנים בוצע. יש ללחוץ על אישור"</string>
@@ -1502,7 +1510,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"דילוג"</string>
<string name="no_matches" msgid="6472699895759164599">"אין התאמות"</string>
<string name="find_on_page" msgid="5400537367077438198">"חיפוש בדף"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{התאמה אחת}two{# מתוך {total}}many{# מתוך {total}}other{# מתוך {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"סיום"</string>
<string name="progress_erasing" msgid="6891435992721028004">"בתהליך מחיקה של אחסון משותף…"</string>
<string name="share" msgid="4157615043345227321">"שיתוף"</string>
@@ -1930,6 +1939,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"הפעלה"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"האפליקציה לא זמינה"</string>
<string name="app_blocked_message" msgid="542972921087873023">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> לא זמינה בשלב זה."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> לא זמינה"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"אי אפשר לגשת לאפליקציה הזו במכשיר <xliff:g id="DEVICE">%1$s</xliff:g> כרגע. במקום זאת, יש לנסות במכשיר Android TV."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"אי אפשר לגשת לאפליקציה הזו במכשיר <xliff:g id="DEVICE">%1$s</xliff:g> כרגע. במקום זאת, יש לנסות בטאבלט."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"אי אפשר לגשת לאפליקציה הזו במכשיר <xliff:g id="DEVICE">%1$s</xliff:g> כרגע. במקום זאת, יש לנסות בטלפון."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"האפליקציה הזו עוצבה לגרסה ישנה יותר של Android וייתכן שלא תפעל כראוי. ניתן לבדוק אם יש עדכונים או ליצור קשר עם המפתח."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"יש עדכון חדש?"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"יש לך הודעות חדשות"</string>
@@ -2019,16 +2032,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"הסרת התקנה"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"לפתוח בכל זאת"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"אותרה אפליקציה מזיקה"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"בקשת גישה ליומן מערכת"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"רק הפעם"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"אין אישור"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"האפליקציה <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> מבקשת יומני מערכת לצורך ניפוי באגים פונקציונלי. יכול להיות שהיומנים האלה מכילים מידע שנכתב על ידי אפליקציות ושירותים שבמכשיר שלך."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"אין להציג שוב"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> רוצה להציג חלקים מ-<xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"עריכה"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"שיחות והודעות ירטטו"</string>
@@ -2091,22 +2099,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"תיבת דו-שיח לגבי הסוללה"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"מסך הנעילה"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"צילום מסך"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"הוק לאוזניות"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"קיצור דרך לנגישות במסך"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"בורר קיצורי דרך לנגישות במסך"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"קיצור דרך לנגישות"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"סגירת לוח ההתראות"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"לחצן עליון ב-Dpad"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"לחצן תחתון ב-Dpad"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"לחצן שמאלי ב-Dpad"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"לחצן ימני ב-Dpad"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"לחצן אמצעי ב-Dpad"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"סרגל כיתוב של <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> התווספה לקטגוריה \'מוגבל\'"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2127,10 +2129,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"יש להקיש כדי להפעיל את פרופיל העבודה"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"אין אפליקציות לעבודה"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"אין אפליקציות לשימוש אישי"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"לפתוח את <xliff:g id="APP">%s</xliff:g> בפרופיל האישי?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"לפתוח את <xliff:g id="APP">%s</xliff:g> בפרופיל העבודה?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"בדפדפן האישי"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"בדפדפן של העבודה"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"קוד אימות לביטול הנעילה של רשת SIM"</string>
@@ -2265,4 +2265,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"האפליקציה <xliff:g id="APP">%1$s</xliff:g> פועלת ברקע ומרוקנת את הסוללה. יש להקיש כדי לבדוק."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"האפליקציה <xliff:g id="APP">%1$s</xliff:g> פועלת ברקע במשך הרבה זמן. יש להקיש כדי לבדוק."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"כדאי לבדוק את האפליקציות הפעילות"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 99435f4..0c70187 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -30,7 +30,7 @@
<string name="untitled" msgid="3381766946944136678">"<新規>"</string>
<string name="emptyPhoneNumber" msgid="5812172618020360048">"(電話番号なし)"</string>
<string name="unknownName" msgid="7078697621109055330">"不明"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"ボイスメール"</string>
+ <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"留守番電話"</string>
<string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
<string name="mmiError" msgid="2862759606579822246">"接続に問題があるか、MMIコードが正しくありません。"</string>
<string name="mmiFdnError" msgid="3975490266767565852">"発信番号制限で指定された番号に対してのみ操作できます。"</string>
@@ -91,7 +91,7 @@
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"緊急通報待機モード"</string>
<string name="notification_channel_mobile_data_status" msgid="1941911162076442474">"モバイルデータのステータス"</string>
<string name="notification_channel_sms" msgid="1243384981025535724">"SMS メッセージ"</string>
- <string name="notification_channel_voice_mail" msgid="8457433203106654172">"ボイスメール メッセージ"</string>
+ <string name="notification_channel_voice_mail" msgid="8457433203106654172">"留守番電話メッセージ"</string>
<string name="notification_channel_wfc" msgid="9048240466765169038">"Wi-Fi 通話"</string>
<string name="notification_channel_sim" msgid="5098802350325677490">"SIM のステータス"</string>
<string name="notification_channel_sim_high_prio" msgid="642361929452850928">"高優先度: SIM のステータス"</string>
@@ -304,10 +304,8 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"カレンダーへのアクセス"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"SMSメッセージの送信と表示"</string>
- <!-- no translation found for permgrouplab_storage (9173334109512154196) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (8352226729501080525) -->
- <skip />
+ <string name="permgrouplab_storage" msgid="9173334109512154196">"ファイル、ドキュメント"</string>
+ <string name="permgroupdesc_storage" msgid="8352226729501080525">"デバイス内のファイルやドキュメントへのアクセス"</string>
<string name="permgrouplab_readMediaAural" msgid="5885210465560755316">"音楽やその他の音声"</string>
<string name="permgroupdesc_readMediaAural" msgid="1170143315714662822">"デバイス上の音声ファイルへのアクセス"</string>
<string name="permgrouplab_readMediaVisual" msgid="9137695801926624061">"写真と動画"</string>
@@ -588,8 +586,9 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"続行するには画面ロックを入力してください"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"指紋の一部しか検出できません"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"指紋を処理できませんでした。もう一度お試しください。"</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"センサーの汚れを取り除いてください"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"もう少し長く押してください"</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"指紋認証センサーの汚れを取り除いて、もう一度お試しください"</string>
+ <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"センサーの汚れを取り除いて、もう一度お試しください"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"センサーにしっかりと押し当ててください"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"指の動きが遅すぎました。もう一度お試しください。"</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"別の指紋をお試しください"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"明るすぎます"</string>
@@ -597,6 +596,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"毎回、指を置く位置を少し変えてください"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"指紋を認識できません"</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="4709197752023550709">"センサーにしっかりと押し当ててください"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"指紋認証を完了しました"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"顔を認証しました"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"顔を認証しました。[確認] を押してください"</string>
@@ -1037,8 +1038,8 @@
<string name="permdesc_writeHistoryBookmarks" product="default" msgid="2245203087160913652">"モバイル デバイスに保存されているブラウザの履歴やブックマークの変更をアプリに許可します。これにより、アプリがブラウザデータを消去または変更できるようになる可能性があります。注: この許可は、サードパーティブラウザまたはウェブブラウジング機能を備えたその他のアプリでは適用されない場合があります。"</string>
<string name="permlab_setAlarm" msgid="1158001610254173567">"アラームの設定"</string>
<string name="permdesc_setAlarm" msgid="2185033720060109640">"インストール済みアラームアプリのアラームを設定することをアプリに許可します。この機能が実装されていないアラームアプリもあります。"</string>
- <string name="permlab_addVoicemail" msgid="4770245808840814471">"ボイスメールの追加"</string>
- <string name="permdesc_addVoicemail" msgid="5470312139820074324">"ボイスメール受信トレイにメッセージを追加することをアプリに許可します。"</string>
+ <string name="permlab_addVoicemail" msgid="4770245808840814471">"留守番電話の追加"</string>
+ <string name="permdesc_addVoicemail" msgid="5470312139820074324">"留守番電話受信トレイにメッセージを追加することをアプリに許可します。"</string>
<string name="permlab_writeGeolocationPermissions" msgid="8605631647492879449">"ブラウザの現在地情報に対する権限の変更"</string>
<string name="permdesc_writeGeolocationPermissions" msgid="5817346421222227772">"ブラウザの現在地情報に対する権限の変更をアプリに許可します。この許可を悪意のあるアプリに利用されると、任意のウェブサイトに現在地情報が送信される恐れがあります。"</string>
<string name="save_password_message" msgid="2146409467245462965">"このパスワードをブラウザで保存しますか?"</string>
@@ -1500,7 +1501,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"スキップ"</string>
<string name="no_matches" msgid="6472699895759164599">"該当なし"</string>
<string name="find_on_page" msgid="5400537367077438198">"ページ内を検索"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# 件の一致}other{# 件(合計 {total} 件)}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"完了"</string>
<string name="progress_erasing" msgid="6891435992721028004">"共有ストレージを消去しています…"</string>
<string name="share" msgid="4157615043345227321">"共有"</string>
@@ -1928,6 +1930,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"ON にする"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"アプリの利用不可"</string>
<string name="app_blocked_message" msgid="542972921087873023">"現在 <xliff:g id="APP_NAME">%1$s</xliff:g> はご利用になれません。"</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g>は利用できません"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"現在、<xliff:g id="DEVICE">%1$s</xliff:g> からアクセスできません。Android TV デバイスでのアクセスをお試しください。"</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"現在、<xliff:g id="DEVICE">%1$s</xliff:g> からアクセスできません。タブレットでのアクセスをお試しください。"</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"現在、<xliff:g id="DEVICE">%1$s</xliff:g> からアクセスできません。スマートフォンでのアクセスをお試しください。"</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"このアプリは以前のバージョンの Android 用に作成されており、正常に動作しない可能性があります。アップデートを確認するか、デベロッパーにお問い合わせください。"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"アップデートを確認"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"新着メッセージがあります"</string>
@@ -2017,16 +2023,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"アンインストール"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"開く"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"有害なアプリが検出されました"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"システムログへのアクセスのリクエスト"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"今回のみ"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"許可しない"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> が機能デバッグのためにシステムログをリクエストしています。これらのログには、デバイス上のアプリやサービスが書き込んだ情報が含まれている可能性があります。"</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"次回から表示しない"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"「<xliff:g id="APP_0">%1$s</xliff:g>」が「<xliff:g id="APP_2">%2$s</xliff:g>」のスライスの表示をリクエストしています"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"編集"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"着信や通知をバイブレーションで知らせます"</string>
@@ -2089,22 +2090,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"電源ダイアログ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ロック画面"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"スクリーンショット"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"ヘッドセット: フック"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"画面上のユーザー補助機能のショートカット"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"画面上のユーザー補助機能のショートカットの選択メニュー"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"ユーザー補助機能のショートカット"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"通知シェードを閉じる"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"D-pad: 上"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"D-pad: 下"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"D-pad: 左"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"D-pad: 右"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"D-pad: 中央"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> のキャプション バーです。"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> は RESTRICTED バケットに移動しました。"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2120,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"タップすると有効になります"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"仕事用アプリはありません"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"個人用アプリはありません"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"個人用プロファイルで <xliff:g id="APP">%s</xliff:g> を開きますか?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"仕事用プロファイルで <xliff:g id="APP">%s</xliff:g> を開きますか?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"個人用ブラウザを使用"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"仕事用ブラウザを使用"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM のネットワーク ロック解除 PIN"</string>
@@ -2263,4 +2256,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> がバックグラウンドで実行され、バッテリーを消費しています。タップしてご確認ください。"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> がバックグラウンドで長時間実行されています。タップしてご確認ください。"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"有効なアプリをチェック"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 8af5df9..ae3f31c 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -304,10 +304,8 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"თქვენს კალენდარზე წვდომა"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS შეტყობინებების გაგზავნა და ნახვა"</string>
- <!-- no translation found for permgrouplab_storage (9173334109512154196) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (8352226729501080525) -->
- <skip />
+ <string name="permgrouplab_storage" msgid="9173334109512154196">"ფაილები და დოკუმენტები"</string>
+ <string name="permgroupdesc_storage" msgid="8352226729501080525">"თქვენს მოწყობილობაზე ფაილებსა და დოკუმენტებზე წვდომა"</string>
<string name="permgrouplab_readMediaAural" msgid="5885210465560755316">"მუსიკა და სხვა აუდიო ფაილები"</string>
<string name="permgroupdesc_readMediaAural" msgid="1170143315714662822">"თქვენს მოწყობილობაზე აუდიო ფაილებზე წვდომა"</string>
<string name="permgrouplab_readMediaVisual" msgid="9137695801926624061">"ფოტოები და ვიდეოები"</string>
@@ -588,8 +586,9 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"გასაგრძელებლად შედით ეკრანის დაბლოკვაში"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"ამოცნობილია ნაწილობრივი თითის ანაბეჭდი"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"თითის ანაბეჭდის დამუშავება ვერ მოხერხდა. გთხოვთ, ცადოთ ხელახლა."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"გაწმინდეთ სენსორი"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"ცოტა მეტ ხანს გეჭიროთ"</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"გაწმინდეთ თითის ანაბეჭდის სენსორი და ხელახლა ცადეთ"</string>
+ <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"გაწმინდეთ სენსორი და ხელახლა ცადეთ"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"მაგრად დააჭირეთ სენსორს"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"თითის აღება მეტისმეტად ნელა მოხდა. გთხოვთ, სცადოთ ხელახლა."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"ცადეთ სხვა თითის ანაბეჭდი"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"ზედმეტად ნათელია"</string>
@@ -597,6 +596,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"ოდნავ შეცვალეთ თითის დაჭერის ადგილი ყოველ ჯერზე"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"თითის ანაბეჭდის ამოცნობა ვერ მოხერხდა"</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="4709197752023550709">"მაგრად დააჭირეთ სენსორს"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"თითის ანაბეჭდი ავტორიზებულია"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"სახე ავტორიზებულია"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"სახე ავტორიზებულია, დააჭირეთ დადასტურებას"</string>
@@ -1500,7 +1501,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"გამოტოვება"</string>
<string name="no_matches" msgid="6472699895759164599">"შესატყვისები არ არის."</string>
<string name="find_on_page" msgid="5400537367077438198">"გვერდზე ძებნა"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# დამთხვევა}other{# {total}-დან}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"დასრულდა"</string>
<string name="progress_erasing" msgid="6891435992721028004">"მიმდინარეობს ზიარი მეხსიერების ამოშლა…"</string>
<string name="share" msgid="4157615043345227321">"გაზიარება"</string>
@@ -1928,6 +1930,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"ჩართვა"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"აპი მიუწვდომელია"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ამჟამად მიუწვდომელია."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> მიუწვდომელია"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"ამჟამად ამ აპზე თქვენი <xliff:g id="DEVICE">%1$s</xliff:g>-დან წვდომა შეუძლებელია. ცადეთ Android TV მოწყობილობიდან."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"ამჟამად ამ აპზე თქვენი <xliff:g id="DEVICE">%1$s</xliff:g>-დან წვდომა შეუძლებელია. ცადეთ ტაბლეტიდან."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"ამჟამად ამ აპზე თქვენი <xliff:g id="DEVICE">%1$s</xliff:g>-დან წვდომა შეუძლებელია. ცადეთ ტელეფონიდან."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ეს აპი Android-ის ძველი ვერსიისთვის შეიქმნა და შესაძლოა სათანადოდ არ მუშაობდეს. გადაამოწმეთ განახლებები ან დაუკავშირდით დეველოპერს."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"განახლების შემოწმება"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"თქვენ ახალი შეტყობინებები გაქვთ"</string>
@@ -2017,16 +2023,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"დეინსტალაცია"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"მაინც გახსნა"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"აღმოჩენილია საზიანო აპი"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"სისტემის ჟურნალში წვდომის მოთხოვნა"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"მხოლოდ ამ ერთხელ"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"არ დაიშვას"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ითხოვს სისტემის ჟურნალებს ფუნქციური გამართვისთვის. ეს ჟურნალები შეიძლება შეიცავდეს ინფორმაციას, რომელიც დაწერილია თქვენს მოწყობილობაზე არსებულ აპებსა და სერვისებზე."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"აღარ გამოჩნდეს"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g>-ს სურს, გაჩვენოთ <xliff:g id="APP_2">%2$s</xliff:g>-ის ფრაგმენტები"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"რედაქტირება"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"ზარების და შეტყობინებების მიღებისას ვიბრაცია ჩაირთვება"</string>
@@ -2089,22 +2090,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"ელკვების დიალოგი"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ჩაკეტილი ეკრანი"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ეკრანის ანაბეჭდი"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"ყურსაცვამის წამოგება"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"მისაწვდომობის ეკრანული მალსახმობი"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"მისაწვდომობის ეკრანული მალსახმობის ამომრჩევი"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"მისაწვდომობის მალსახმობი"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"შეტყობინებების ფარდის დახურვა"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Dpad ზევით"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Dpad ქვევით"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad მარცხნივ"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad მარჯვნივ"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad ცენტრი"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ის სუბტიტრების ზოლი."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> მოთავსდა კალათაში „შეზღუდული“"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2120,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"შეეხეთ ჩასართავად"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"სამსახურის აპები არ არის"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"პირადი აპები არ არის"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"გსურთ <xliff:g id="APP">%s</xliff:g>-ის გახსნა თქვენს პირად პროფილში?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"გსურთ <xliff:g id="APP">%s</xliff:g>-ის გახსნა თქვენს სამსახურის პროფილში?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"პირადი ბრაუზერის გამოყენება"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"სამსახურის ბრაუზერის გამოყენება"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM ქსელის განბლოკვის PIN-კოდი"</string>
@@ -2263,4 +2256,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> გაშვებულია ფონურ რეჟიმში და იყენებს ბატარეას. შეეხეთ გადასახედად."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> ფონურ რეჟიმში დიდი ხანია გაშვებულია. შეეხეთ გადასახედად."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"აქტიური აპების შემოწმება"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index ced90de..439060f 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Жалғастыру үшін экран құлпын енгізіңіз."</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Саусақ ізі жартылай анықталды."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Саусақ ізін өңдеу мүмкін емес. Әрекетті қайталаңыз."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Датчикті тазалаңыз."</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Сәл ұзағырақ ұстаңыз."</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Саусағыңызды тым баяу қозғалттыңыз. Әрекетті қайталап көріңіз."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Басқа саусақ ізін байқап көріңіз."</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Тым жарық."</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Саусағыңыздың қалпын аздап өзгертіп тұрыңыз."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Саусақ ізі аутентификацияланды"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Бет танылды"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Бет танылды, \"Растау\" түймесін басыңыз"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Өткізіп жіберу"</string>
<string name="no_matches" msgid="6472699895759164599">"Сәйкес табылмады"</string>
<string name="find_on_page" msgid="5400537367077438198">"Беттен табу"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# матч}other{#/{total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Дайын"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Ортақ жад тазартылуда…"</string>
<string name="share" msgid="4157615043345227321">"Бөлісу"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Қосу"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Қолданба қолжетімді емес"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> қазір қолжетімді емес."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> қолжетімсіз"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Қазір бұған <xliff:g id="DEVICE">%1$s</xliff:g> құрылғысынан кіру мүмкін емес. Оның орнына Android TV құрылғысын пайдаланып көріңіз."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Қазір бұған <xliff:g id="DEVICE">%1$s</xliff:g> құрылғысынан кіру мүмкін емес. Оның орнына планшетті пайдаланып көріңіз."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Қазір бұған <xliff:g id="DEVICE">%1$s</xliff:g> құрылғысынан кіру мүмкін емес. Оның орнына телефонды пайдаланып көріңіз."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Қолданба Android жүйесінің ескі нұсқасына арналған және дұрыс жұмыс істемеуі мүмкін. Жаңартылған нұсқаны тексеріңіз немесе әзірлеушіге хабарласыңыз."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Жаңарту бар-жоғын тексеру"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Сізде жаңа хабарлар бар"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ЖОЮ"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"БӘРІБІР АШУ"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Зиянды қолданба анықталды"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Жүйе журналын пайдалану рұқсатын сұрау"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Тек осы жолы"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Рұқсат бермеу"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> қолданбасы функционалдық түзету үшін жүйе журналдарын сұрайды. Бұл журналдарда құрылғыңыздағы қолданбалар мен қызметтер енгізген ақпарат қамтылуы мүмкін."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Қайта көрсетілмесін"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> қолданбасы <xliff:g id="APP_2">%2$s</xliff:g> қолданбасының үзінділерін көрсеткісі келеді"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Өзгерту"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Қоңыраулар мен хабарландырулардың вибрациясы болады"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Қуат диалогтік терезесі"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Құлып экраны"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Скриншот"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Гарнитура ілгіші"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Экрандағы арнайы мүмкіндіктерді жылдам қосу"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Экрандағы арнайы мүмкіндіктерді жылдам қосу әрекетін таңдау"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Арнайы мүмкіндіктерді жылдам қосу"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Хабарландыру тақтасын жабу"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Жоғарғы Dpad түймесі"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Төменгі Dpad түймесі"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Сол жақ Dpad түймесі"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Оң жақ Dpad түймесі"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Ортаңғы Dpad түймесі"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасының жазу жолағы."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ШЕКТЕЛГЕН себетке салынды."</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Қосу үшін түртіңіз"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Жұмыс қолданбалары жоқ."</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Жеке қолданбалар жоқ."</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"<xliff:g id="APP">%s</xliff:g> қолданбасын жеке профиліңізде ашу керек пе?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"<xliff:g id="APP">%s</xliff:g> қолданбасын жұмыс профиліңізде ашу керек пе?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Жеке браузерді пайдалану"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Жұмыс браузерін пайдалану"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM желісінің құлпын ашатын PIN коды"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> қолданбасы фондық режимде жұмыс істеуде және батарея жұмсауда. Көру үшін түртіңіз."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> қолданбасы ұзақ уақыт бойы фондық режимде жұмыс істеуде. Көру үшін түртіңіз."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Белсенді қолданбаларды тексеру"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 0497b4e..49f2255 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"បញ្ចូលការចាក់សោអេក្រង់របស់អ្នក ដើម្បីបន្ត"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"បានសម្គាល់ស្នាមម្រាមដៃដោយផ្នែក"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"មិនអាចដំណើរការស្នាមម្រាមដៃបានទេ។ សូមព្យាយាមម្តងទៀត។"</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"សម្អាតឧបករណ៍ចាប់ស្នាមម្រាមដៃ"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"ដាក់ឱ្យយូរជាងនេះបន្តិច"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"ចលនាម្រាមដៃយឺតពេកហើយ។ សូមព្យាយាមម្តងទៀត។"</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"សាកល្បងប្រើស្នាមម្រាមដៃផ្សេងទៀត"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"ភ្លឺពេក"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"ប្ដូរទីតាំងម្រាមដៃរបស់អ្នកតិចៗគ្រប់ពេល"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"បានផ្ទៀងផ្ទាត់ស្នាមម្រាមដៃ"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"បានផ្ទៀងផ្ទាត់មុខ"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"បានផ្ទៀងផ្ទាត់មុខ សូមចុចបញ្ជាក់"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"រំលង"</string>
<string name="no_matches" msgid="6472699895759164599">"គ្មានការផ្គូផ្គង"</string>
<string name="find_on_page" msgid="5400537367077438198">"រកក្នុងទំព័រ"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# ដូចគ្នា}other{# នៃ {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"រួចរាល់"</string>
<string name="progress_erasing" msgid="6891435992721028004">"កំពុងលុបទំហំផ្ទុករួម…"</string>
<string name="share" msgid="4157615043345227321">"ចែករំលែក"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"បើក"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"មិនអាចប្រើកម្មវិធីនេះបានទេ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"មិនអាចប្រើ <xliff:g id="APP_NAME">%1$s</xliff:g> នៅពេលនេះបានទេ។"</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"មិនអាចប្រើ <xliff:g id="ACTIVITY">%1$s</xliff:g> បានទេ"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"មិនអាចប្រើកម្មវិធីនេះនៅលើ <xliff:g id="DEVICE">%1$s</xliff:g> របស់អ្នកនៅពេលនេះបានទេ។ សូមសាកល្បងប្រើនៅលើឧបករណ៍ Android TV របស់អ្នកជំនួសវិញ។"</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"មិនអាចប្រើកម្មវិធីនេះនៅលើ <xliff:g id="DEVICE">%1$s</xliff:g> របស់អ្នកនៅពេលនេះបានទេ។ សូមសាកល្បងប្រើនៅលើថេប្លេតរបស់អ្នកជំនួសវិញ។"</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"មិនអាចប្រើកម្មវិធីនេះនៅលើ <xliff:g id="DEVICE">%1$s</xliff:g> របស់អ្នកនៅពេលនេះបានទេ។ សូមសាកល្បងប្រើនៅលើទូរសព្ទរបស់អ្នកជំនួសវិញ។"</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"កម្មវិធីនេះត្រូវបានបង្កើតឡើងសម្រាប់កំណែប្រព័ន្ធប្រតិបត្តិការ Android ចាស់ ហើយវាអាចដំណើរការខុសប្រក្រតី។ សូមសាកល្បងពិនិត្យមើលកំណែថ្មី ឬទាក់ទងទៅអ្នកអភិវឌ្ឍន៍។"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"រកមើលកំណែថ្មី"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"អ្នកមានសារថ្មី"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"លុប"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"មិនអីទេ បើកចុះ"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"បានរកឃើញកម្មវិធីដែលបង្កគ្រោះថ្នាក់"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"សំណើចូលប្រើកំណត់ហេតុប្រព័ន្ធ"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"តែពេលនេះប៉ុណ្ណោះ"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"មិនអនុញ្ញាត"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ស្នើសុំកំណត់ហេតុប្រព័ន្ធសម្រាប់ជួសជុលមុខងារ។ កំណត់ហេតុទាំងនេះប្រហែលជាមានព័ត៌មានដែលកម្មវិធី និងសេវាកម្មនៅលើឧបករណ៍របស់អ្នកបានសរសេរ។"</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"កុំបង្ហាញម្ដងទៀត"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ចង់បង្ហាញស្ថិតិប្រើប្រាស់របស់ <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"កែសម្រួល"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"ការហៅទូរសព្ទ និងការជូនដំណឹងនឹងញ័រ"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"ប្រអប់ថាមពល"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"អេក្រង់ចាក់សោ"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"រូបថតអេក្រង់"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"ទំពក់កាស"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"ផ្លូវកាត់ភាពងាយស្រួលនៅលើអេក្រង់"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"ម៉ឺនុយជ្រើសរើសផ្លូវកាត់ភាពងាយស្រួលនៅលើអេក្រង់"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"ផ្លូវកាត់ភាពងាយស្រួល"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"ច្រានចោលផ្ទាំងជូនដំណឹង"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Dpad ឡើងលើ"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Dpad ចុះក្រោម"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad ឆ្វេង"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad ស្ដាំ"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad កណ្ដាល"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"របារពណ៌នាអំពី <xliff:g id="APP_NAME">%1$s</xliff:g>។"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ត្រូវបានដាក់ទៅក្នុងធុងដែលបានដាក់កំហិត"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>៖"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"ចុចដើម្បីបើក"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"គ្មានកម្មវិធីការងារទេ"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"គ្មានកម្មវិធីផ្ទាល់ខ្លួនទេ"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"បើក <xliff:g id="APP">%s</xliff:g> នៅក្នុងកម្រងព័ត៌មានផ្ទាល់ខ្លួនរបស់អ្នកឬ?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"បើក <xliff:g id="APP">%s</xliff:g> នៅក្នុងកម្រងព័ត៌មានការងាររបស់អ្នកឬ?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"ប្រើកម្មវិធីរុករកតាមអ៊ីនធឺណិតផ្ទាល់ខ្លួន"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"ប្រើកម្មវិធីរុករកតាមអ៊ីនធឺណិតសម្រាប់ការងារ"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"កូដ PIN ដោះសោបណ្ដាញស៊ីម"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> កំពុងដំណើរការនៅផ្ទៃខាងក្រោយ និងធ្វើឱ្យអស់ថ្មលឿន។ សូមចុច ដើម្បីពិនិត្យមើល។"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> កំពុងដំណើរការនៅផ្ទៃខាងក្រោយអស់រយៈពេលយូរហើយ។ សូមចុច ដើម្បីពិនិត្យមើល។"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"ពិនិត្យមើលកម្មវិធីសកម្ម"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 659d885..b73b96f 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -304,10 +304,8 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"ನಿಮ್ಮ ಕ್ಯಾಲೆಂಡರ್ ಪ್ರವೇಶಿಸಲು"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS ಸಂದೇಶಗಳನ್ನು ಕಳುಹಿಸಲು ಮತ್ತು ನಿರ್ವಹಿಸಲು"</string>
- <!-- no translation found for permgrouplab_storage (9173334109512154196) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (8352226729501080525) -->
- <skip />
+ <string name="permgrouplab_storage" msgid="9173334109512154196">"ಫೈಲ್ಗಳು ಮತ್ತು ಡಾಕ್ಯುಮೆಂಟ್ಗಳು"</string>
+ <string name="permgroupdesc_storage" msgid="8352226729501080525">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಫೈಲ್ಗಳು ಮತ್ತು ಡಾಕ್ಯುಮೆಂಟ್ಗಳನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
<string name="permgrouplab_readMediaAural" msgid="5885210465560755316">"ಸಂಗೀತ ಮತ್ತು ಇತರ ಆಡಿಯೋ"</string>
<string name="permgroupdesc_readMediaAural" msgid="1170143315714662822">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಆಡಿಯೊ ಫೈಲ್ಗಳನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
<string name="permgrouplab_readMediaVisual" msgid="9137695801926624061">"ಫೋಟೋಗಳು ಮತ್ತು ವೀಡಿಯೊಗಳು"</string>
@@ -588,8 +586,9 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"ಮುಂದುವರಿಯಲು ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಅನ್ನು ನಮೂದಿಸಿ"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"ಭಾಗಶಃ ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಪತ್ತೆಯಾಗಿದೆ"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಅನ್ನು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ದಯವಿಟ್ಟು ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"ಸೆನ್ಸರ್ ಅನ್ನು ಸ್ವಚ್ಚಗೊಳಿಸಿ"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"ಸ್ವಲ್ಪ ಹೆಚ್ಚು ಸಮಯ ಒತ್ತಿ ಹಿಡಿಯಿರಿ"</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"ಫಿಂಗರ್ ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ಸ್ವಚ್ಛಗೊಳಿಸಿ ಹಾಗೂ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ"</string>
+ <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"ಸೆನ್ಸರ್ ಸ್ವಚ್ಛಗೊಳಿಸಿ ಹಾಗೂ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"ಸೆನ್ಸರ್ ಮೇಲೆ ದೃಢವಾಗಿ ಒತ್ತಿರಿ"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"ಬೆರಳನ್ನು ತುಂಬಾ ನಿಧಾನವಾಗಿ ಸರಿಸಲಾಗಿದೆ. ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"ಮತ್ತೊಂದು ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಪ್ರಯತ್ನಿಸಿ"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"ತುಂಬಾ ಪ್ರಕಾಶಮಾನವಾಗಿದೆ"</string>
@@ -597,6 +596,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"ಪ್ರತಿ ಬಾರಿಯೂ ನಿಮ್ಮ ಬೆರಳಿನ ಸ್ಥಾನವನ್ನು ಸ್ವಲ್ಪ ಮಟ್ಟಿಗೆ ಬದಲಾಯಿಸಿ"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"ಫಿಂಗರ್ ಪ್ರಿಂಟ್ ಅನ್ನು ಗುರುತಿಸಲಾಗಿಲ್ಲ"</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="4709197752023550709">"ಸೆನ್ಸರ್ ಮೇಲೆ ದೃಢವಾಗಿ ಒತ್ತಿರಿ"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಅನ್ನು ಪ್ರಮಾಣೀಕರಣ ಮಾಡಲಾಗಿದೆ"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"ಮುಖವನ್ನು ದೃಢೀಕರಿಸಲಾಗಿದೆ"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"ಮುಖವನ್ನು ದೃಢೀಕರಿಸಲಾಗಿದೆ, ದೃಢೀಕರಣವನ್ನು ಒತ್ತಿ"</string>
@@ -1500,7 +1501,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"ಸ್ಕಿಪ್"</string>
<string name="no_matches" msgid="6472699895759164599">"ಯಾವುದೇ ಹೊಂದಿಕೆಗಳಿಲ್ಲ"</string>
<string name="find_on_page" msgid="5400537367077438198">"ಪುಟದಲ್ಲಿ ಹುಡುಕಿ"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# ಹೊಂದಾಣಿಕೆ{total} ರಲ್ಲಿ }one{#{total} ರಲ್ಲಿ }other{#}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"ಮುಗಿದಿದೆ"</string>
<string name="progress_erasing" msgid="6891435992721028004">"ಹಂಚಲಾದ ಸಂಗ್ರಹಣೆಯನ್ನು ಅಳಿಸಲಾಗುತ್ತಿದೆ…"</string>
<string name="share" msgid="4157615043345227321">"ಹಂಚಿಕೊಳ್ಳಿ"</string>
@@ -1928,6 +1930,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"ಆನ್ ಮಾಡಿ"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ಆ್ಯಪ್ ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಇದೀಗ ಲಭ್ಯವಿಲ್ಲ."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ಲಭ್ಯವಿಲ್ಲ"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"ಈ ಸಮಯದಲ್ಲಿ ನಿಮ್ಮ <xliff:g id="DEVICE">%1$s</xliff:g> ನಲ್ಲಿ ಇದನ್ನು ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಅದರ ಬದಲು ನಿಮ್ಮ Android TV ಸಾಧನದಲ್ಲಿ ಪ್ರಯತ್ನಿಸಿ."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"ಈ ಸಮಯದಲ್ಲಿ ನಿಮ್ಮ <xliff:g id="DEVICE">%1$s</xliff:g> ನಲ್ಲಿ ಇದನ್ನು ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಅದರ ಬದಲು ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ನಲ್ಲಿ ಪ್ರಯತ್ನಿಸಿ."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"ಈ ಸಮಯದಲ್ಲಿ ನಿಮ್ಮ <xliff:g id="DEVICE">%1$s</xliff:g> ನಲ್ಲಿ ಇದನ್ನು ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಅದರ ಬದಲು ನಿಮ್ಮ ಫೋನ್ನಲ್ಲಿ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ಈ ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು Android ನ ಹಳೆಯ ಆವೃತ್ತಿಗೆ ರಚಿಸಲಾಗಿದೆ ಮತ್ತು ಸರಿಯಾಗಿ ಕೆಲಸ ಮಾಡದಿರಬಹುದು. ಅಪ್ಡೇಟ್ಗಳನ್ನು ಪರಿಶೀಲಿಸಲು ಪ್ರಯತ್ನಿಸಿ ಅಥವಾ ಡೆವಲಪರ್ ಅನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"ಅಪ್ಡೇಟ್ಗಾಗಿ ಪರಿಶೀಲಿಸಿ"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"ನೀವು ಹೊಸ ಸಂದೇಶಗಳನ್ನು ಹೊಂದಿರುವಿರಿ"</string>
@@ -2017,16 +2023,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ಅನ್ಇನ್ಸ್ಟಾಲ್ ಮಾಡಿ"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"ಹೇಗಿದ್ದರೂ ತೆರೆಯಿರಿ"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"ಅಪಾಯಕಾರಿ ಅಪ್ಲಿಕೇಶನ್ ಕಂಡುಬಂದಿದೆ"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"ಸಿಸ್ಟಂ ಲಾಗ್ ಪ್ರವೇಶ ವಿನಂತಿ"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"ಈ ಬಾರಿ ಮಾತ್ರ"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"ಅನುಮತಿಸಬೇಡಿ"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"ಫಂಕ್ಷನಲ್ ಡೀಬಗ್ ಮಾಡುವಿಕೆಗಾಗಿ <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ಸಿಸ್ಟಂ ಲಾಗ್ಗಳನ್ನು ವಿನಂತಿಸುತ್ತದೆ. ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿನ ಆ್ಯಪ್ಗಳು ಮತ್ತು ಸೇವೆಗಳು ಬರೆದಿರುವ ಮಾಹಿತಿಯನ್ನು ಈ ಲಾಗ್ಗಳು ಒಳಗೊಂಡಿರಬಹುದು."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"ಮತ್ತೊಮ್ಮೆ ತೋರಿಸಬೇಡಿ"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_2">%2$s</xliff:g> ಸ್ಲೈಸ್ಗಳನ್ನು <xliff:g id="APP_0">%1$s</xliff:g> ತೋರಿಸಲು ಬಯಸಿದೆ"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"ಎಡಿಟ್"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"ಕರೆಗಳು ಮತ್ತು ಅಧಿಸೂಚನೆಗಳು ವೈಬ್ರೇಟ್ ಆಗುತ್ತವೆ"</string>
@@ -2119,10 +2120,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"ಆನ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"ಯಾವುದೇ ಕೆಲಸಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಆ್ಯಪ್ಗಳಿಲ್ಲ"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"ಯಾವುದೇ ವೈಯಕ್ತಿಕ ಆ್ಯಪ್ಗಳಿಲ್ಲ"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ಪ್ರೊಫೈಲ್ನಲ್ಲಿ <xliff:g id="APP">%s</xliff:g> ಅನ್ನು ತೆರೆಯಬೇಕೆ?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"ನಿಮ್ಮ ಉದ್ಯೋಗದ ಪ್ರೊಫೈಲ್ನಲ್ಲಿ <xliff:g id="APP">%s</xliff:g> ಅನ್ನು ತೆರೆಯಬೇಕೆ?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"ವೈಯಕ್ತಿಕ ಬ್ರೌಸರ್ ಬಳಸಿ"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"ಉದ್ಯೋಗ ಬ್ರೌಸರ್ ಬಳಸಿ"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM ನೆಟ್ವರ್ಕ್ ಅನ್ಲಾಕ್ ಮಾಡುವ ಪಿನ್"</string>
@@ -2257,4 +2256,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> ಹಿನ್ನೆಲೆಯಲ್ಲಿ ರನ್ ಆಗುತ್ತಿದೆ ಹಾಗೂ ಬ್ಯಾಟರಿಯನ್ನು ಹೆಚ್ಚು ಬಳಸುತ್ತಿದೆ. ಪರಿಶೀಲಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> ಬಹಳ ಸಮಯದಿಂದ ಹಿನ್ನೆಲೆಯಲ್ಲಿ ರನ್ ಆಗುತ್ತಿದೆ. ಪರಿಶೀಲಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"ಸಕ್ರಿಯ ಆ್ಯಪ್ಗಳನ್ನು ಪರಿಶೀಲಿಸಿ"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index ff4d5d6..a7f8cb4 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"계속하려면 화면 잠금용 사용자 인증 정보를 입력하세요"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"지문의 일부만 감지됨"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"지문을 인식할 수 없습니다. 다시 시도해 주세요."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"센서 닦기"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"조금 더 길게 터치하세요."</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"손가락을 너무 느리게 움직였습니다. 다시 시도해 주세요."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"다른 지문으로 시도"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"너무 밝음"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"지문을 등록할 때마다 손가락을 조금씩 이동하세요."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"지문이 인증됨"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"얼굴이 인증되었습니다"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"얼굴이 인증되었습니다. 확인을 누르세요"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"건너뛰기"</string>
<string name="no_matches" msgid="6472699895759164599">"검색결과 없음"</string>
<string name="find_on_page" msgid="5400537367077438198">"페이지에서 찾기"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{일치하는 항목 #개}other{#/{total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"완료"</string>
<string name="progress_erasing" msgid="6891435992721028004">"공유 저장공간 지우는 중…"</string>
<string name="share" msgid="4157615043345227321">"공유"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"사용 설정"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"앱을 사용할 수 없습니다"</string>
<string name="app_blocked_message" msgid="542972921087873023">"현재 <xliff:g id="APP_NAME">%1$s</xliff:g> 앱을 사용할 수 없습니다."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> 사용할 수 없음"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"현재 <xliff:g id="DEVICE">%1$s</xliff:g>에서 액세스할 수 없습니다. 대신 Android TV 기기에서 시도해 보세요."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"현재 <xliff:g id="DEVICE">%1$s</xliff:g>에서 액세스할 수 없습니다. 대신 태블릿에서 시도해 보세요."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"현재 <xliff:g id="DEVICE">%1$s</xliff:g>에서 액세스할 수 없습니다. 대신 스마트폰에서 시도해 보세요."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"이 앱은 Android 이전 버전에 맞게 개발되었기 때문에 제대로 작동하지 않을 수 있습니다. 업데이트를 확인하거나 개발자에게 문의하세요."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"업데이트 확인"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"새 메시지 있음"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"제거"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"열기"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"유해한 앱 감지됨"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"시스템 로그 액세스 요청"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"이번만 허용"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"허용 안함"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> 앱에서 기능 디버깅을 위해 시스템 로그를 요청합니다. 이 로그에는 기기의 앱과 서비스가 작성한 정보가 포함될 수 있습니다."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"다시 표시 안함"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g>에서 <xliff:g id="APP_2">%2$s</xliff:g>의 슬라이스를 표시하려고 합니다"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"수정"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"전화 및 알림이 오면 진동이 사용됩니다."</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"전원 대화상자"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"잠금 화면"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"스크린샷"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"헤드셋 후크"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"화면상의 접근성 바로가기"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"화면상의 접근성 바로가기 선택 도구"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"접근성 단축키"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"알림 창 닫기"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"방향 패드 위쪽"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"방향 패드 아래"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"방향 패드 왼쪽"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"방향 패드 오른쪽"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"방향 패드 가운데"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>의 자막 표시줄입니다."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 항목이 RESTRICTED 버킷으로 이동함"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"탭하여 사용 설정"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"직장 앱 없음"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"개인 앱 없음"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"개인 프로필에서 <xliff:g id="APP">%s</xliff:g> 앱을 여시겠습니까?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"직장 프로필에서 <xliff:g id="APP">%s</xliff:g> 앱을 여시겠습니까?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"개인 브라우저 사용"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"직장 브라우저 사용"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM 네트워크 잠금 해제 PIN"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> 앱이 백그라운드에서 실행 중이며 배터리를 소모하고 있습니다. 확인하려면 탭하세요."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> 앱이 백그라운드에서 오랫동안 실행 중입니다. 확인하려면 탭하세요."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"활성 상태의 앱 확인"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 7e25ce4..577626d 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Улантуу үчүн экрандын кулпусун киргизиңиз"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Манжа изи жарым-жартылай аныкталды"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Манжа изи иштелбей койду. Кайталап көрүңүз."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Сенсорду тазалаңыз"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Дагы бир аз кармап туруңуз"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Манжа өтө жай жылды. Кайталап көрүңүз."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Башка манжа изин байкап көрүңүз"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Өтө жарык"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Манжаңыздын абалын ар жолкусунда бир аз өзгөртүп туруңуз"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Манжа изи текшерилди"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Жүздүн аныктыгы текшерилди"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Жүздүн аныктыгы текшерилди, эми \"Ырастоону\" басыңыз"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Өткөрүп жиберүү"</string>
<string name="no_matches" msgid="6472699895759164599">"Дал келүүлөр жок"</string>
<string name="find_on_page" msgid="5400537367077438198">"Барактан табуу"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# дал келүү{total} ичинен }other{# }} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Даяр"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Жалпы сактагыч тазаланууда…"</string>
<string name="share" msgid="4157615043345227321">"Бөлүшүү"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Күйгүзүү"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Колдонмо учурда жеткиликсиз"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> учурда жеткиликсиз"</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> жеткиликсиз"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Учурда буга <xliff:g id="DEVICE">%1$s</xliff:g> түзмөгүңүздөн кире албайсыз. Android TV түзмөгүңүздөн аракет кылып көрүңүз."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Учурда буга <xliff:g id="DEVICE">%1$s</xliff:g> түзмөгүңүздөн кире албайсыз. Планшетиңизден кирип көрүңүз."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Учурда буга <xliff:g id="DEVICE">%1$s</xliff:g> түзмөгүңүздөн кире албайсыз. Анын ордуна телефондон кирип көрүңүз."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Бул колдонмо Android\'дин эски версиясы үчүн иштеп чыгарылган, андыктан туура эмес иштеши мүмкүн. Жаңыртууларды издеп көрүңүз же иштеп чыгуучуга кайрылыңыз."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Жаңыртууларды текшерүү"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Сизге жаңы билдирүүлөр келди"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ЧЫГАРЫП САЛУУ"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"БААРЫ БИР АЧЫЛСЫН"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Зыянкеч колдонмо аныкталды"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Тутум таржымалына кирүүгө уруксат суралды"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Ушул жолу гана"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Уруксат берилбесин"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> функционалдык мүчүлүштүктөрдү оңдоо үчүн тутум таржымалдарын сурап жатат. Бул таржымалдарда түзмөгүңүздөгү колдонмолор жана кызматтар жазган маалымат камтылышы мүмкүн."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Экинчи көрүнбөсүн"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> колдонмосу <xliff:g id="APP_2">%2$s</xliff:g> үлгүлөрүн көрсөткөнү жатат"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Түзөтүү"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Чалуулар менен билдирмелер дирилдөө режиминде иштейт"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Кубат диалогу"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Кулпуланган экран"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Скриншот"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Гарнитуранын илмеги"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Ыкчам иштетүү"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Ыкчам иштетүү менюсу"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Ыкчам иштетүү"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Билдирмелер тактасын жабуу"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Dpad\'дын жогорку баскычы"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Dpad\'дын ылдыйкы баскычы"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad\'дын сол баскычы"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad\'дын оң баскычы"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad\'дын ортоңку баскычы"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунун маалымат тилкеси."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ЧЕКТЕЛГЕН чакага коюлган"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Күйгүзүү үчүн таптап коюңуз"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Жумуш колдонмолору жок"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Жеке колдонмолор жок"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"<xliff:g id="APP">%s</xliff:g> колдонмосу жеке профилде ачылсынбы?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"<xliff:g id="APP">%s</xliff:g> колдонмосу жумуш профилинде ачылсынбы?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Жеке серепчини колдонуу"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Жумуш серепчисин колдонуу"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM карта тармагынын кулпусун ачуучу PIN код"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> фондо иштеп, батареяны отургузуп жатат. Көрүү үчүн таптап коюңуз."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> колдонмосу көп убакыттан бери фондо иштеп жатат. Көрүү үчүн таптап коюңуз."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Жигердүү колдонмолорду карап чыгуу"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index e8ac194..090bde9 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -304,10 +304,8 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"ເຂົ້າຫາປະຕິທິນຂອງທ່ານ"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"ສົ່ງ ແລະເບິ່ງຂໍ້ຄວາມ SMS"</string>
- <!-- no translation found for permgrouplab_storage (9173334109512154196) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (8352226729501080525) -->
- <skip />
+ <string name="permgrouplab_storage" msgid="9173334109512154196">"ໄຟລ໌ ແລະ ເອກະສານ"</string>
+ <string name="permgroupdesc_storage" msgid="8352226729501080525">"ເຂົ້າເຖິງໄຟລ໌ ແລະ ເອກະສານຢູ່ອຸປະກອນຂອງທ່ານ"</string>
<string name="permgrouplab_readMediaAural" msgid="5885210465560755316">"ເພງ ແລະ ສຽງອື່ນໆ"</string>
<string name="permgroupdesc_readMediaAural" msgid="1170143315714662822">"ເຂົ້າເຖິງໄຟລ໌ສຽງຢູ່ອຸປະກອນຂອງທ່ານ"</string>
<string name="permgrouplab_readMediaVisual" msgid="9137695801926624061">"ຮູບພາບ ແລະ ວິດີໂອ"</string>
@@ -588,8 +586,9 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"ໃສ່ການລັອກໜ້າຈໍຂອງທ່ານເພື່ອສືບຕໍ່"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"ກວດພົບລາຍນິ້ວມືບາງສ່ວນ"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ບໍ່ສາມາດດຳເນີນການລາຍນີ້ວມືໄດ້. ກະລຸນາລອງໃໝ່ອີກ."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"ກະລຸນາອະນາໄມເຊັນເຊີ"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"ກົດໄວ້ດົນຂຶ້ນອີກໜ້ອຍໜຶ່ງ"</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"ໃຫ້ອະນາໄມເຊັນເຊີລາຍນິ້ວມືແລ້ວລອງໃໝ່"</string>
+ <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"ໃຫ້ອະນາໄມເຊັນເຊີແລ້ວລອງໃໝ່"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"ກົດຢູ່ເຊັນເຊີໃຫ້ແໜ້ນ"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"ຍ້າຍນີ້ວມືໄປຊ້າເກີນໄປ. ກະລຸນາລອງໃໝ່ອີກ."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"ລອງໃຊ້ລາຍນິ້ວມືອື່ນ"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"ແຈ້ງເກີນໄປ"</string>
@@ -597,6 +596,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"ປ່ຽນຕຳແໜ່ງຂອງນິ້ວມືຂອງທ່ານເລັກນ້ອຍໃນແຕ່ລະເທື່ອ"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"ບໍ່ຮູ້ຈັກລາຍນິ້ວມື"</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="4709197752023550709">"ກົດຢູ່ເຊັນເຊີໃຫ້ແໜ້ນ"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ພິສູດຢືນຢັນລາຍນິ້ວມືແລ້ວ"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"ພິສູດຢືນຢັນໃບໜ້າແລ້ວ"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"ພິສູດຢືນຢັນໃບໜ້າແລ້ວ, ກະລຸນາກົດຢືນຢັນ"</string>
@@ -1500,7 +1501,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"ຂ້າມ"</string>
<string name="no_matches" msgid="6472699895759164599">"ບໍ່ພົບຜົນການຊອກຫາ"</string>
<string name="find_on_page" msgid="5400537367077438198">"ຊອກໃນໜ້າ"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# ຂໍ້ມູນທີ່ກົງກັນ}other{# ຈາກທັງໝົດ {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"ແລ້ວໆ"</string>
<string name="progress_erasing" msgid="6891435992721028004">"ກຳລັງລຶບບ່ອນຈັດເກັບຂໍ້ມູນທີ່ແບ່ງປັນ…"</string>
<string name="share" msgid="4157615043345227321">"ແບ່ງປັນ"</string>
@@ -1928,6 +1930,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"ເປີດ"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ແອັບບໍ່ສາມາດໃຊ້ໄດ້"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ່ສາມາດໃຊ້ໄດ້ໃນຕອນນີ້."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"ບໍ່ສາມາດໃຊ້ <xliff:g id="ACTIVITY">%1$s</xliff:g> ໄດ້"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"ບໍ່ສາມາດເຂົ້າເຖິງແອັບນີ້ໄດ້ຢູ່ <xliff:g id="DEVICE">%1$s</xliff:g> ຂອງທ່ານໃນຕອນນີ້. ກະລຸນາລອງໃຊ້ຢູ່ອຸປະກອນ Android TV ຂອງທ່ານແທນ."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"ບໍ່ສາມາດເຂົ້າເຖິງແອັບນີ້ໄດ້ຢູ່ <xliff:g id="DEVICE">%1$s</xliff:g> ຂອງທ່ານໃນຕອນນີ້. ກະລຸນາລອງຢູ່ແທັບເລັດຂອງທ່ານແທນ."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"ບໍ່ສາມາດເຂົ້າເຖິງແອັບນີ້ໄດ້ຢູ່ <xliff:g id="DEVICE">%1$s</xliff:g> ຂອງທ່ານໃນຕອນນີ້. ກະລຸນາລອງຢູ່ໂທລະສັບຂອງທ່ານແທນ."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ແອັບນີ້ຖືກສ້າງຂຶ້ນສຳລັບ Android ເວີຊັນທີ່ເກົ່າກວ່າ ແລະ ອາດເຮັດວຽກໄດ້ບໍ່ປົກກະຕິ. ໃຫ້ລອງກວດສອບເບິ່ງອັບເດດ ຫຼື ຕິດຕໍ່ຜູ້ພັດທະນາ."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"ກວດເບິ່ງອັບເດດ"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"ທ່ານມີຂໍ້ຄວາມໃໝ່"</string>
@@ -2017,16 +2023,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ຖອນການຕິດຕັ້ງ"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"ຢືນຢັນການເປີດ"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"ກວດສອບແອັບທີ່ເປັນອັນຕະລາຍ"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"ຄຳຮ້ອງຂໍການເຂົ້າເຖິງບັນທຶກລະບົບ"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"ສະເພາະເທື່ອນີ້"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"ບໍ່ອະນຸຍາດ"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ຮ້ອງຂໍບັນທຶກລະບົບສຳລັບການດີບັກການເຮັດວຽກ. ບັນທຶກເຫຼົ່ານີ້ອາດມີເນື້ອຫາທີ່ແອັບ ແລະ ບໍລິການຢູ່ອຸປະກອນຂອງທ່ານໄດ້ຂຽນໄວ້."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"ບໍ່ຕ້ອງສະແດງອີກ"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ຕ້ອງການສະແດງ <xliff:g id="APP_2">%2$s</xliff:g> ສະໄລ້"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"ແກ້ໄຂ"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"ການໂທ ແລະ ການແຈ້ງເຕືອນຈະສັ່ນ"</string>
@@ -2089,22 +2090,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"ກ່ອງໂຕ້ຕອບການເປີດປິດ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ໜ້າຈໍລັອກ"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ຮູບໜ້າຈໍ"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"ຄຳສັ່ງ Hook ຂອງຊຸດຫູຟັງ"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"ທາງລັດການຊ່ວຍເຂົ້າເຖິງຢູ່ໜ້າຈໍ"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"ຕົວເລືອກທາງລັດການຊ່ວຍເຂົ້າເຖິງຢູ່ໜ້າຈໍ"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"ທາງລັດການຊ່ວຍເຂົ້າເຖິງ"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"ປິດເງົາການແຈ້ງເຕືອນໄວ້"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Dpad ຂຶ້ນ"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Dpad ລົງ"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad ຊ້າຍ"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad ຂວາ"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad ກາງ"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"ແຖບຄຳບັນຍາຍຂອງ <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ຖືກວາງໄວ້ໃນກະຕ່າ \"ຈຳກັດ\" ແລ້ວ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2120,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"ແຕະເພື່ອເປີດໃຊ້"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"ບໍ່ມີແອັບບ່ອນເຮັດວຽກ"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"ບໍ່ມີແອັບສ່ວນຕົວ"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"ເປີດ <xliff:g id="APP">%s</xliff:g> ໃນໂປຣໄຟລ໌ສ່ວນຕົວຂອງທ່ານບໍ?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"ເປີດ <xliff:g id="APP">%s</xliff:g> ໃນໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຂອງທ່ານບໍ?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"ໃຊ້ໂປຣແກຣມທ່ອງເວັບສ່ວນຕົວ"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"ໃຊ້ໂປຣແກຣມທ່ອງເວັບບ່ອນເຮັດວຽກ"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"PIN ປົດລັອກເຄືອຂ່າຍຊິມ"</string>
@@ -2263,4 +2256,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> ກຳລັງເຮັດວຽກໃນພື້ນຫຼັງ ແລະ ໃຊ້ແບັດເຕີຣີຫຼາຍ. ແຕະເພື່ອກວດສອບ."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> ກຳລັງເຮັດວຽກໃນພື້ນຫຼັງເປັນເວລາດົນແລ້ວ. ແຕະເພື່ອກວດສອບ."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"ກວດສອບແອັບທີ່ເຄື່ອນໄຫວ"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 77e61a5..f89c429 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -306,10 +306,8 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"pasiekti kalendorių"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"siųsti ir peržiūrėti SMS pranešimus"</string>
- <!-- no translation found for permgrouplab_storage (9173334109512154196) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (8352226729501080525) -->
- <skip />
+ <string name="permgrouplab_storage" msgid="9173334109512154196">"Failai ir dokumentai"</string>
+ <string name="permgroupdesc_storage" msgid="8352226729501080525">"pasiekti failus ir dokumentus jūsų įrenginyje"</string>
<string name="permgrouplab_readMediaAural" msgid="5885210465560755316">"Muzika ir kiti garso įrašai"</string>
<string name="permgroupdesc_readMediaAural" msgid="1170143315714662822">"pasiekti garso failus įrenginyje"</string>
<string name="permgrouplab_readMediaVisual" msgid="9137695801926624061">"Nuotraukos ir vaizdo įrašai"</string>
@@ -590,8 +588,9 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Jei norite tęsti, įveskite ekrano užraktą"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Aptiktas dalinis kontrolinis kodas"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Nepavyko apdoroti piršto antspaudo. Bandykite dar kartą."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Nuvalykite jutiklį"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Palaukite šiek tiek ilgiau"</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Nuvalykite kontrolinio kodo jutiklį ir bandykite dar kartą"</string>
+ <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Nuvalykite jutiklį ir bandykite dar kartą"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Tvirtai paspauskite jutiklį"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Per lėtai judinate pirštą. Bandykite dar kartą."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Pabandykite kitą kontrolinį kodą"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Per šviesu"</string>
@@ -599,6 +598,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Kaskart šiek tiek pakeiskite piršto poziciją"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"Kontrolinis kodas neatpažintas"</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="4709197752023550709">"Tvirtai paspauskite jutiklį"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Piršto antspaudas autentifikuotas"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Veidas autentifikuotas"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Veidas autentifikuotas, paspauskite patvirtinimo mygtuką"</string>
@@ -1502,7 +1503,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Praleisti"</string>
<string name="no_matches" msgid="6472699895759164599">"Nėra atitikčių"</string>
<string name="find_on_page" msgid="5400537367077438198">"Ieškoti puslapyje"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# atitiktis}one{# iš {total}}few{# iš {total}}many{# iš {total}}other{# iš {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Atlikta"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Ištrinama bendrinama saugykla…"</string>
<string name="share" msgid="4157615043345227321">"Bendrinti"</string>
@@ -1930,6 +1932,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Įjungti"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Programa nepasiekiama."</string>
<string name="app_blocked_message" msgid="542972921087873023">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ šiuo metu nepasiekiama."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"„<xliff:g id="ACTIVITY">%1$s</xliff:g>“ nepasiekiama"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Šįkart nepavyksta pasiekti programos iš jūsų „<xliff:g id="DEVICE">%1$s</xliff:g>“. Pabandykite naudoti „Android TV“ įrenginį."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Šįkart nepavyksta pasiekti programos iš jūsų „<xliff:g id="DEVICE">%1$s</xliff:g>“. Pabandykite naudoti planšetinį kompiuterį."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Šįkart nepavyksta pasiekti programos iš jūsų „<xliff:g id="DEVICE">%1$s</xliff:g>“. Pabandykite naudoti telefoną."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ši programa sukurta naudoti senesnės versijos sistemoje „Android“ ir gali tinkamai neveikti. Pabandykite patikrinti, ar yra naujinių, arba susisiekite su kūrėju."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Tikrinti, ar yra naujinių"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Turite naujų pranešimų"</string>
@@ -2019,16 +2025,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"PAŠALINTI"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"VIS TIEK ATIDARYTI"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Aptikta žalinga programa"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Prieigos prie sistemos žurnalų užklausa"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Tik šį kartą"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Neleisti"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"„<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>“ prašo leisti pasiekti sistemos žurnalus funkcinio derinimo tikslais. Šiuose žurnaluose gali būti informacijos, kurią įrašė įrenginyje esančios programos ir paslaugos."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Daugiau neberodyti"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"„<xliff:g id="APP_0">%1$s</xliff:g>“ nori rodyti „<xliff:g id="APP_2">%2$s</xliff:g>“ fragmentus"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Redaguoti"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Skambučiai ir pranešimai vibruos"</string>
@@ -2091,22 +2092,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Maitinimo dialogo langas"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Užrakinimo ekranas"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekrano kopija"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Pakabinti virtualiosios realybės įrenginį"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Ekrano pritaikomumo šaukinys"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Ekrano pritaikomumo šaukinių parinkiklis"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Pritaikomumo šaukinys"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Atsisakyti pranešimų skydelio"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Valdymo pultas – aukštyn"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Valdymo pultas – žemyn"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Valdymo pultas – kairėn"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Valdymo pultas – dešinėn"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Valdymo pultas – centras"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Programos „<xliff:g id="APP_NAME">%1$s</xliff:g>“ antraštės juosta."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"„<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>“ įkeltas į grupę APRIBOTA"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2127,10 +2122,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Paliesti, norint įjungti"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Nėra darbo programų"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Nėra asmeninių programų"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Atidaryti „<xliff:g id="APP">%s</xliff:g>“ asmeniniame profilyje?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Atidaryti „<xliff:g id="APP">%s</xliff:g>“ darbo profilyje?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Naudoti asmeninę naršyklę"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Naudoti darbo naršyklę"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM tinklo operatoriaus pasirinkimo ribojimo panaikinimo PIN kodas"</string>
@@ -2265,4 +2258,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"„<xliff:g id="APP">%1$s</xliff:g>“ veikia fone ir eikvoja akumuliatoriaus energiją. Palieskite ir peržiūrėkite."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"„<xliff:g id="APP">%1$s</xliff:g>“ ilgą laiką veikia fone. Palieskite ir peržiūrėkite."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Peržiūrėkite aktyvias programas"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 166ec36..030144b 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -589,8 +589,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Lai turpinātu, ievadiet ekrāna bloķēšanas informāciju"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Tika konstatēts nepilnīgs pilna nospiedums"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Nevarēja apstrādāt pirksta nospiedumu. Lūdzu, mēģiniet vēlreiz."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Notīriet sensoru"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Turiet pirkstu uz sensora nedaudz ilgāk."</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Pārāk lēna pirksta kustība. Lūdzu, mēģiniet vēlreiz."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Izmēģiniet citu pirksta nospiedumu"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Pārāk spilgts"</string>
@@ -598,6 +602,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Katru reizi mazliet mainiet pirksta pozīciju."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Pirksta nospiedums tika autentificēts."</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Seja autentificēta"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Seja ir autentificēta. Nospiediet pogu Apstiprināt."</string>
@@ -1501,7 +1509,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Izlaist"</string>
<string name="no_matches" msgid="6472699895759164599">"Nav atbilstību"</string>
<string name="find_on_page" msgid="5400537367077438198">"Atrast lapā"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# atbilstība}zero{#. no {total}}one{#. no {total}}other{#. no {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Gatavs"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Notiek koplietotās krātuves dzēšana…"</string>
<string name="share" msgid="4157615043345227321">"Kopīgot"</string>
@@ -1929,6 +1938,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Ieslēgt"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Lietotne nav pieejama"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> pašlaik nav pieejama."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nav pieejams"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Šajā ierīcē (<xliff:g id="DEVICE">%1$s</xliff:g>) pašlaik nevar piekļūt šai lietotnei. Mēģiniet tai piekļūt savā Android TV ierīcē."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Šajā ierīcē (<xliff:g id="DEVICE">%1$s</xliff:g>) pašlaik nevar piekļūt šai lietotnei. Mēģiniet tai piekļūt savā planšetdatorā."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Šajā ierīcē (<xliff:g id="DEVICE">%1$s</xliff:g>) pašlaik nevar piekļūt šai lietotnei. Mēģiniet tai piekļūt savā tālrunī."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Šī lietotne tika izstrādāta vecākai Android versijai un var nedarboties pareizi. Meklējiet atjauninājumus vai sazinieties ar izstrādātāju."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Meklēt atjauninājumu"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Jums ir jaunas īsziņas."</string>
@@ -2018,16 +2031,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ATINSTALĒT"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"TIK UN TĀ ATVĒRT"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Konstatēta kaitīga lietotne"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Pieprasījums piekļūt sistēmas žurnāliem"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Tikai šoreiz"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Neatļaut"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"Lietotne <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> pieprasa sistēmas žurnālus funkciju atkļūdošanai. Šie žurnāli var ietvert informāciju, ko ir rakstījušas jūsu ierīces lietotnes un pakalpojumi."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Vairs nerādīt"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Lietotne <xliff:g id="APP_0">%1$s</xliff:g> vēlas rādīt lietotnes <xliff:g id="APP_2">%2$s</xliff:g> sadaļas"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Rediģēt"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Zvaniem un paziņojumiem tiks aktivizēta vibrācija."</string>
@@ -2090,22 +2098,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Barošanas dialoglodziņš"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Bloķēt ekrānu"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekrānuzņēmums"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Uzkārt austiņas"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Ekrāna pieejamības saīsne"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Ekrāna pieejamības saīsnes atlasītājs"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Pieejamības saīsne"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Nerādīt paziņojumu paneli"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Virzienu slēdzis — augšup"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Virzienu slēdzis — lejup"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Virzienu slēdzis — pa kreisi"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Virzienu slēdzis — pa labi"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Virzienu slēdzis — centrs"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Lietotnes <xliff:g id="APP_NAME">%1$s</xliff:g> subtitru josla."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Pakotne “<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>” ir ievietota ierobežotā kopā."</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2126,10 +2128,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Lai ieslēgtu, pieskarieties"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Nav darba lietotņu"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Nav personīgu lietotņu"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Vai atvērt lietotni <xliff:g id="APP">%s</xliff:g> jūsu personīgajā profilā?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Vai atvērt lietotni <xliff:g id="APP">%s</xliff:g> jūsu darba profilā?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Izmantot personīgo pārlūku"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Izmantot darba pārlūku"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM tīkla atbloķēšanas PIN"</string>
@@ -2264,4 +2264,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> darbojas fonā un patērē akumulatora enerģiju. Pieskarieties, lai to pārskatītu."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> ilgi darbojas fonā. Pieskarieties, lai to pārskatītu."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Pārbaudiet aktīvās lietotnes"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 930e4ab..a67a522 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Внесете го заклучувањето на екранот за да продолжите"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Откриен е делумен отпечаток"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Отпечатокот не може да се обработи. Обидете се повторно."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Исчистете го сензорот"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Држете малку подолго"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Прстот се движеше премногу бавно. Обидете се повторно."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Пробајте со друг отпечаток"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Премногу светло"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Менувајте ја положбата на прстот по малку секој пат"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Отпечатокот е проверен"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Лицето е проверено"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Лицето е проверено, притиснете го копчето „Потврди“"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Прескокни"</string>
<string name="no_matches" msgid="6472699895759164599">"Нема совпаѓања"</string>
<string name="find_on_page" msgid="5400537367077438198">"Пронајди на страница"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# совпаѓање}one{# од {total}}other{# од {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Готово"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Бришење споделена меморија…"</string>
<string name="share" msgid="4157615043345227321">"Сподели"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Вклучи"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Апликацијата не е достапна"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> не е достапна во моментов."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> е недостапна"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Ова не може да се отвори на <xliff:g id="DEVICE">%1$s</xliff:g> во моментов. Пробајте на вашиот Android TV како алтернатива."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Ова не може да се отвори на <xliff:g id="DEVICE">%1$s</xliff:g> во моментов. Пробајте на вашиот таблет како алтернатива."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Ова не може да се отвори на <xliff:g id="DEVICE">%1$s</xliff:g> во моментов. Пробајте на вашиот телефон како алтернатива."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Апликацијава е создадена за постара верзија на Android и може да не функционира правилно. Проверете за ажурирања или контактирајте со програмерот."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Проверка за ажурирање"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Имате нови пораки"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ДЕИНСТАЛИРАЈ"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"СЕПАК ОТВОРИ"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Откриена е штетна апликација"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Барање за пристап до системска евиденција"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Само овој пат"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Не дозволувај"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> бара системска евиденција за отстранување грешка на функција. Оваа евиденција може да содржи податоци запишани од апликациите и услугите на уредот."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Не прикажувај повторно"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> сака да прикажува делови од <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Измени"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Повиците и известувањата ќе вибрираат"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Дијалог за напојување"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заклучен екран"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Слика од екранот"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Елемент за привлекување на слушалките"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Кратенка за пристапност на екранот"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Избирач на кратенка за пристапност на екранот"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Кратенка за пристапност"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Отфрлете го панелот за известување"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Навигациско копче за нагоре"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Навигациско копче за надолу"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Навигациско копче за налево"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Навигациско копче за надесно"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Навигациско копче за средина"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Насловна лента на <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> е ставен во корпата ОГРАНИЧЕНИ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Допрете за да вклучите"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Нема работни апликации"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Нема лични апликации"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Да се отвори <xliff:g id="APP">%s</xliff:g> во личниот профил?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Да се отвори <xliff:g id="APP">%s</xliff:g> во работниот профил?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Користи личен прелистувач"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Користи работен прелистувач"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"PIN за отклучување на мрежата на SIM-картичката"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> се извршува во заднина и ја троши батеријата. Допрете за да прегледате."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> се извршува во заднина веќе долго време. Допрете за да прегледате."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Проверете ги активните апликации"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index c41cec4..ec027b9 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -304,10 +304,8 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"നിങ്ങളുടെ കലണ്ടർ ആക്സസ്സ് ചെയ്യുക"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS സന്ദേശങ്ങൾ അയയ്ക്കുകയും കാണുകയും ചെയ്യുക"</string>
- <!-- no translation found for permgrouplab_storage (9173334109512154196) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (8352226729501080525) -->
- <skip />
+ <string name="permgrouplab_storage" msgid="9173334109512154196">"ഫയലുകളും ഡോക്യുമെന്റുകളും"</string>
+ <string name="permgroupdesc_storage" msgid="8352226729501080525">"നിങ്ങളുടെ ഉപകരണത്തിലെ ഫയലുകളും ഡോക്യുമെന്റുകളും ആക്സസ് ചെയ്യുക"</string>
<string name="permgrouplab_readMediaAural" msgid="5885210465560755316">"സംഗീതവും മറ്റ് ഓഡിയോയും"</string>
<string name="permgroupdesc_readMediaAural" msgid="1170143315714662822">"നിങ്ങളുടെ ഉപകരണത്തിലെ ഓഡിയോ ഫയലുകൾ ആക്സസ് ചെയ്യുക"</string>
<string name="permgrouplab_readMediaVisual" msgid="9137695801926624061">"ഫോട്ടോകളും വീഡിയോകളും"</string>
@@ -588,8 +586,9 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"തുടരാൻ നിങ്ങളുടെ സ്ക്രീൻ ലോക്ക് നൽകുക"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"ഫിംഗർപ്രിന്റ് ഭാഗികമായി തിരിച്ചറിഞ്ഞു"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ഫിംഗർപ്രിന്റ് പ്രോസസ് ചെയ്യാനായില്ല. വീണ്ടും ശ്രമിക്കുക."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"സെൻസർ വൃത്തിയാക്കുക"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"കുറച്ച് സമയം കൂടി അമർത്തിപ്പിടിക്കുക"</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"ഫിംഗർപ്രിന്റ് സെൻസർ വൃത്തിയാക്കിയ ശേഷം വീണ്ടും ശ്രമിക്കുക"</string>
+ <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"സെൻസർ വൃത്തിയാക്കിയ ശേഷം വീണ്ടും ശ്രമിക്കുക"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"സെൻസറിന് മുകളിൽ ശക്തിയായി അമർത്തുക"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"വിരൽ വളരെ പതുക്കെ നീക്കി. വീണ്ടും ശ്രമിക്കുക."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"മറ്റൊരു ഫിംഗർപ്രിന്റ് ഉപയോഗിച്ച് നോക്കുക"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"തെളിച്ചം വളരെയധികമാണ്"</string>
@@ -597,6 +596,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"ഓരോ തവണയും നിങ്ങളുടെ വിരലിന്റെ സ്ഥാനം ചെറുതായി മാറ്റുക"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"ഫിംഗർപ്രിന്റ് തിരിച്ചറിഞ്ഞില്ല"</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="4709197752023550709">"സെൻസറിന് മുകളിൽ ശക്തിയായി അമർത്തുക"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ഫിംഗർപ്രിന്റ് പരിശോധിച്ചുറപ്പിച്ചു"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"മുഖം പരിശോധിച്ചുറപ്പിച്ചു"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"മുഖം പരിശോധിച്ചുറപ്പിച്ചു, സ്ഥിരീകരിക്കുക അമർത്തുക"</string>
@@ -1500,7 +1501,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"ഒഴിവാക്കുക"</string>
<string name="no_matches" msgid="6472699895759164599">"പൊരുത്തപ്പെടലുകൾ ഒന്നുമില്ല"</string>
<string name="find_on_page" msgid="5400537367077438198">"പേജിൽ കണ്ടെത്തുക"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# പൊരുത്തം}other{{total}-ൽ #-ാമത്തെ പൊരുത്തം}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"പൂർത്തിയായി"</string>
<string name="progress_erasing" msgid="6891435992721028004">"പങ്കിടുന്ന സ്റ്റോറേജ് മായ്ക്കുന്നു…"</string>
<string name="share" msgid="4157615043345227321">"പങ്കിടുക"</string>
@@ -1928,6 +1930,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"ഓണാക്കുക"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ആപ്പ് ലഭ്യമല്ല"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ഇപ്പോൾ ലഭ്യമല്ല."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ലഭ്യമല്ല"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"ഇപ്പോൾ നിങ്ങളുടെ <xliff:g id="DEVICE">%1$s</xliff:g> ഉപകരണത്തിൽ ഇത് ആക്സസ് ചെയ്യാനാകില്ല. പകരം Android TV ഉപകരണത്തിൽ ശ്രമിച്ച് നോക്കൂ."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"ഇപ്പോൾ നിങ്ങളുടെ <xliff:g id="DEVICE">%1$s</xliff:g> ഉപകരണത്തിൽ ഇത് ആക്സസ് ചെയ്യാനാകില്ല. പകരം നിങ്ങളുടെ ടാബ്ലെറ്റിൽ ശ്രമിച്ച് നോക്കൂ."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"ഇപ്പോൾ നിങ്ങളുടെ <xliff:g id="DEVICE">%1$s</xliff:g> ഉപകരണത്തിൽ ഇത് ആക്സസ് ചെയ്യാനാകില്ല. പകരം നിങ്ങളുടെ ഫോണിൽ ശ്രമിച്ച് നോക്കൂ."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ഈ ആപ്പ് Android-ന്റെ പഴയ പതിപ്പിനായി നിർമ്മിച്ചിരിക്കുന്നതിനാൽ ശരിയായി പ്രവർത്തിച്ചേക്കില്ല. അപ്ഡേറ്റിനായി പരിശോധിക്കുക, അല്ലെങ്കിൽ ഡെവലപ്പറുമായി ബന്ധപ്പെടുക."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"അപ്ഡേറ്റിനായി പരിശോധിക്കുക"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"നിങ്ങൾക്ക് പുതിയ സന്ദേശങ്ങൾ ഉണ്ട്"</string>
@@ -2017,16 +2023,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"അൺഇൻസ്റ്റാള് ചെയ്യുക"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"എന്തായാലും തുറക്കുക"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"ദോഷകരമായ ആപ്പ് കണ്ടെത്തി"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"സിസ്റ്റം ലോഗ് ആക്സസ് അഭ്യർത്ഥന"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"ഇപ്രാവശ്യം മാത്രം"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"അനുവദിക്കരുത്"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>, ഫംഗ്ഷണൽ ഡീബഗ്ഗിംഗിന് സിസ്റ്റം ലോഗുകൾ അഭ്യർത്ഥിക്കുന്നു. ഈ ലോഗുകളിൽ, നിങ്ങളുടെ ഉപകരണത്തിലെ ആപ്പുകളും സേവനങ്ങളും രേഖപ്പെടുത്തിയ വിവരങ്ങൾ അടങ്ങിയേക്കാം."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"വീണ്ടും കാണിക്കരുത്"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_2">%2$s</xliff:g> സ്ലൈസുകൾ കാണിക്കാൻ <xliff:g id="APP_0">%1$s</xliff:g> താൽപ്പര്യപ്പെടുന്നു"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"എഡിറ്റ് ചെയ്യുക"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"കോളുകളും അറിയിപ്പുകളും വൈബ്രേറ്റ് ചെയ്യും"</string>
@@ -2119,10 +2120,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"ഓണാക്കാൻ ടാപ്പ് ചെയ്യുക"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"ഔദ്യോഗിക ആപ്പുകൾ ഇല്ല"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"വ്യക്തിപര ആപ്പുകൾ ഇല്ല"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"<xliff:g id="APP">%s</xliff:g>, നിങ്ങളുടെ വ്യക്തിപരമായ പ്രൊഫൈലിൽ തുറക്കണോ?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"<xliff:g id="APP">%s</xliff:g>, നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈലിൽ തുറക്കണോ?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"വ്യക്തിപരമായ ബ്രൗസർ ഉപയോഗിക്കുക"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"ഔദ്യോഗിക ബ്രൗസർ ഉപയോഗിക്കുക"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"സിം നെറ്റ്വർക്ക് അൺലോക്ക് ചെയ്യാനുള്ള പിൻ"</string>
@@ -2257,4 +2256,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> ആപ്പ് പശ്ചാത്തലത്തിൽ റൺ ചെയ്യുന്നു, ഇത് ബാറ്ററി ഉപയോഗിച്ചുതീർക്കുന്നു. അവലോകനം ചെയ്യാൻ ടാപ്പ് ചെയ്യുക."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"പശ്ചാത്തലത്തിൽ <xliff:g id="APP">%1$s</xliff:g> ആപ്പ് ഒരുപാട് നേരമായി റൺ ചെയ്യുന്നു. അവലോകനം ചെയ്യാൻ ടാപ്പ് ചെയ്യുക."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"സജീവമായ ആപ്പുകൾ പരിശോധിക്കുക"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 9fee4c8..5681de0 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -304,10 +304,8 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"Календарь руу хандах"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"Мессеж"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS мессежийг илгээх, харах"</string>
- <!-- no translation found for permgrouplab_storage (9173334109512154196) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (8352226729501080525) -->
- <skip />
+ <string name="permgrouplab_storage" msgid="9173334109512154196">"Файл болон документ"</string>
+ <string name="permgroupdesc_storage" msgid="8352226729501080525">"таны төхөөрөмж дээрх файл болон документод хандах"</string>
<string name="permgrouplab_readMediaAural" msgid="5885210465560755316">"Хөгжим & бусад аудио"</string>
<string name="permgroupdesc_readMediaAural" msgid="1170143315714662822">"таны төхөөрөмж дээрх аудио файлд хандах"</string>
<string name="permgrouplab_readMediaVisual" msgid="9137695801926624061">"Зураг & видео"</string>
@@ -588,8 +586,9 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Үргэлжлүүлэхийн тулд дэлгэцийн түгжээгээ оруулна уу"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Хэсэгчилсэн хурууны хээ илэрлээ"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Хурууны хээ боловсруулж чадахгүй байна. Дахин оролдоно уу."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Мэдрэгчийг цэвэрлэнэ үү"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Бага зэрэг удаан дарна уу"</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Хурууны хээ мэдрэгчийг цэвэрлээд, дахин оролдоно уу"</string>
+ <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Мэдрэгчийг цэвэрлээд, дахин оролдоно уу"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Мэдрэгч дээр чанга дарна уу"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Хуруу хэт удаан хөдөлгөсөн байна. Дахин оролдоно уу."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Өөр хурууны хээ туршина уу"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Хэт гэрэлтэй байна"</string>
@@ -597,6 +596,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Хурууныхаа байрлалыг тухай бүрд бага зэрэг өөрчилнө үү"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"Хурууны хээг таньсангүй"</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="4709197752023550709">"Мэдрэгч дээр чанга дарна уу"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Хурууны хээг нотолсон"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Царайг баталгаажууллаа"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Царайг баталгаажууллаа. Баталгаажуулах товчлуурыг дарна уу"</string>
@@ -1500,7 +1501,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Алгасах"</string>
<string name="no_matches" msgid="6472699895759164599">"Илэрц алга"</string>
<string name="find_on_page" msgid="5400537367077438198">"Хуудаснаас олох"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# таарсан илэрц{total}-н }other{#}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Дуусгах"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Хуваалцсан хадгалах санг устгаж байна…"</string>
<string name="share" msgid="4157615043345227321">"Хуваалцах"</string>
@@ -1928,6 +1930,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Асаах"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Апп боломжгүй байна"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> яг одоо боломжгүй байна."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> боломжгүй байна"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Одоогоор үүнд таны <xliff:g id="DEVICE">%1$s</xliff:g> дээрээс хандах боломжгүй. Оронд нь Android TV төхөөрөмж дээрээ туршиж үзнэ үү."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Одоогоор үүнд таны <xliff:g id="DEVICE">%1$s</xliff:g> дээрээс хандах боломжгүй. Оронд нь таблет дээрээ туршиж үзнэ үү."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Одоогоор үүнд таны <xliff:g id="DEVICE">%1$s</xliff:g> дээрээс хандах боломжгүй. Оронд нь утсан дээрээ туршиж үзнэ үү."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Энэ аппыг Андройдын хуучин хувилбарт зориулсан бөгөөд буруу ажиллаж болзошгүй. Шинэчлэлтийг шалгаж эсвэл хөгжүүлэгчтэй холбогдоно уу."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Шинэчлэлтийг шалгах"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Танд шинэ мессежүүд байна"</string>
@@ -2017,16 +2023,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"УСТГАХ"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"ЯМАР Ч ТОХИОЛДОЛД НЭЭХ"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Аюултай апп олдсон"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Системийн логийн хандалтын хүсэлт"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Зөвхөн энэ удаа"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Бүү зөвшөөр"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> функциональ дибаг хийх системийн логийг хүсдэг. Эдгээр лог нь таны төхөөрөмж дээрх апп болон үйлчилгээнүүдийн бичсэн мэдээллийг агуулж болно."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Дахиж бүү харуул"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> <xliff:g id="APP_2">%2$s</xliff:g>-н хэсгүүдийг (slices) харуулах хүсэлтэй байна"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Засах"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Дуудлага болон мэдэгдэл чичирнэ"</string>
@@ -2089,22 +2090,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Тэжээлийн харилцах цонх"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Дэлгэцийг түгжих"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Дэлгэцийн зураг дарах"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Чихэвч дэгээдэгч"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Дэлгэц дээрх хандалтын товчлол"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Дэлгэц дээрх хандалтын товчлол сонгогч"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Хандалтын товчлол"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Мэдэгдлийн хураангуй самбарыг хаах"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Dpad дээш"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Dpad доош"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad зүүн"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad баруун"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad гол"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>-н гарчгийн талбар."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>-г ХЯЗГААРЛАСАН сагс руу орууллаа"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2120,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Асаахын тулд товших"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Ямар ч ажлын апп байхгүй байна"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Ямар ч хувийн апп байхгүй байна"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Хувийн профайл дээрээ <xliff:g id="APP">%s</xliff:g>-г нээх үү?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Ажлын профайл дээрээ <xliff:g id="APP">%s</xliff:g>-г нээх үү?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Хувийн хөтөч ашиглах"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Ажлын хөтөч ашиглах"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"Сүлжээний SIM-н түгжээг тайлах ПИН"</string>
@@ -2263,4 +2256,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> дэвсгэрт ажиллаж байгаа бөгөөд батарейг дуусгаж байна. Хянахын тулд товшино уу."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> дэвсгэрт удаан хугацааны турш ажиллаж байна. Хянахын тулд товшино уу."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Идэвхтэй аппуудыг шалгах"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index af1e760..1c434bb 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -304,10 +304,8 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"आपल्या कॅलेंडरवर प्रवेश"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS मेसेज पाठवणे आणि पाहणे हे"</string>
- <!-- no translation found for permgrouplab_storage (9173334109512154196) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (8352226729501080525) -->
- <skip />
+ <string name="permgrouplab_storage" msgid="9173334109512154196">"फाइल आणि दस्तऐवज"</string>
+ <string name="permgroupdesc_storage" msgid="8352226729501080525">"तुमच्या डिव्हाइसवर फाइल आणि दस्तऐवज अॅक्सेस करा"</string>
<string name="permgrouplab_readMediaAural" msgid="5885210465560755316">"संगीत & इतर ऑडिओ"</string>
<string name="permgroupdesc_readMediaAural" msgid="1170143315714662822">"तुमच्या डिव्हाइसवर ऑडिओ फाइल अॅक्सेस करा"</string>
<string name="permgrouplab_readMediaVisual" msgid="9137695801926624061">"फोटो & व्हिडिओ"</string>
@@ -588,8 +586,9 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"पुढे सुरू ठेवण्यासाठी तुमचे स्क्रीन लॉक एंटर करा"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"आंशिक फिंगरप्रिंट डिटेक्ट केली"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"फिंगरप्रिंटवर प्रक्रिया करणे शक्य झाले नाही. कृपया पुन्हा प्रयत्न करा."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"सेन्सर साफ करा"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"जरा जास्त वेळ धरून ठेवा"</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"फिंगरप्रिंट सेन्सर स्वच्छ करा आणि पुन्हा प्रयत्न करा"</string>
+ <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"सेन्सर स्वच्छ करा आणि पुन्हा प्रयत्न करा"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"सेन्सरवर जोरात दाबा"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"बोट खूप सावकाश हलविले. कृपया पुन्हा प्रयत्न करा."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"दुसरी फिंगरप्रिंट वापरून पहा"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"खूप प्रखर"</string>
@@ -597,6 +596,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"तुमच्या बोटाची स्थिती प्रत्येक वेळी थोडीशी बदला"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"फिंगरप्रिंट ओळखले नाही"</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="4709197752023550709">"सेन्सरवर जोरात दाबा"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"फिंगरप्रिंट ऑथेंटिकेट केली आहे"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"चेहरा ऑथेंटिकेशन केलेला आहे"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"चेहरा ऑथेंटिकेशन केलेला आहे, कृपया कंफर्म दाबा"</string>
@@ -1500,7 +1501,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"वगळा"</string>
<string name="no_matches" msgid="6472699895759164599">"कोणत्याही जुळण्या नाहीत"</string>
<string name="find_on_page" msgid="5400537367077438198">"पेजवर शोधा"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# सामना }other{ # सामने }} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"पूर्ण केले"</string>
<string name="progress_erasing" msgid="6891435992721028004">"शेअर केलेले स्टोरेज मिटवत आहे…"</string>
<string name="share" msgid="4157615043345227321">"शेअर करा"</string>
@@ -1928,6 +1930,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"सुरू करा"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ॲप उपलब्ध नाही"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> आता उपलब्ध नाही."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> उपलब्ध नाही"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"हे यावेळी तुमच्या <xliff:g id="DEVICE">%1$s</xliff:g> वर अॅक्सेस करू शकत नाही. त्याऐवजी तुमच्या Android TV डिव्हाइसवर अॅक्सेस करून पहा."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"हे यावेळी तुमच्या <xliff:g id="DEVICE">%1$s</xliff:g> वर अॅक्सेस करू शकत नाही. त्याऐवजी तुमच्या टॅबलेटवर अॅक्सेस करून पहा."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"हे यावेळी तुमच्या <xliff:g id="DEVICE">%1$s</xliff:g> वर अॅक्सेस करू शकत नाही. त्याऐवजी तुमच्या फोनवर अॅक्सेस करून पहा."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"हे अॅप Android च्या जुन्या आवृत्ती साठी तयार करण्यात आले होते आणि योग्यरितीने कार्य करू शकणार नाही. अपडेट आहेत का ते तपासून पहा, किंवा डेव्हलपरशी संपर्क साधण्याचा प्रयत्न करा."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"अपडेटसाठी तपासा"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"आपल्याकडे नवीन मेसेज आहेत"</string>
@@ -2017,16 +2023,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"अनइंस्टॉल करा"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"तरीही उघडा"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"हानिकारक अॅप आढळला"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"सिस्टीम लॉगच्या अॅक्सेसची विनंती"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"फक्त यावेळी"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"अनुमती देऊ नका"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> हे फंक्शनल डीबगिंगसाठी सिस्टीम लॉगची विनंती करते. या लॉगमध्ये तुमच्या डिव्हाइसवरील ॲप्स आणि सेवांनी लिहिलेली माहिती असू शकते."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"पुन्हा दाखवू नका"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ला <xliff:g id="APP_2">%2$s</xliff:g> चे तुकडे दाखवायचे आहेत"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"संपादित करा"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"कॉल आणि सूचनांवर व्हायब्रेट होईल"</string>
@@ -2119,10 +2120,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"सुरू करण्यासाठी टॅप करा"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"कोणतीही कार्य ॲप्स सपोर्ट करत नाहीत"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"कोणतीही वैयक्तिक ॲप्स सपोर्ट करत नाहीत"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"तुमच्या वैयक्तिक प्रोफाइलमध्ये <xliff:g id="APP">%s</xliff:g> उघडायचे आहे का?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"तुमच्या कार्य प्रोफाइलमध्ये <xliff:g id="APP">%s</xliff:g> उघडायचे आहे का?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"वैयक्तिक ब्राउझर वापरा"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"कार्य ब्राउझर वापरा"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"सिम नेटवर्क अनलॉक पिन"</string>
@@ -2257,4 +2256,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> हे बॅकग्राउंडमध्ये रन होत आहे आणि बॅटरी संपवत आहे. पुनरावलोकनासाठी टॅप करा."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> हे बऱ्याच कालावधीपासून बॅकग्राउंडमध्ये रन होत आहे. पुनरावलोकनासाठी टॅप करा."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"ॲक्टिव्ह ॲप्स पहा"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index cacdc8d..b4ce57c 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Masukkan kunci skrin untuk teruskan"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Cap jari separa dikesan"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Tidak dapat memproses cap jari. Sila cuba lagi."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Bersihkan penderia"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Tahan lebih lama sedikit"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Jari digerakkan terlalu perlahan. Sila cuba lagi."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Cuba cap jari lain"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Terlalu terang"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Tukar sedikit kedudukan jari anda setiap kali pergerakan dilakukan"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Cap jari disahkan"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Wajah disahkan"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Wajah disahkan, sila tekan sahkan"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Langkau"</string>
<string name="no_matches" msgid="6472699895759164599">"Tiada padanan"</string>
<string name="find_on_page" msgid="5400537367077438198">"Cari di halaman"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# padanan}other{# daripada {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Selesai"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Memadamkan storan kongsi…"</string>
<string name="share" msgid="4157615043345227321">"Kongsi"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Hidupkan"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Apl tidak tersedia"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak tersedia sekarang."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> tidak tersedia"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Aplikasi ini tidak boleh diakses pada <xliff:g id="DEVICE">%1$s</xliff:g> anda pada masa ini. Cuba pada peranti Android TV anda."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Aplikasi ini tidak boleh diakses pada <xliff:g id="DEVICE">%1$s</xliff:g> anda pada masa ini. Cuba pada tablet anda."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Aplikasi ini tidak boleh diakses pada <xliff:g id="DEVICE">%1$s</xliff:g> anda pada masa ini. Cuba pada telefon anda."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Apl ini dibina untuk versi Android yang lebih lama dan mungkin tidak berfungsi dengan betul. Cuba semak kemas kini atau hubungi pembangun."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Semak kemaskinian"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Anda mempunyai mesej baharu"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"NYAHPASANG"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"BUKA JUGA"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Apl berbahaya dikesan"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Permintaan akses log sistem"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Kali ini sahaja"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Jangan benarkan"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> meminta log sistem untuk penyahpepijatan berfungsi. Log ini mungkin mengandungi maklumat yang telah ditulis apl dan perkhidmatan pada peranti anda."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Jangan tunjuk lagi"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> mahu menunjukkan <xliff:g id="APP_2">%2$s</xliff:g> hirisan"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Panggilan dan pemberitahuan akan bergetar"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialog Kuasa"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Skrin Kunci"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Tangkapan skrin"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Cangkuk Set Kepala"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Pintasan Kebolehaksesan Pada Skrin"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Pemilih Pintasan Kebolehaksesan Pada Skrin"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Pintasan Kebolehaksesan"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Ketepikan Bidai Pemberitahuan"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Dpad Atas"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Dpad Bawah"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad Kiri"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad Kanan"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad Tengah"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Bar kapsyen <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> telah diletakkan dalam baldi TERHAD"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Ketik untuk menghidupkan profil"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Tiada apl kerja"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Tiada apl peribadi"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Buka <xliff:g id="APP">%s</xliff:g> dalam profil peribadi anda?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Buka <xliff:g id="APP">%s</xliff:g> dalam profil kerja anda?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Gunakan penyemak imbas peribadi"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Gunakan penyemak imbas kerja"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"PIN buka kunci rangkaian SIM"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> sedang berjalan di latar belakang dan menghabiskan bateri. Ketik untuk menyemak."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g>sedang berjalan di latar belakang untuk masa yang lama. Ketik untuk menyemak."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Semak apl aktif"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 3259803..acbd498 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"ရှေ့ဆက်ရန် သင်၏ဖန်သားပြင် လော့ခ်ချခြင်းကို ထည့်ပါ"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"လက်ဗွေတစ်စိတ်တစ်ပိုင်းကို ရှာတွေ့သည်"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"လက်ဗွေယူ၍ မရပါ။ ထပ်စမ်းကြည့်ပါ။"</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"အာရုံခံကိရိယာကို သန့်ရှင်းရေးလုပ်ပါ"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"အနည်းငယ်ကြာအောင် ဖိထားပါ"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"လက်ညှိုးအလွန်နှေးကွေးစွာ ရွေ့ခဲ့သည်။ ကျေးဇူးပြု၍ ထပ်မံကြိုးစားပါ။"</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"အခြားလက်ဗွေဖြင့် စမ်းကြည့်ပါ"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"အလွန် လင်းသည်"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"အကြိမ်တိုင်း သင့်လက်ချောင်း၏တည်နေရာကို အနည်းငယ်ပြောင်းပါ"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"လက်ဗွေကို အထောက်အထား စိစစ်ပြီးပါပြီ"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"မျက်နှာ အထောက်အထားစိစစ်ပြီးပြီ"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"မျက်နှာ အထောက်အထားစိစစ်ပြီးပြီ၊ အတည်ပြုရန်ကို နှိပ်ပါ"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"ကျော်ရန်"</string>
<string name="no_matches" msgid="6472699895759164599">"ထပ်တူမတွေ့ရှိပါ"</string>
<string name="find_on_page" msgid="5400537367077438198">"စာမျက်နှာတွင်ရှာဖွေရန်"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# ပွဲ}other{{total} ပွဲအနက် #}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"ပြီးပါပြီ"</string>
<string name="progress_erasing" msgid="6891435992721028004">"မျှဝေထားသည့် သိုလှောင်ခန်းကို ဖျက်နေသည်…"</string>
<string name="share" msgid="4157615043345227321">"မျှဝေရန်"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"ဖွင့်ပါ"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"အက်ပ်ကို မရနိုင်ပါ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ကို ယခု မရနိုင်ပါ။"</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> မရနိုင်ပါ"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"၎င်းအား ယခု သင့် <xliff:g id="DEVICE">%1$s</xliff:g> တွင် ဝင်၍မရပါ။ ယင်းအစား Android TV စက်တွင် စမ်းကြည့်ပါ။"</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"၎င်းအား ယခု သင့် <xliff:g id="DEVICE">%1$s</xliff:g> တွင် ဝင်၍မရပါ။ ယင်းအစား တက်ဘလက်တွင် စမ်းကြည့်ပါ။"</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"၎င်းအား ယခု သင့် <xliff:g id="DEVICE">%1$s</xliff:g> တွင် ဝင်၍မရပါ။ ယင်းအစား ဖုန်းတွင် စမ်းကြည့်ပါ။"</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ဤအက်ပ်ကို Android ဗားရှင်းဟောင်းအတွက် ပြုလုပ်ထားခြင်းဖြစ်ပြီး ပုံမှန်အလုပ်မလုပ်နိုင်ပါ။ အပ်ဒိတ်များအတွက် ရှာကြည့်ပါ သို့မဟုတ် ဆော့ဖ်ဝဲအင်ဂျင်နီယာကို ဆက်သွယ်ပါ။"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"အပ်ဒိတ်စစ်ရန်"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"သင့်ထံတွင် စာအသစ်များရောက်နေသည်"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ဖြုတ်ရန်"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"ဘာဖြစ်ဖြစ် ဖွင့်ရန်"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"အန္တရာယ်ရှိသော အက်ပ်ကို တွေ့ရှိထားသည်"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"စနစ်မှတ်တမ်းသုံးခွင့် တောင်းဆိုခြင်း"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"ဤတစ်ကြိမ်သာ"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"ခွင့်မပြုပါ"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"အမှားရှာပြင်မှု လုပ်ဆောင်နိုင်ရန်အတွက် စနစ်မှတ်တမ်းများကို <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> က တောင်းဆိုသည်။ ဤမှတ်တမ်းများတွင် သင်၏စက်ပေါ်ရှိအက်ပ်နှင့် ဝန်ဆောင်မှုများ ရေးထားသော အချက်အလက်များ ပါဝင်နိုင်သည်။"</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"နောက်ထပ်မပြပါနှင့်"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> သည် <xliff:g id="APP_2">%2$s</xliff:g> ၏အချပ်များကို ပြသလိုသည်"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"တည်းဖြတ်ရန်"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"ခေါ်ဆိုမှုများနှင့် အကြောင်းကြားချက်များ တုန်ခါပါမည်"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"ပါဝါ ဒိုင်ယာလော့"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"လော့ခ်မျက်နှာပြင်"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ဖန်သားပြင်ဓာတ်ပုံ"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"မိုက်ခွက်ပါနားကြပ်ချိတ်"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"ဖန်သားပြင်အတွက် အများသုံးစွဲနိုင်မှုဖြတ်လမ်းလင့်ခ်"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"ဖန်သားပြင်အတွက် အများသုံးစွဲနိုင်မှုဖြတ်လမ်းလင့်ခ် ရွေးချယ်စနစ်"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"အများသုံးစွဲနိုင်မှု ဖြတ်လမ်းလင့်ခ်"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"အကြောင်းကြားစာအကွက်ကို ပယ်ရန်"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Dpad အပေါ်"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Dpad အောက်"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad ဘယ်"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad ညာ"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad အလယ်"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>၏ ခေါင်းစီး ဘား။"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ကို တားမြစ်ထားသော သိမ်းဆည်းမှုအတွင်းသို့ ထည့်ပြီးပါပြီ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>-"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"ဖွင့်ရန်တို့ပါ"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"အလုပ်သုံးအက်ပ်များ မရှိပါ"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"ကိုယ်ပိုင်အက်ပ်များ မရှိပါ"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"<xliff:g id="APP">%s</xliff:g> ကို သင့်ကိုယ်ပိုင်ပရိုဖိုင်တွင် ဖွင့်မလား။"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"<xliff:g id="APP">%s</xliff:g> ကို သင့်အလုပ်ပရိုဖိုင်တွင် ဖွင့်မလား။"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"ကိုယ်ပိုင်ဘရောင်ဇာ သုံးရန်"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"အလုပ်သုံးဘရောင်ဇာ သုံးရန်"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"ဆင်းမ်ကွန်ရက် လော့ခ်ဖွင့်ရန် ပင်နံပါတ်"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> သည် နောက်ခံတွင်ပွင့်နေပြီး ဘက်ထရီအားကုန်စေသည်။ ပြန်ကြည့်ရန် တို့ပါ။"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> သည် နောက်ခံတွင် အချိန်အတော်ကြာပွင့်နေသည်။ ပြန်ကြည့်ရန် တို့ပါ။"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"ပွင့်နေသည့်အက်ပ်များ စစ်ဆေးရန်"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index db84e2f..234ead8 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Skriv inn skjermlåsen for å fortsette"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Et delvis fingeravtrykk er registrert"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Kunne ikke registrere fingeravtrykket. Prøv på nytt."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Rengjør sensoren"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Hold litt lenger"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Du flyttet fingeren for sakte. Prøv på nytt."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Prøv et annet fingeravtrykk"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"For lyst"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Endre posisjonen til fingeren litt hver gang"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingeravtrykket er godkjent"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Ansiktet er autentisert"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Ansiktet er autentisert. Trykk på Bekreft"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Hopp over"</string>
<string name="no_matches" msgid="6472699895759164599">"Ingen treff"</string>
<string name="find_on_page" msgid="5400537367077438198">"Finn på side"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# treff}other{# av {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Ferdig"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Sletter delt lagring …"</string>
<string name="share" msgid="4157615043345227321">"Del"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Slå på"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Appen er ikke tilgjengelig"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> er ikke tilgjengelig for øyeblikket."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> er utilgjengelig"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Dette er ikke tilgjengelig på <xliff:g id="DEVICE">%1$s</xliff:g> for øyeblikket. Prøv på Android TV-enheten din i stedet."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Dette er ikke tilgjengelig på <xliff:g id="DEVICE">%1$s</xliff:g> for øyeblikket. Prøv på nettbrettet ditt i stedet."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Dette er ikke tilgjengelig på <xliff:g id="DEVICE">%1$s</xliff:g> for øyeblikket. Prøv på telefonen din i stedet."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Denne appen er utviklet for en eldre versjon av Android og fungerer kanskje ikke som den skal. Prøv å se etter oppdateringer, eller kontakt utvikleren."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Se etter oppdateringer"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Du har nye meldinger"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"AVINSTALLER"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"ÅPNE LIKEVEL"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"En skadelig app ble oppdaget"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Forespørsel om tilgang til systemlogg"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Bare denne gangen"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ikke tillat"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ber om systemlogger for funksjonell feilsøking. Disse loggene kan inneholde informasjon som apper og tjenester på enheten din har skrevet."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ikke vis igjen"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> vil vise <xliff:g id="APP_2">%2$s</xliff:g>-utsnitt"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Endre"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Anrop og varsler vibrerer"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialogboks for å slå av/på"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Låseskjerm"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skjermdump"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Hook for hodetelefoner"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Tilgjengelighetssnarvei på skjermen"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Velger for tilgjengelighetssnarvei på skjermen"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Tilgjengelighetssnarvei"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Lukk varselpanelet"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Opp på styrepilene"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Ned på styrepilene"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Venstre på styrepilene"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Høyre på styrepilene"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Midt på styrepilene"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Tekstingsfelt i <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> er blitt plassert i TILGANGSBEGRENSET-toppmappen"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Trykk for å slå på"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Ingen jobbapper"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Ingen personlige apper"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Vil du åpne <xliff:g id="APP">%s</xliff:g> i den personlige profilen din?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Vil du åpne <xliff:g id="APP">%s</xliff:g> i jobbprofilen din?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Bruk den personlige nettleseren"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Bruk jobbnettleseren"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"PIN-kode for å fjerne operatørlåser"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> kjører i bakgrunnen og bruker batteri. Trykk for å gjennomgå."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> kjører lenge i bakgrunnen. Trykk for å gjennomgå."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Sjekk aktive apper"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 6a4ac47..77257b1 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -304,10 +304,8 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"तपाईंको पात्रोमाथि पहुँच गर्नुहोस्"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS सन्देशहरू पठाउनुहोस् र हेर्नुहोस्"</string>
- <!-- no translation found for permgrouplab_storage (9173334109512154196) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (8352226729501080525) -->
- <skip />
+ <string name="permgrouplab_storage" msgid="9173334109512154196">"फाइल र डकुमेन्टहरू"</string>
+ <string name="permgroupdesc_storage" msgid="8352226729501080525">"आफ्नो डिभाइसमा भएका फाइल र डकुमेन्टहरू प्रयोग गर्नुहोस्"</string>
<string name="permgrouplab_readMediaAural" msgid="5885210465560755316">"सङ्गीत तथा अन्य अडियो"</string>
<string name="permgroupdesc_readMediaAural" msgid="1170143315714662822">"तपाईंको डिभाइसमा भएका अडियो फाइलहरू प्रयोग गर्ने"</string>
<string name="permgrouplab_readMediaVisual" msgid="9137695801926624061">"फोटो तथा भिडियोहरू"</string>
@@ -588,8 +586,9 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"जारी राख्न आफ्नो स्क्रिन लक हाल्नुहोस्"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"फिंगरप्रिन्ट आंशिक रूपमा पत्ता लाग्यो"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"फिंगरप्रिन्ट प्रशोधन गर्न सकिएन। कृपया फेरि प्रयास गर्नुहोस्।"</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"सेन्सर सफा गर्नुहोस्"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"औँला अलि बढी समयसम्म सेन्सरमा राख्नुहोस्"</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"फिंगरप्रिन्ट सेन्सर सफा गरेर फेरि प्रयास गर्नुहोस्"</string>
+ <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"सेन्सर सफा गरेर फेरि प्रयास गर्नुहोस्"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"सेन्सरमा बेसरी थिच्नुहोस्"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"औंला निकै सुस्त सारियो। कृपया फेरि प्रयास गर्नुहोस्।"</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"अर्को फिंगरप्रिन्ट प्रयोग गरी हेर्नुहोस्"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"ज्यादै उज्यालो छ"</string>
@@ -597,6 +596,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"हरेक पटक आफ्नो औँला थोरै यताउता सार्नुहोस्"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"फिंगरप्रिन्ट पहिचान गर्न सकिएन"</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="4709197752023550709">"सेन्सरमा बेसरी थिच्नुहोस्"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"फिंगरप्रिन्ट प्रमाणीकरण गरियो"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"अनुहार प्रमाणीकरण गरियो"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"अनुहार प्रमाणीकरण गरियो, कृपया पुष्टि गर्नुहोस् थिच्नुहोस्"</string>
@@ -1500,7 +1501,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"छोड्नुहोस्"</string>
<string name="no_matches" msgid="6472699895759164599">"कुनै मिलेन"</string>
<string name="find_on_page" msgid="5400537367077438198">"पृष्ठमा फेला पार्नुहोस्"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# खेल{total} वटा खेलमध्ये }other{# औँ खेल}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"भयो"</string>
<string name="progress_erasing" msgid="6891435992721028004">"साझेदारी गरिएको भण्डारण मेट्दै…"</string>
<string name="share" msgid="4157615043345227321">"सेयर गर्नुहोस्"</string>
@@ -1928,6 +1930,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"सक्रिय गर्नुहोस्"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"एप उपलब्ध छैन"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> अहिले उपलब्ध छैन।"</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> उपलब्ध छैन"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"यस बखत तपाईंको <xliff:g id="DEVICE">%1$s</xliff:g> मा यो एप स्ट्रिम गर्न मिल्दैन। बरु तपाईंको Android TV डिभाइसमा स्ट्रिम गरी हेर्नुहोस्।"</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"यस बखत तपाईंको <xliff:g id="DEVICE">%1$s</xliff:g> मा यो एप स्ट्रिम गर्न मिल्दैन। बरु तपाईंको ट्याब्लेटमा स्ट्रिम गरी हेर्नुहोस्।"</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"यस बखत तपाईंको <xliff:g id="DEVICE">%1$s</xliff:g> मा यो एप स्ट्रिम गर्न मिल्दैन। बरु तपाईंको फोनमा स्ट्रिम गरी हेर्नुहोस्।"</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"यो एप Android को पुरानो संस्करणका लागि बनाइएको हुनाले यसले सही ढङ्गले काम नगर्न सक्छ। अद्यावधिकहरू उपलब्ध छन् वा छैनन् भनी जाँच गरी हेर्नुहोस् वा यसको विकासकर्तालाई सम्पर्क गर्नुहोस्।"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"अपडेट उपलब्ध छ वा छैन जाँच्नुहोस्"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"तपाईंलाई नयाँ सन्देश आएको छ"</string>
@@ -2017,16 +2023,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"स्थापना रद्द गर्नु…"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"जे भए पनि खोल्नुहोस्"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"हानिकारक एप भेटियो"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"सिस्टम लग प्रयोग गर्ने अनुमति"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"यस पटक मात्र"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"अनुमति नदिनुहोस्"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ले फङ्सनल डिबग प्रक्रियाका लागि सिस्टम लगहरू हेर्ने तथा प्रयोग गर्ने अनुमति माग्दै छ। यी लगहरूमा तपाईंको डिभाइसमा रहेका एप र सेवाहरूले राइट गरेको जानकारी समावेश हुन सक्छ।"</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"फेरि नदेखाइयोस्"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ले <xliff:g id="APP_2">%2$s</xliff:g> का स्लाइसहरू देखाउन चाहन्छ"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"सम्पादन गर्नुहोस्"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"कल तथा सूचनाहरू आउँदा कम्पन हुने छ"</string>
@@ -2119,10 +2120,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"अन गर्न ट्याप गर्नुहोस्"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"यो सामग्री खोल्न मिल्ने कुनै पनि कामसम्बन्धी एप छैन"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"यो सामग्री खोल्न मिल्ने कुनै पनि व्यक्तिगत एप छैन"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"<xliff:g id="APP">%s</xliff:g> तपाईंको व्यक्तिगत प्रोफाइलमा खोल्ने हो?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"<xliff:g id="APP">%s</xliff:g> तपाईंको कार्य प्रोफाइलमा खोल्ने हो?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"व्यक्तिगत ब्राउजर प्रयोग गर्नुहोस्"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"कार्य ब्राउजर प्रयोग गर्नुहोस्"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM को नेटवर्क अनलक गर्ने PIN"</string>
@@ -2257,4 +2256,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> ब्याकग्राउन्डमा चलिरहेको हुनाले ब्याट्री खपत भइरहेको छ। तपाईं यसका सम्बन्धमा समीक्षा गर्न चाहनुहुन्छ भने ट्याप गर्नुहोस्।"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> लामो समयदेखि ब्याकग्राउन्डमा चलिरहेको छ। तपाईं यसका सम्बन्धमा समीक्षा गर्न चाहनुहुन्छ भने ट्याप गर्नुहोस्।"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"कुन कुन एप सक्रिय छ भन्ने कुरा जाँच्नुहोस्"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index b06db70..f85f5f6 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Voer je schermvergrendeling in om door te gaan"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Gedeeltelijke vingerafdruk gedetecteerd"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Kan vingerafdruk niet verwerken. Probeer het opnieuw."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Maak de sensor schoon"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Houd iets langer vast"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Vinger te langzaam bewogen. Probeer het opnieuw."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Probeer een andere vingerafdruk"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Te veel licht"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Verander de positie van je vinger steeds een beetje"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Vingerafdruk geverifieerd"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Gezicht geverifieerd"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Gezicht geverifieerd. Druk op Bevestigen."</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Overslaan"</string>
<string name="no_matches" msgid="6472699895759164599">"Geen overeenkomsten"</string>
<string name="find_on_page" msgid="5400537367077438198">"Zoeken op pagina"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# overeenkomst}other{# van {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Klaar"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Gedeelde opslag wissen…"</string>
<string name="share" msgid="4157615043345227321">"Delen"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aanzetten"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"App is niet beschikbaar"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is momenteel niet beschikbaar."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> niet beschikbaar"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Je hebt hier nu geen toegang toe op je <xliff:g id="DEVICE">%1$s</xliff:g>. Probeer het in plaats daarvan op je Android TV-apparaat."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Je hebt hier nu geen toegang toe op je <xliff:g id="DEVICE">%1$s</xliff:g>. Probeer het in plaats daarvan op je tablet."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Je hebt hier nu geen toegang toe op je <xliff:g id="DEVICE">%1$s</xliff:g>. Probeer het in plaats daarvan op je telefoon."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Deze app is ontwikkeld voor een oudere versie van Android en werkt mogelijk niet op de juiste manier. Controleer op updates of neem contact op met de ontwikkelaar."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Controleren op update"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Je hebt nieuwe berichten"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"VERWIJDEREN"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"TOCH OPENEN"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Schadelijke app gevonden"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Verzoek om toegang tot systeemlogboeken"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Alleen deze keer"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Niet toestaan"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> vraagt om systeemlogboeken voor functionele foutopsporing. Deze logboeken kunnen informatie bevatten die apps en services op je apparaat hebben geschreven."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Niet opnieuw tonen"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wil segmenten van <xliff:g id="APP_2">%2$s</xliff:g> tonen"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Bewerken"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Trillen bij gesprekken en meldingen"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Voedingsdialoogvenster"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Scherm vergrendelen"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Headset-hook"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Snelkoppeling voor toegankelijkheid op scherm"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Kiezer voor snelkoppeling voor toegankelijkheid op scherm"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Snelkoppeling voor toegankelijkheid"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Meldingenpaneel sluiten"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"D-pad omhoog"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"D-pad omlaag"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"D-pad links"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"D-pad rechts"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"D-pad midden"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Ondertitelingsbalk van <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> is in de bucket RESTRICTED geplaatst"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Tik om aan te zetten"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Geen werk-apps"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Geen persoonlijke apps"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"<xliff:g id="APP">%s</xliff:g> openen in je persoonlijke profiel?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"<xliff:g id="APP">%s</xliff:g> openen in je werkprofiel?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Persoonlijke browser gebruiken"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Werkbrowser gebruiken"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"Ontgrendelingspincode voor SIM-netwerk"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> wordt uitgevoerd op de achtergrond en verbruikt veel batterijlading. Tik om te bekijken."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> wordt al lange tijd uitgevoerd op de achtergrond. Tik om te bekijken."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Actieve apps checken"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 37682af..0a945e0 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -304,10 +304,8 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"ଆପଣଙ୍କ କ୍ୟାଲେଣ୍ଡର୍ ଆକ୍ସେସ୍ କରେ"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS ମେସେଜ୍ ପଠାନ୍ତୁ ଓ ଦେଖନ୍ତୁ"</string>
- <!-- no translation found for permgrouplab_storage (9173334109512154196) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (8352226729501080525) -->
- <skip />
+ <string name="permgrouplab_storage" msgid="9173334109512154196">"ଫାଇଲ ଏବଂ ଡକ୍ୟୁମେଣ୍ଟଗୁଡ଼ିକ"</string>
+ <string name="permgroupdesc_storage" msgid="8352226729501080525">"ଆପଣଙ୍କ ଡିଭାଇସରେ ଥିବା ଫାଇଲ ଏବଂ ଡକ୍ୟୁମେଣ୍ଟଗୁଡ଼ିକୁ ଆକ୍ସେସ କରନ୍ତୁ"</string>
<string name="permgrouplab_readMediaAural" msgid="5885210465560755316">"ମ୍ୟୁଜିକ ଓ ଅନ୍ୟ ଅଡିଓ"</string>
<string name="permgroupdesc_readMediaAural" msgid="1170143315714662822">"ଆପଣଙ୍କ ଡିଭାଇସରେ ଅଡିଓ ଫାଇଲଗୁଡ଼ିକୁ ଆକ୍ସେସ କରନ୍ତୁ"</string>
<string name="permgrouplab_readMediaVisual" msgid="9137695801926624061">"ଫଟୋ ଓ ଭିଡିଓଗୁଡ଼ିକ"</string>
@@ -588,8 +586,9 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"ଜାରି ରଖିବାକୁ ଆପଣଙ୍କ ସ୍କ୍ରିନ୍ ଲକ୍ ଏଣ୍ଟର୍ କରନ୍ତୁ"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"ଆଂଶିକ ଟିପଚିହ୍ନ ଚିହ୍ନଟ କରାଯାଇଛି"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ଟିପଚିହ୍ନ ପ୍ରୋସେସ୍ କରାଯାଇପାରିଲା ନାହିଁ। ଦୟାକରି ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"ସେନ୍ସରକୁ ସଫା କରନ୍ତୁ"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"ଟିକିଏ ଅଧିକ ସମୟ ଧରି ରଖନ୍ତୁ"</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"ଟିପଚିହ୍ନ ସେନ୍ସରକୁ ପରିଷ୍କାର କରି ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ"</string>
+ <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"ସେନ୍ସରକୁ ପରିଷ୍କାର କରି ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"ସେନ୍ସର ଉପରେ ଦୃଢ଼ ଭାବେ ଦବାନ୍ତୁ"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"ଆଙ୍ଗୁଠି ଖୁବ୍ ଧୀରେ ନିଆଗଲା। ଦୟାକରି ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"ଅନ୍ୟ ଏକ ଟିପଚିହ୍ନ ବ୍ୟବହାର କରି ଦେଖନ୍ତୁ"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"ବହୁତ ଉଜ୍ଜ୍ୱଳ"</string>
@@ -597,6 +596,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"ପ୍ରତି ଥର ଆପଣଙ୍କ ଆଙ୍ଗୁଠିର ସ୍ଥାନ ସାମାନ୍ୟ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"ଟିପଚିହ୍ନ ଚିହ୍ନଟ ହେଲା ନାହିଁ"</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="4709197752023550709">"ସେନ୍ସର ଉପରେ ଦୃଢ଼ ଭାବେ ଦବାନ୍ତୁ"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ଟିପଚିହ୍ନ ପ୍ରମାଣିତ ହେଲା"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"ମୁହଁ ଚିହ୍ନଟ ହୋଇଛି"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"ମୁହଁ ଚିହ୍ନଟ ହୋଇଛି, ଦୟାକରି ସୁନିଶ୍ଚିତ ଦବାନ୍ତୁ"</string>
@@ -1500,7 +1501,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"ଛାଡ଼ିଦିଅନ୍ତୁ"</string>
<string name="no_matches" msgid="6472699895759164599">"କୌଣସି ମେଳକ ନାହିଁ"</string>
<string name="find_on_page" msgid="5400537367077438198">"ପୃଷ୍ଠାରେ ଖୋଜନ୍ତୁ"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{#ଟି ମେଳ{total}ର }other{#ଟି ମେଳ}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"ହୋଇଗଲା"</string>
<string name="progress_erasing" msgid="6891435992721028004">"ସେୟାର୍ ହୋଇଥିବା ଷ୍ଟୋରେଜ୍ ଲିଭାଉଛି…"</string>
<string name="share" msgid="4157615043345227321">"ସେୟାର୍"</string>
@@ -1928,6 +1930,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"ଚାଲୁ କରନ୍ତୁ"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ଆପ୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବର୍ତ୍ତମାନ ଉପଲବ୍ଧ ନାହିଁ।"</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ଉପଲବ୍ଧ ନାହିଁ"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"ବର୍ତ୍ତମାନ ଏହାକୁ ଆପଣଙ୍କ <xliff:g id="DEVICE">%1$s</xliff:g>ରେ ଆକ୍ସେସ କରାଯାଇପାରିବ ନାହିଁ। ଏହା ପରିବର୍ତ୍ତେ ଆପଣଙ୍କ Android TV ଡିଭାଇସରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"ବର୍ତ୍ତମାନ ଏହାକୁ ଆପଣଙ୍କ <xliff:g id="DEVICE">%1$s</xliff:g>ରେ ଆକ୍ସେସ କରାଯାଇପାରିବ ନାହିଁ। ଏହା ପରିବର୍ତ୍ତେ ଆପଣଙ୍କ ଟାବଲେଟରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"ବର୍ତ୍ତମାନ ଏହାକୁ ଆପଣଙ୍କ <xliff:g id="DEVICE">%1$s</xliff:g>ରେ ଆକ୍ସେସ କରାଯାଇପାରିବ ନାହିଁ। ଏହା ପରିବର୍ତ୍ତେ ଆପଣଙ୍କ ଫୋନରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ଏହି ଆପ୍କୁ Androidର ପୁରୁଣା ଭର୍ସନ୍ ପାଇଁ ନିର୍ମାଣ କରାଯାଇଥିଲା ଏବଂ ଠିକ୍ ଭାବେ କାମ କରିନପାରେ। ଏହାପାଇଁ ଅପଡେଟ୍ ଅଛି କି ନାହିଁ ଯାଞ୍ଚ କରନ୍ତୁ କିମ୍ବା ଡେଭେଲପର୍ଙ୍କ ସହିତ ସମ୍ପର୍କ କରନ୍ତୁ।"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"ଅପଡେଟ୍ ପାଇଁ ଯାଞ୍ଚ କରନ୍ତୁ"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"ଆପଣଙ୍କ ପାଖରେ ନୂଆ ମେସେଜ୍ ରହିଛି"</string>
@@ -2017,16 +2023,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ଅନଇନଷ୍ଟଲ୍ କରନ୍ତୁ"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"କୌଣସିମତେ ଖୋଲନ୍ତୁ"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"ହାନିକାରକ ଆପ୍ ଚିହ୍ନଟ ହୋଇଛି"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"ସିଷ୍ଟମ ଲଗକୁ ଆକ୍ସେସ କରିବାର ଅନୁରୋଧ"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"କେବଳ ଏହି ଥର"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"ଅନୁମତି ଦିଅନ୍ତୁ ନାହିଁ"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ଫଙ୍କସନାଲ ଡିବଗିଂ ପାଇଁ ସିଷ୍ଟମ ଲଗଗୁଡ଼ିକର ଅନୁରୋଧ କରୁଛି। ଆପଣଙ୍କ ଡିଭାଇସରେ ଥିବା ଆପ ଏବଂ ସେବାଗୁଡ଼ିକ ଲେଖିଥିବା ସୂଚନା ଏହି ଲଗଗୁଡ଼ିକରେ ଥାଇପାରେ।"</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"ପୁଣି ଦେଖାନ୍ତୁ ନାହିଁ"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g>, <xliff:g id="APP_2">%2$s</xliff:g> ସ୍ଲାଇସ୍କୁ ଦେଖାଇବା ପାଇଁ ଚାହେଁ"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"ଏଡିଟ୍ କରନ୍ତୁ"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"କଲ୍ ଓ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ଭାଇବ୍ରେଟ୍ ହେବ"</string>
@@ -2089,22 +2090,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"ପାୱାର ଡାୟଲଗ୍ ଖୋଲନ୍ତୁ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ସ୍କ୍ରିନ୍ ଲକ୍ କରନ୍ତୁ"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ସ୍କ୍ରିନ୍ସଟ୍ ନିଅନ୍ତୁ"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"ହେଡସେଟ ହୁକ"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"ଅନ୍-ସ୍କ୍ରିନ୍ ଆକ୍ସେସିବିଲିଟୀ ସର୍ଟକଟ୍"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"ଅନ୍-ସ୍କ୍ରିନ୍ ଆକ୍ସେସିବିଲିଟୀ ସର୍ଟକଟ୍ ବାଛିବା ସୁବିଧା"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"ଆକ୍ସେସିବିଲିଟୀ ସର୍ଟକଟ୍"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"ବିଜ୍ଞପ୍ତି ସେଡକୁ ଖାରଜ କରନ୍ତୁ"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Dpad ଉପର"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Dpad ତଳ"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad ବାମ"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad ଡାହାଣ"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad କେନ୍ଦ୍ର"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>ର କ୍ୟାପ୍ସନ୍ ବାର୍।"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>କୁ ପ୍ରତିବନ୍ଧିତ ବକେଟରେ ରଖାଯାଇଛି"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2120,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"ଚାଲୁ କରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"କୌଣସି ୱାର୍କ ଆପ୍ ନାହିଁ"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"କୌଣସି ବ୍ୟକ୍ତିଗତ ଆପ୍ ନାହିଁ"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"<xliff:g id="APP">%s</xliff:g>କୁ ଆପଣଙ୍କ ବ୍ୟକ୍ତିଗତ ପ୍ରୋଫାଇଲରେ ଖୋଲିବେ?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"<xliff:g id="APP">%s</xliff:g>କୁ ଆପଣଙ୍କ ୱାର୍କ ପ୍ରୋଫାଇଲରେ ଖୋଲିବେ?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"ବ୍ୟକ୍ତିଗତ ବ୍ରାଉଜର୍ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"ୱାର୍କ ବ୍ରାଉଜର୍ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM ନେଟୱାର୍କ ଅନଲକ୍ PIN"</string>
@@ -2263,4 +2256,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> ପୃଷ୍ଠପଟରେ ଚାଲୁଛି ଏବଂ ବ୍ୟାଟେରୀର ଚାର୍ଜ ସମାପ୍ତ ହେଉଛି। ସମୀକ୍ଷା କରିବାକୁ ଟାପ କରନ୍ତୁ।"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> ଦୀର୍ଘ ସମୟ ଧରି ପୃଷ୍ଠପଟରେ ଚାଲୁଛି। ସମୀକ୍ଷା କରିବାକୁ ଟାପ କରନ୍ତୁ।"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"ସକ୍ରିୟ ଆପଗୁଡ଼ିକୁ ଯାଞ୍ଚ କରନ୍ତୁ"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 636cdba..294dd3c 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"ਜਾਰੀ ਰੱਖਣ ਲਈ ਆਪਣਾ ਸਕ੍ਰੀਨ ਲਾਕ ਦਾਖਲ ਕਰੋ"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"ਅੰਸ਼ਕ ਫਿੰਗਰਪ੍ਰਿੰਟ ਦਾ ਪਤਾ ਲੱਗਿਆ"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ਫਿੰਗਰਪ੍ਰਿੰਟ \'ਤੇ ਪ੍ਰਕਿਰਿਆ ਨਹੀਂ ਹੋ ਸਕੀ। ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"ਸੈਂਸਰ ਨੂੰ ਸਾਫ਼ ਕਰੋ"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"ਸੈਂਸਰ \'ਤੇ ਉਂਗਲ ਨੂੰ ਥੋੜ੍ਹਾ ਜ਼ਿਆਦਾ ਦੇਰ ਲਈ ਰੱਖੋ"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"ਉਂਗਲ ਕਾਫ਼ੀ ਹੌਲੀ ਮੂਵ ਹੋਈ। ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"ਕੋਈ ਹੋਰ ਫਿੰਗਰਪ੍ਰਿੰਟ ਵਰਤ ਕੇ ਦੇਖੋ"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"ਬਹੁਤ ਜ਼ਿਆਦਾ ਚਮਕ"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"ਹਰ ਵਾਰ ਆਪਣੀ ਉਂਗਲ ਨੂੰ ਥੋੜ੍ਹਾ ਹਿਲਾਓ"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਪ੍ਰਮਾਣਿਤ ਹੋਇਆ"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"ਚਿਹਰਾ ਪੁਸ਼ਟੀਕਰਨ"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"ਚਿਹਰਾ ਪੁਸ਼ਟੀਕਰਨ, ਕਿਰਪਾ ਕਰਕੇ \'ਪੁਸ਼ਟੀ ਕਰੋ\' ਦਬਾਓ"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"ਛੱਡੋ"</string>
<string name="no_matches" msgid="6472699895759164599">"ਕੋਈ ਮੇਲ ਨਹੀਂ"</string>
<string name="find_on_page" msgid="5400537367077438198">"ਸਫ਼ੇ ਤੇ ਲੱਭੋ"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# ਮਿਲਾਨ{total} ਵਿੱਚੋਂ }one{#{total} ਵਿੱਚੋਂ }other{#}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"ਹੋ ਗਿਆ"</string>
<string name="progress_erasing" msgid="6891435992721028004">"ਸਾਂਝੀ ਕੀਤੀ ਸਟੋਰੇਜ ਮਿਟਾਈ ਜਾ ਰਹੀ ਹੈ…"</string>
<string name="share" msgid="4157615043345227321">"ਸਾਂਝਾ ਕਰੋ"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"ਚਾਲੂ ਕਰੋ"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ਐਪ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਐਪ ਇਸ ਵੇਲੇ ਉਪਲਬਧ ਨਹੀਂ ਹੈ।"</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"ਇਸ ਸਮੇਂ ਤੁਹਾਡੇ <xliff:g id="DEVICE">%1$s</xliff:g> \'ਤੇ ਇਸ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ। ਇਸਦੀ ਬਜਾਏ ਆਪਣੇ Android TV ਡੀਵਾਈਸ \'ਤੇ ਵਰਤ ਕੇ ਦੇਖੋ।"</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"ਇਸ ਸਮੇਂ ਤੁਹਾਡੇ <xliff:g id="DEVICE">%1$s</xliff:g> \'ਤੇ ਇਸ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ। ਇਸਦੀ ਬਜਾਏ ਆਪਣੇ ਟੈਬਲੈੱਟ \'ਤੇ ਵਰਤ ਕੇ ਦੇਖੋ।"</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"ਇਸ ਸਮੇਂ ਤੁਹਾਡੇ <xliff:g id="DEVICE">%1$s</xliff:g> \'ਤੇ ਇਸ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ। ਇਸਦੀ ਬਜਾਏ ਆਪਣੇ ਫ਼ੋਨ \'ਤੇ ਵਰਤ ਕੇ ਦੇਖੋ।"</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ਇਹ ਐਪ Android ਦੇ ਕਿਸੇ ਵਧੇਰੇ ਪੁਰਾਣੇ ਵਰਜਨ ਲਈ ਬਣਾਈ ਗਈ ਸੀ ਅਤੇ ਸ਼ਾਇਦ ਸਹੀ ਢੰਗ ਨਾਲ ਕੰਮ ਨਾ ਕਰੇ। ਅੱਪਡੇਟਾਂ ਲਈ ਜਾਂਚ ਕਰੋ ਜਾਂ ਵਿਕਾਸਕਾਰ ਨਾਲ ਸੰਪਰਕ ਕਰੋ।"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"ਅੱਪਡੇਟ ਲਈ ਜਾਂਚ ਕਰੋ"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"ਤੁਹਾਨੂੰ ਨਵੇਂ ਸੁਨੇਹੇ ਪ੍ਰਾਪਤ ਹੋਏ ਹਨ"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ਅਣਸਥਾਪਤ ਕਰੋ"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"ਫਿਰ ਵੀ ਖੋਲ੍ਹੋ"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"ਹਾਨੀਕਾਰਕ ਐਪ ਦਾ ਪਤਾ ਲੱਗਿਆ"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"ਸਿਸਟਮ ਲੌਗ ਤੱਕ ਪਹੁੰਚ ਦੀ ਬੇਨਤੀ"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"ਸਿਰਫ਼ ਇਸ ਵਾਰ"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"ਆਗਿਆ ਨਾ ਦਿਓ"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"ਕਾਰਜਾਤਮਿਕ ਡੀਬੱਗਿੰਗ ਲਈ <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ਸਿਸਟਮ ਲੌਗਾਂ ਦੀ ਬੇਨਤੀ ਕਰਦੀ ਹੈ। ਇਨ੍ਹਾਂ ਲੌਗਾਂ ਵਿੱਚ ਉਹ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਹੋ ਸਕਦੀ ਹੈ ਜੋ ਤੁਹਾਡੇ ਡੀਵਾਈਸ \'ਤੇ ਐਪਾਂ ਅਤੇ ਸੇਵਾਵਾਂ ਨੇ ਲਿਖੀ ਹੈ।"</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"ਦੁਬਾਰਾ ਨਾ ਦਿਖਾਓ"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ਦੀ <xliff:g id="APP_2">%2$s</xliff:g> ਦੇ ਹਿੱਸੇ ਦਿਖਾਉਣ ਦੀ ਇੱਛਾ ਹੈ"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"ਸੰਪਾਦਨ ਕਰੋ"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"ਕਾਲਾਂ ਅਤੇ ਸੂਚਨਾਵਾਂ ਦੀ ਥਰਥਰਾਹਟ ਹੋਵੇਗੀ"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"ਪਾਵਰ ਵਿੰਡੋ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ਲਾਕ ਸਕ੍ਰੀਨ"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"ਹੈੱਡਸੈੱਟ ਦਾ ਹੁੱਕ ਬਟਨ"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"ਸਕ੍ਰੀਨ \'ਤੇ ਦਿਸਣ ਵਾਲਾ ਪਹੁੰਚਯੋਗਤਾ ਸ਼ਾਰਟਕੱਟ"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"ਸਕ੍ਰੀਨ \'ਤੇ ਦਿਸਣ ਵਾਲੇ ਪਹੁੰਚਯੋਗਤਾ ਸ਼ਾਰਟਕੱਟ ਦਾ ਚੋਣਕਾਰ"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"ਪਹੁੰਚਯੋਗਤਾ ਸ਼ਾਰਟਕੱਟ"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"ਸੂਚਨਾ ਸ਼ੇਡ ਖਾਰਜ ਕਰੋ"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Dpad ਦਾ ਉੱਪਰਲਾ ਬਟਨ"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Dpad ਦਾ ਹੇਠਲਾ ਬਟਨ"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad ਦਾ ਖੱਬੇ ਪਾਸੇ ਵਾਲਾ ਬਟਨ"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad ਦਾ ਸੱਜੇ ਪਾਸੇ ਵਾਲਾ ਬਟਨ"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad ਦਾ ਵਿਚਕਾਰਲਾ ਬਟਨ"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਦੀ ਸੁਰਖੀ ਪੱਟੀ।"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ਨੂੰ ਪ੍ਰਤਿਬੰਧਿਤ ਖਾਨੇ ਵਿੱਚ ਪਾਇਆ ਗਿਆ ਹੈ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"ਚਾਲੂ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"ਕੋਈ ਕੰਮ ਸੰਬੰਧੀ ਐਪ ਨਹੀਂ"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"ਕੋਈ ਨਿੱਜੀ ਐਪ ਨਹੀਂ"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"ਕੀ ਆਪਣੇ ਨਿੱਜੀ ਪ੍ਰੋਫਾਈਲ ਵਿੱਚ <xliff:g id="APP">%s</xliff:g> ਨੂੰ ਖੋਲ੍ਹਣਾ ਹੈ?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"ਕੀ ਆਪਣੇ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਵਿੱਚ <xliff:g id="APP">%s</xliff:g> ਨੂੰ ਖੋਲ੍ਹਣਾ ਹੈ?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"ਨਿੱਜੀ ਬ੍ਰਾਊਜ਼ਰ ਵਰਤੋ"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"ਕੰਮ ਸੰਬੰਧੀ ਬ੍ਰਾਊਜ਼ਰ ਵਰਤੋ"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"ਸਿਮ ਨੈੱਟਵਰਕ ਅਣਲਾਕ ਪਿੰਨ"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਚੱਲ ਰਹੀ ਹੈ ਅਤੇ ਬੈਟਰੀ ਦੀ ਖਪਤ ਕਰ ਰਹੀ ਹੈ। ਸਮੀਖਿਆ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> ਲੰਮੇ ਸਮੇਂ ਤੋਂ ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਚੱਲ ਰਹੀ ਹੈ। ਸਮੀਖਿਆ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"ਕਿਰਿਆਸ਼ੀਲ ਐਪਾਂ ਦੀ ਜਾਂਚ ਕਰੋ"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index f8b3dec..a316127 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -590,8 +590,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Użyj blokady ekranu, aby kontynuować"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Wykryto częściowy odcisk palca"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Nie udało się przetworzyć odcisku palca. Spróbuj ponownie."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Wyczyść czytnik"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Przytrzymaj trochę dłużej"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Palec został obrócony zbyt wolno. Spróbuj ponownie."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Użyj odcisku innego palca"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Zbyt jasno"</string>
@@ -599,6 +603,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Za każdym razem lekko zmieniaj ułożenie palca"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Uwierzytelniono odciskiem palca"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Twarz rozpoznana"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Twarz rozpoznana, kliknij Potwierdź"</string>
@@ -1502,7 +1510,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Pomiń"</string>
<string name="no_matches" msgid="6472699895759164599">"Brak wyników"</string>
<string name="find_on_page" msgid="5400537367077438198">"Znajdź na stronie"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# odpowiednik}few{# z {total}}many{# z {total}}other{# z {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Gotowe"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Kasuję dane z pamięci współdzielonej…"</string>
<string name="share" msgid="4157615043345227321">"Udostępnij"</string>
@@ -1930,6 +1939,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Włącz"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacja jest niedostępna"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> jest obecnie niedostępna."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> – brak dostępu"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"W tej chwili nie można z tego skorzystać na urządzeniu <xliff:g id="DEVICE">%1$s</xliff:g>. Użyj urządzenia z Androidem TV."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"W tej chwili nie można z tego skorzystać na urządzeniu <xliff:g id="DEVICE">%1$s</xliff:g>. Użyj tabletu."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"W tej chwili nie można z tego skorzystać na urządzeniu <xliff:g id="DEVICE">%1$s</xliff:g>. Użyj telefonu."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ta aplikacja jest na starszą wersję Androida i może nie działać prawidłowo. Sprawdź dostępność aktualizacji lub skontaktuj się z programistą."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Sprawdź dostępność aktualizacji"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Masz nowe wiadomości"</string>
@@ -2019,16 +2032,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ODINSTALUJ"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"OTWÓRZ MIMO TO"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Wykryto szkodliwą aplikację"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Prośba o dostęp do dziennika systemowego"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Tylko tym razem"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nie zezwalaj"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"Aplikacja <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> prosi o dzienniki systemowe do funkcjonalnego debugowania. Te dzienniki mogą zawierać informacje zapisane Twoim urządzeniu przez aplikacje i usługi."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Nie pokazuj ponownie"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Aplikacja <xliff:g id="APP_0">%1$s</xliff:g> chce pokazywać wycinki z aplikacji <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Edytuj"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Wibracje przy połączeniach i powiadomieniach"</string>
@@ -2091,22 +2099,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Okno opcji zasilania"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ekran blokady"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Zrzut ekranu"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Punkt zaczepienia zestawu słuchawkowego"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Ekranowy skrót ułatwień dostępu"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Wybierz ekranowy skrót ułatwień dostępu"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Skrót ułatwień dostępu"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Zamknij obszar powiadomień"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Dpad – w górę"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Dpad – w dół"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad – w lewo"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad – w prawo"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad – środek"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Pasek napisów w aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Umieszczono pakiet <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> w zasobniku danych RESTRICTED"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2127,10 +2129,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Kliknij, aby włączyć"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Brak aplikacji służbowych"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Brak aplikacji osobistych"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Otworzyć aplikację <xliff:g id="APP">%s</xliff:g> w profilu osobistym?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Otworzyć aplikację <xliff:g id="APP">%s</xliff:g> w profilu służbowym?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Użyj przeglądarki osobistej"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Użyj przeglądarki służbowej"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"Kod PIN do karty SIM odblokowujący sieć"</string>
@@ -2265,4 +2265,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"Aplikacja <xliff:g id="APP">%1$s</xliff:g> działa w tle i zużywa baterię. Kliknij, aby sprawdzić."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"Aplikacja <xliff:g id="APP">%1$s</xliff:g> długo działa w tle. Kliknij, aby sprawdzić."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Sprawdź aktywne aplikacje"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index f867ea9..fd01b22 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Insira seu bloqueio de tela para continuar"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Impressão digital parcial detectada"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Não foi possível processar a impressão digital. Tente novamente."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Limpe o sensor"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Mantenha o dedo por mais tempo"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"O movimento do dedo está muito lento. Tente novamente."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Use outra impressão digital"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Claro demais"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Mude a posição do dedo ligeiramente a cada momento"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Impressão digital autenticada"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Rosto autenticado"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Rosto autenticado, pressione \"Confirmar\""</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Pular"</string>
<string name="no_matches" msgid="6472699895759164599">"Não encontrado"</string>
<string name="find_on_page" msgid="5400537367077438198">"Localizar na página"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# corresponde a }one{# de {total}}other{# de {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Concluído"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Limpando armazenamento compartilhado…"</string>
<string name="share" msgid="4157615043345227321">"Compartilhar"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Ativar"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"O app não está disponível"</string>
<string name="app_blocked_message" msgid="542972921087873023">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não está disponível no momento."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> indisponível"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"No momento, não é possível acessar esse app pelo <xliff:g id="DEVICE">%1$s</xliff:g>. Tente pelo dispositivo Android TV."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"No momento, não é possível acessar esse app pelo <xliff:g id="DEVICE">%1$s</xliff:g>. Tente pelo seu tablet."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"No momento, não é possível acessar esse app pelo <xliff:g id="DEVICE">%1$s</xliff:g>. Tente pelo seu smartphone."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Este app foi criado para uma versão mais antiga do Android e pode não funcionar corretamente. Tente verificar se há atualizações ou entre em contato com o desenvolvedor."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Procurar atualizações"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Você tem mensagens novas"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"DESINSTALAR"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"ABRIR MESMO ASSIM"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"App nocivo detectado"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Solicitação de acesso ao registro do sistema"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Apenas esta vez"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Não permitir"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"O app <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> solicita registros do sistema para fazer uma depuração funcional. Esses registros podem conter informações que apps e serviços do dispositivo escreveram."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Não mostrar novamente"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> quer mostrar partes do app <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Editar"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Chamadas e notificações farão o dispositivo vibrar"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Caixa de diálogo de liga/desliga"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Bloquear tela"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Capturar tela"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Gancho do fone de ouvido"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Atalho de acessibilidade na tela"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Seletor de atalho de acessibilidade na tela"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Atalho de acessibilidade"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Dispensar aba de notificações"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Botão direcional: para cima"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Botão direcional: para baixo"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Botão direcional: para a esquerda"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Botão direcional: para a direita"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Botão direcional: centro"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de legendas do app <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no intervalo \"RESTRITO\""</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Toque para ativar"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Nenhum app de trabalho"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Nenhum app pessoal"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Abrir o app <xliff:g id="APP">%s</xliff:g> no seu perfil pessoal?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Abrir o app <xliff:g id="APP">%s</xliff:g> no seu perfil de trabalho?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Usar o navegador pessoal"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Usar o navegador de trabalho"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"PIN para desbloqueio da rede do chip"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> está sendo executado em segundo plano e drenando a energia da bateria. Toque para revisar."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> está sendo executado em segundo plano faz muito tempo. Toque para revisar."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Verificar apps ativos"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 13da16e..aa8571b 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Introduza o bloqueio de ecrã para continuar"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Impressão digital parcial detetada"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Não foi possível processar a impressão digital. Tente novamente."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Limpe o sensor"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Mantenha o dedo encostado durante mais algum tempo"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Moveu o dedo demasiado lentamente. Tente novamente."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Experimente outra impressão digital"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Está demasiado claro"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Altere a posição do seu dedo ligeiramente de cada vez"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"A impressão digital foi autenticada."</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Rosto autenticado."</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Rosto autenticado. Prima Confirmar."</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Ignorar"</string>
<string name="no_matches" msgid="6472699895759164599">"Sem correspondências"</string>
<string name="find_on_page" msgid="5400537367077438198">"Localizar na página"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# correspondência}one{# de {total}}other{# de {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Concluído"</string>
<string name="progress_erasing" msgid="6891435992721028004">"A apagar o armazenamento partilhado…"</string>
<string name="share" msgid="4157615043345227321">"Partilhar"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Ativar"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"A app não está disponível"</string>
<string name="app_blocked_message" msgid="542972921087873023">"De momento, a app <xliff:g id="APP_NAME">%1$s</xliff:g> não está disponível."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> indisponível"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"De momento, não é possível aceder a esta app no seu <xliff:g id="DEVICE">%1$s</xliff:g>. Em alternativa, experimente no dispositivo Android TV."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"De momento, não é possível aceder a esta app no seu <xliff:g id="DEVICE">%1$s</xliff:g>. Em alternativa, experimente no tablet."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"De momento, não é possível aceder a esta app no seu <xliff:g id="DEVICE">%1$s</xliff:g>. Em alternativa, experimente no telemóvel."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Esta app foi concebida para uma versão mais antiga do Android e pode não funcionar corretamente. Experimente verificar se existem atualizações ou contacte o programador."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Verificar atualizações"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Tem mensagens novas"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"DESINSTALAR"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"ABRIR MESMO ASSIM"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Aplicação prejudicial detetada"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Pedido de acesso ao registo do sistema"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Apenas desta vez"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Não permitir"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"A app <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> solicita registos do sistema para depuração funcional. Estes registos podem conter informações escritas por apps e serviços no seu dispositivo."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Não mostrar de novo"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"A app <xliff:g id="APP_0">%1$s</xliff:g> pretende mostrar partes da app <xliff:g id="APP_2">%2$s</xliff:g>."</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Editar"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"As chamadas e as notificações vibram."</string>
@@ -2119,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Tocar para ativar"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Sem apps de trabalho"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Sem apps pessoais"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Abrir a app <xliff:g id="APP">%s</xliff:g> no seu perfil pessoal?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Abrir a app <xliff:g id="APP">%s</xliff:g> no seu perfil de trabalho?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Utilizar navegador pessoal"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Utilizar navegador de trabalho"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"PIN para desbloqueio de rede do cartão SIM"</string>
@@ -2257,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"A app <xliff:g id="APP">%1$s</xliff:g> está a ser executada em segundo plano e a consumir rapidamente a bateria Toque para analisar."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"A app <xliff:g id="APP">%1$s</xliff:g> está a ser executada em segundo plano há muito tempo. Toque para analisar."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Verificar apps ativas"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index f867ea9..fd01b22 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Insira seu bloqueio de tela para continuar"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Impressão digital parcial detectada"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Não foi possível processar a impressão digital. Tente novamente."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Limpe o sensor"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Mantenha o dedo por mais tempo"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"O movimento do dedo está muito lento. Tente novamente."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Use outra impressão digital"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Claro demais"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Mude a posição do dedo ligeiramente a cada momento"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Impressão digital autenticada"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Rosto autenticado"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Rosto autenticado, pressione \"Confirmar\""</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Pular"</string>
<string name="no_matches" msgid="6472699895759164599">"Não encontrado"</string>
<string name="find_on_page" msgid="5400537367077438198">"Localizar na página"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# corresponde a }one{# de {total}}other{# de {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Concluído"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Limpando armazenamento compartilhado…"</string>
<string name="share" msgid="4157615043345227321">"Compartilhar"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Ativar"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"O app não está disponível"</string>
<string name="app_blocked_message" msgid="542972921087873023">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não está disponível no momento."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> indisponível"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"No momento, não é possível acessar esse app pelo <xliff:g id="DEVICE">%1$s</xliff:g>. Tente pelo dispositivo Android TV."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"No momento, não é possível acessar esse app pelo <xliff:g id="DEVICE">%1$s</xliff:g>. Tente pelo seu tablet."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"No momento, não é possível acessar esse app pelo <xliff:g id="DEVICE">%1$s</xliff:g>. Tente pelo seu smartphone."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Este app foi criado para uma versão mais antiga do Android e pode não funcionar corretamente. Tente verificar se há atualizações ou entre em contato com o desenvolvedor."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Procurar atualizações"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Você tem mensagens novas"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"DESINSTALAR"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"ABRIR MESMO ASSIM"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"App nocivo detectado"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Solicitação de acesso ao registro do sistema"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Apenas esta vez"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Não permitir"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"O app <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> solicita registros do sistema para fazer uma depuração funcional. Esses registros podem conter informações que apps e serviços do dispositivo escreveram."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Não mostrar novamente"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> quer mostrar partes do app <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Editar"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Chamadas e notificações farão o dispositivo vibrar"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Caixa de diálogo de liga/desliga"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Bloquear tela"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Capturar tela"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Gancho do fone de ouvido"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Atalho de acessibilidade na tela"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Seletor de atalho de acessibilidade na tela"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Atalho de acessibilidade"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Dispensar aba de notificações"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Botão direcional: para cima"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Botão direcional: para baixo"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Botão direcional: para a esquerda"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Botão direcional: para a direita"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Botão direcional: centro"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de legendas do app <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no intervalo \"RESTRITO\""</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Toque para ativar"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Nenhum app de trabalho"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Nenhum app pessoal"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Abrir o app <xliff:g id="APP">%s</xliff:g> no seu perfil pessoal?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Abrir o app <xliff:g id="APP">%s</xliff:g> no seu perfil de trabalho?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Usar o navegador pessoal"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Usar o navegador de trabalho"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"PIN para desbloqueio da rede do chip"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> está sendo executado em segundo plano e drenando a energia da bateria. Toque para revisar."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> está sendo executado em segundo plano faz muito tempo. Toque para revisar."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Verificar apps ativos"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 9471cb2..fab2656 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -305,10 +305,8 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"acceseze calendarul"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"trimită și să vadă mesajele SMS"</string>
- <!-- no translation found for permgrouplab_storage (9173334109512154196) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (8352226729501080525) -->
- <skip />
+ <string name="permgrouplab_storage" msgid="9173334109512154196">"Fișiere și documente"</string>
+ <string name="permgroupdesc_storage" msgid="8352226729501080525">"să acceseze fișiere și documente de pe dispozitiv"</string>
<string name="permgrouplab_readMediaAural" msgid="5885210465560755316">"Muzică și alt conținut audio"</string>
<string name="permgroupdesc_readMediaAural" msgid="1170143315714662822">"să acceseze fișiere audio de pe dispozitiv"</string>
<string name="permgrouplab_readMediaVisual" msgid="9137695801926624061">"Fotografii și videoclipuri"</string>
@@ -589,8 +587,9 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Introduceți blocarea ecranului ca să continuați"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"S-a detectat o amprentă parțială"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Amprenta nu a putut fi procesată. Încercați din nou."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Curățați senzorul"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Țineți degetul apăsat puțin mai mult"</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Curățați senzorul de amprentă și încercați din nou"</string>
+ <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Curățați senzorul și încercați din nou"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Apăsați ferm pe senzor"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Ați mișcat degetul prea lent. Încercați din nou."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Încercați altă amprentă"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Prea luminos"</string>
@@ -598,6 +597,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Schimbați ușor poziția degetului de fiecare dată"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"Amprenta nu a fost recunoscută"</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="4709197752023550709">"Apăsați ferm pe senzor"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Amprentă autentificată"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Chip autentificat"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Chip autentificat, apăsați Confirmați"</string>
@@ -1501,7 +1502,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Omiteți"</string>
<string name="no_matches" msgid="6472699895759164599">"Nicio potrivire"</string>
<string name="find_on_page" msgid="5400537367077438198">"Găsiți pe pagină"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# potrivire}few{# din {total}}other{# din {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Terminat"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Se șterge spațiul de stocare distribuit..."</string>
<string name="share" msgid="4157615043345227321">"Distribuiți"</string>
@@ -1929,6 +1931,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activați"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplicația nu este disponibilă"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> nu este disponibilă momentan."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nu este disponibilă"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Aplicația nu poate fi accesată pe <xliff:g id="DEVICE">%1$s</xliff:g> momentan. Încercați pe dispozitivul Android TV."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Aplicația nu poate fi accesată pe <xliff:g id="DEVICE">%1$s</xliff:g> momentan. Încercați pe tabletă."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Aplicația nu poate fi accesată pe <xliff:g id="DEVICE">%1$s</xliff:g> momentan. Încercați pe telefon."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Această aplicație a fost creată pentru o versiune Android mai veche și este posibil să nu funcționeze corect. Încercați să căutați actualizări sau contactați dezvoltatorul."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Căutați actualizări"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Aveți mesaje noi"</string>
@@ -2018,16 +2024,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"DEZINSTALAȚI"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"Deschideți oricum"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Aplicație dăunătoare detectată"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Solicitare de acces la jurnale de sistem"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Doar de data aceasta"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nu permiteți"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> solicită jurnale de sistem pentru remedierea erorilor de funcționare. Aceste jurnale pot conține informații scrise de aplicațiile și serviciile de pe dispozitiv."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Nu mai afișa"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> vrea să afișeze porțiuni din <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Editați"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Apelurile și notificările vor vibra"</string>
@@ -2090,22 +2091,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Power Dialog"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ecran de blocare"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captură de ecran"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Hook pentru setul de căști-microfon"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Comandă rapidă de accesibilitate de pe ecran"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Selector de comenzi rapide de accesibilitate de pe ecran"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Comandă rapidă de accesibilitate"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Închideți fereastra de notificări"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Dpad sus"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Dpad jos"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad stânga"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad dreapta"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad centru"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Bară cu legenda pentru <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a fost adăugat la grupul RESTRICȚIONATE"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2126,10 +2121,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Atingeți pentru a activa"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Nicio aplicație pentru lucru"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Nicio aplicație personală"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Deschideți <xliff:g id="APP">%s</xliff:g> în profilul personal?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Deschideți <xliff:g id="APP">%s</xliff:g> în profilul de serviciu?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Folosiți browserul personal"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Folosiți browserul de serviciu"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"Codul PIN de deblocare SIM privind rețeaua"</string>
@@ -2264,4 +2257,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> rulează în fundal și consumă bateria. Atingeți pentru a examina."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> rulează în fundal mult timp. Atingeți pentru a examina."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Verificați aplicațiile active"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index aaf2bc9..0ba7cb0 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -590,8 +590,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Чтобы продолжить, разблокируйте экран."</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Отсканирована только часть отпечатка."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Не удалось распознать отпечаток. Повторите попытку."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Очистите сканер."</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Вы слишком быстро убираете палец со сканера."</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Вы перемещали палец слишком медленно. Повторите попытку."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Попробуйте сохранить отпечаток другого пальца."</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Слишком светло."</string>
@@ -599,6 +603,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Каждый раз немного меняйте положение пальца."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Отпечаток пальца проверен"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Лицо распознано"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Лицо распознано, нажмите кнопку \"Подтвердить\""</string>
@@ -1502,7 +1510,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Пропустить"</string>
<string name="no_matches" msgid="6472699895759164599">"Нет совпадений"</string>
<string name="find_on_page" msgid="5400537367077438198">"Найти на странице"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# совпадение}one{# из {total}}few{# из {total}}many{# из {total}}other{# из {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Готово"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Очистка единого хранилища…"</string>
<string name="share" msgid="4157615043345227321">"Поделиться"</string>
@@ -1930,6 +1939,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Включить"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Приложение недоступно"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" сейчас недоступно."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"Недоступно: <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Эта функция пока недоступна на устройстве <xliff:g id="DEVICE">%1$s</xliff:g>. Используйте Android TV."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Эта функция пока недоступна на устройстве <xliff:g id="DEVICE">%1$s</xliff:g>. Используйте планшет."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Эта функция пока недоступна на устройстве <xliff:g id="DEVICE">%1$s</xliff:g>. Используйте телефон."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Это приложение было создано для более ранней версии Android и может работать со сбоями. Проверьте наличие обновлений или свяжитесь с разработчиком."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Проверить обновления"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Новые сообщения"</string>
@@ -2019,16 +2032,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"УДАЛИТЬ"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"ОТКРЫТЬ"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Обнаружено вредоносное приложение"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Запрос на доступ к системным журналам"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Только в этот раз"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Запретить"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> запрашивает доступ к системным журналам для отладки функций. В этих журналах может содержаться информация, записанная приложениями и сервисами на вашем устройстве."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Больше не показывать"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Приложение \"<xliff:g id="APP_0">%1$s</xliff:g>\" запрашивает разрешение на показ фрагментов приложения \"<xliff:g id="APP_2">%2$s</xliff:g>\"."</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Изменить"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Для звонков и уведомлений включен вибросигнал."</string>
@@ -2091,22 +2099,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Диалоговое окно питания"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заблокированный экран"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Скриншот"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Повесить гарнитуру"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Действие для быстрого включения"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Выбор действия для быстрого включения"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Быстрое включение"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Скрыть панель уведомлений"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"D-pad – вверх"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"D-pad – вниз"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"D-pad – влево"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"D-pad – вправо"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"D-pad – по центру"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Строка субтитров в приложении \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Приложение \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" помещено в категорию с ограниченным доступом."</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2127,10 +2129,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Нажмите, чтобы включить"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Не поддерживается рабочими приложениями."</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Не поддерживается личными приложениями."</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Открыть приложение \"<xliff:g id="APP">%s</xliff:g>\" в личном профиле?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Открыть приложение \"<xliff:g id="APP">%s</xliff:g>\" в рабочем профиле?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Использовать личный браузер"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Использовать рабочий браузер"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"PIN-код для разблокировки сети SIM-карты"</string>
@@ -2265,4 +2265,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"Приложение \"<xliff:g id="APP">%1$s</xliff:g>\" работает в фоновом режиме и расходует заряд батареи. Нажмите, чтобы узнать подробности."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"Приложение \"<xliff:g id="APP">%1$s</xliff:g>\" работает в фоновом режиме уже длительное время. Нажмите, чтобы узнать подробности."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Проверить активные приложения"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 1404bb0..2c9950c 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"ඉදිරියට යාමට ඔබගේ තිර අගුල ඇතුළත් කරන්න"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"අර්ධ ඇඟිලි සලකුණක් අනාවරණය කරන ලදි"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ඇඟිලි සලකුණ පිරිසැකසීමට නොහැකි විය. කරුණාකර නැවත උත්සාහ කරන්න."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"සංවේදකය පිරිසිදු කරන්න"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"තව ටිකක් වැඩිපුර අල්ලාගෙන සිටින්න"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"ඇඟිල්ල වඩා සෙමෙන් ගෙන යන ලදි. කරුණාකර නැවත උත්සාහ කරන්න."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"තවත් ඇඟිලි සලකුණක් උත්සාහ කරන්න"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"දීප්තිය වැඩියි"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"එක් එක් අවස්ථාවේ ඔබගේ ඇඟිල්ලේ පිහිටීම මදක් වෙනස් කරන්න"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ඇඟිලි සලකුණ සත්යාපනය කරන ලදී"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"මුහුණ සත්යාපනය කරන ලදී"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"මුහුණ සත්යාපනය කරන ලදී, කරුණාකර තහවුරු කරන්න ඔබන්න"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"මඟ හරින්න"</string>
<string name="no_matches" msgid="6472699895759164599">"ගැලපීම් නැත"</string>
<string name="find_on_page" msgid="5400537367077438198">"පිටුවෙහි සෙවීම"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# තරඟ {total}}one{# {total}}other{# }} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"හරි"</string>
<string name="progress_erasing" msgid="6891435992721028004">"බෙදා ගත් ගබඩාව මකා දමමින්…"</string>
<string name="share" msgid="4157615043345227321">"බෙදාගන්න"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"ක්රියාත්මක කරන්න"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"යෙදුම ලබා ගත නොහැකිය"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> මේ දැන් ලබා ගත නොහැකිය."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> නොතිබේ"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"මේ අවස්ථාවේදී මෙයට ඔබගේ <xliff:g id="DEVICE">%1$s</xliff:g> හි ප්රවේශ විය නොහැකිය. ඒ වෙනුවට ඔබගේ Android TV උපාංගයෙහි උත්සාහ කරන්න."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"මේ අවස්ථාවේදී මෙයට ඔබගේ <xliff:g id="DEVICE">%1$s</xliff:g> හි ප්රවේශ විය නොහැකිය. ඒ වෙනුවට ඔබගේ ටැබ්ලටයෙහි උත්සාහ කරන්න."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"මේ අවස්ථාවේදී මෙයට ඔබගේ <xliff:g id="DEVICE">%1$s</xliff:g> හි ප්රවේශ විය නොහැකිය. ඒ වෙනුවට ඔබගේ දුරකථනයෙහි උත්සාහ කරන්න."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"මෙම යෙදුම Android හි පැරණි අනුවාදයක් සඳහා තනා ඇති අතර නිසියාකාරව ක්රියා නොකරනු ඇත. යාවත්කාලීන සඳහා පරික්ෂා කිරීම උත්සාහ කරන්න, නැතහොත් සංවර්ධක අමතන්න."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"යාවත්කාලීන සඳහා පරික්ෂා කරන්න"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"ඔබට නව පණිවිඩ තිබේ"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"අස්ථාපනය කරන්න"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"කෙසේ වුවත් විවෘත කරන්න"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"හානිකර යෙදුමක් අනාවරණය කර ගන්නා ලදී"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"පද්ධති ලොග ප්රවේශ ඉල්ලීම"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"මෙම වතාවේ පමණි"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"ඉඩ නොදෙන්න"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ක්රියාකාරී නිදොස් කිරීම සඳහා පද්ධති ලොග ඉල්ලයි. මෙම ලොගවල ඔබගේ උපාංගයේ යෙදුම් සහ සේවා ලියා ඇති තොරතුරු අඩංගු විය හැකිය."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"නැවත නොපෙන්වන්න"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> හට කොටස් <xliff:g id="APP_2">%2$s</xliff:g>ක් පෙන්වීමට අවශ්යයි"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"සංස්කරණය"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"ඇමතුම් සහ දැනුම්දීම් කම්පනය වනු ඇත"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"බල සංවාදය"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"අගුලු තිරය"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"තිර රුව"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"හෙඩ්සෙට් කොක්ක"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"තිරය මත ප්රවේශ්යතා කෙටිමග"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"තිරය මත ප්රවේශ්යතා කෙටිමං තෝරනය"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"ප්රවේශ්යතා කෙටිමඟ"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"දැනුම්දීම් සෙවන ඉවත ලන්න"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Dpad ඉහළ"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Dpad පහළ"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad වම"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad දකුණ"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad මැද"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> හි සිරස්තල තීරුව."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> අවහිර කළ බාල්දියට දමා ඇත"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"ක්රියාත්මක කිරීමට තට්ටු කරන්න"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"කාර්යාල යෙදුම් නැත"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"පුද්ගලික යෙදුම් නැත"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"<xliff:g id="APP">%s</xliff:g> ඔබගේ පුද්ගලික පැතිකඩ තුළ විවෘත කරන්නද?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"<xliff:g id="APP">%s</xliff:g> ඔබගේ කාර්යාල පැතිකඩ තුළ විවෘත කරන්නද?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"පුද්ගලික බ්රව්සරය භාවිත කරන්න"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"කාර්යාල බ්රව්සරය භාවිත කරන්න"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM ජාල අගුලු හැරීමේ PIN"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> පසුබිමේ ධාවනය වන අතර බැටරිය බැස යයි. සමාලෝචනය කිරීමට තට්ටු කරන්න."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> දිගු වේලාවක් පසුබිමේ ධාවනය වේ. සමාලෝචනය කිරීමට තට්ටු කරන්න."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"සක්රිය යෙදුම් පරීක්ෂා කරන්න"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index c8d965d..ce70e5f 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -306,10 +306,8 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"prístup ku kalendáru"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"posielanie a zobrazovanie SMS"</string>
- <!-- no translation found for permgrouplab_storage (9173334109512154196) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (8352226729501080525) -->
- <skip />
+ <string name="permgrouplab_storage" msgid="9173334109512154196">"Súbory a dokumenty"</string>
+ <string name="permgroupdesc_storage" msgid="8352226729501080525">"prístup k súborom a dokumentom vo vašom zariadení"</string>
<string name="permgrouplab_readMediaAural" msgid="5885210465560755316">"Hudba a iné zvuky"</string>
<string name="permgroupdesc_readMediaAural" msgid="1170143315714662822">"prístup k zvukovým súborom vo vašom zariadení"</string>
<string name="permgrouplab_readMediaVisual" msgid="9137695801926624061">"Fotky a videá"</string>
@@ -590,8 +588,9 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Pokračujte zadaním zámky obrazovky"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Bol rozpoznaný čiastočný odtlačok prsta"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Odtlačok prsta sa nepodarilo spracovať. Skúste to znova."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Vyčistite senzor"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Podržte trochu dlhšie"</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Vyčistite senzor odtlačkov prstov a skúste to znova"</string>
+ <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Vyčistite senzor a skúste to znova"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Pevne pridržte senzor"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Pohli ste prstom príliš pomaly. Skúste to znova."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Vyskúšajte iný odtlačok prsta"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Príliš jasno"</string>
@@ -599,6 +598,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Zakaždým trocha zmeňte pozíciu prsta"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"Odtlačok prsta nebol rozpoznaný"</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="4709197752023550709">"Pevne pridržte senzor"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Odtlačok prsta bol overený"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Tvár bola overená"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Tvár bola overená, stlačte tlačidlo potvrdenia"</string>
@@ -1502,7 +1503,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Preskočiť"</string>
<string name="no_matches" msgid="6472699895759164599">"Žiadne zhody"</string>
<string name="find_on_page" msgid="5400537367077438198">"Vyhľadať na stránke"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# zhoda }few{# z {total}}many{# z {total}}other{# z {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Hotovo"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Vymazáva sa zdieľané úložisko…"</string>
<string name="share" msgid="4157615043345227321">"Zdieľať"</string>
@@ -1930,6 +1932,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Zapnúť"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikácia nie je dostupná"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> nie je teraz dostupná."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nie je k dispozícii"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"V zariadení <xliff:g id="DEVICE">%1$s</xliff:g> momentálne nemáte k tomuto obsahu prístup. Skúste namiesto toho použiť zariadenie Android TV."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"V zariadení <xliff:g id="DEVICE">%1$s</xliff:g> momentálne nemáte k tomuto obsahu prístup. Skúste namiesto toho použiť tablet."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"V zariadení <xliff:g id="DEVICE">%1$s</xliff:g> momentálne nemáte k tomuto obsahu prístup. Skúste namiesto toho použiť telefón."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Táto aplikácia bola zostavená pre staršiu verziu Androidu a nemusí správne fungovať. Skúste skontrolovať dostupnosť aktualizácií alebo kontaktovať vývojára."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Skontrolovať dostupnosť aktualizácie"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Máte nové správy."</string>
@@ -2019,16 +2025,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ODINŠTALOVAŤ"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"OTVORIŤ AJ TAK"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Bola zistená škodlivá aplikácia"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Žiadosť o prístup k denníku systému"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Iba tentokrát"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nepovoliť"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> žiada o denníky systému na účely funkčného ladenia. Môžu obsahovať informácie zapísané aplikáciami a službami vo vašom zariadení."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Už nezobrazovať"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> chce zobrazovať rezy z aplikácie <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Upraviť"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Hovory a upozornenia budú vibrovať"</string>
@@ -2091,22 +2092,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialógové okno napájania"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Uzamknúť obrazovku"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snímka obrazovky"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Hák na slúchadlá s mikrofónom"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Skratka dostupnosti na obrazovke"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Výber skratky dostupnosti na obrazovke"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Skratka dostupnosti"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Zavrieť panel upozornení"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Stlačiť tlačidlo nahor krížového ovládača"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Stlačiť tlačidlo nadol krížového ovládača"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Stlačiť tlačidlo doľava krížového ovládača"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Stlačiť tlačidlo doprava krížového ovládača"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Stlačiť stredné tlačidlo krížového ovládača"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Popis aplikácie <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Balík <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> bol vložený do kontajnera OBMEDZENÉ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2127,10 +2122,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Zapnúť klepnutím"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Žiadne pracovné aplikácie"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Žiadne osobné aplikácie"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Chcete otvoriť <xliff:g id="APP">%s</xliff:g> v osobnom profile?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Chcete otvoriť <xliff:g id="APP">%s</xliff:g> v pracovnom profile?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Použiť osobný prehliadač"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Použiť pracovný prehliadač"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"PIN na odomknutie siete pre SIM kartu"</string>
@@ -2265,4 +2258,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"Aplikácie <xliff:g id="APP">%1$s</xliff:g> je spustená na pozadí a vybíja batériu. Skontrolujte to klepnutím."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"Aplikácia <xliff:g id="APP">%1$s</xliff:g> je dlhodobo spustená na pozadí. Skontrolujte to klepnutím."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Skontrolovať aktívne aplikácie"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 9a3a7f1..e23cf85 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -306,10 +306,8 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"dostop do koledarja"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"pošiljanje in ogled sporočil SMS"</string>
- <!-- no translation found for permgrouplab_storage (9173334109512154196) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (8352226729501080525) -->
- <skip />
+ <string name="permgrouplab_storage" msgid="9173334109512154196">"Datoteke in dokumenti"</string>
+ <string name="permgroupdesc_storage" msgid="8352226729501080525">"dostop do datotek in dokumentov v napravi"</string>
<string name="permgrouplab_readMediaAural" msgid="5885210465560755316">"Glasba in drugi zvočni posnetki"</string>
<string name="permgroupdesc_readMediaAural" msgid="1170143315714662822">"dostop do zvočnih datotek v napravi"</string>
<string name="permgrouplab_readMediaVisual" msgid="9137695801926624061">"Fotografije in videoposnetki"</string>
@@ -590,8 +588,9 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Odklenite zaslon, če želite nadaljevati."</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Zaznan je delni prstni odtis."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Prstnega odtisa ni bilo mogoče obdelati. Poskusite znova."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Očistite tipalo."</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Pridržite malo dlje."</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Očistite tipalo prstnih odtisov in poskusite znova."</string>
+ <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Očistite tipalo in poskusite znova."</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Prst dobro pridržite na tipalu."</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Prepočasen premik prsta. Poskusite znova."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Poskusite z drugim prstnim odtisom."</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Presvetlo je."</string>
@@ -599,6 +598,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Vsakič nekoliko spremenite položaj prsta."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"Prstni odtis ni prepoznan."</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="4709197752023550709">"Prst dobro pridržite na tipalu."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Pristnost prstnega odtisa je preverjena"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Pristnost obraza je potrjena"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Pristnost obraza je preverjena. Pritisnite gumb »Potrdi«."</string>
@@ -1502,7 +1503,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Preskoči"</string>
<string name="no_matches" msgid="6472699895759164599">"Ni ujemanj"</string>
<string name="find_on_page" msgid="5400537367077438198">"Najdi na strani"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# ujemanje}one{# od {total}}two{# od {total}}few{# od {total}}other{# od {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Končano"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Brisanje skupne shrambe …"</string>
<string name="share" msgid="4157615043345227321">"Deli"</string>
@@ -1930,6 +1932,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Vklopi"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija ni na voljo"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutno ni na voljo."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"»<xliff:g id="ACTIVITY">%1$s</xliff:g>« ni na voljo"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"V napravi <xliff:g id="DEVICE">%1$s</xliff:g> trenutno ni mogoče dostopati do te vsebine. Poskusite z napravo Android TV."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"V napravi <xliff:g id="DEVICE">%1$s</xliff:g> trenutno ni mogoče dostopati do te vsebine. Poskusite s tabličnim računalnikom."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"V napravi <xliff:g id="DEVICE">%1$s</xliff:g> trenutno ni mogoče dostopati do te vsebine. Poskusite s telefonom."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ta aplikacija je bila zasnovana za starejšo različico Androida in morda ne bo delovala pravilno. Preverite, ali so na voljo posodobitve, ali pa se obrnite na razvijalca."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Preveri, ali je na voljo posodobitev"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Imate nova sporočila."</string>
@@ -2019,16 +2025,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ODMESTI"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"VSEENO ODPRI"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Zaznana je bila škodljiva aplikacija"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Zahteva za dostop do sistemskega dnevnika"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Samo tokrat"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ne dovoli"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> zahteva sistemske dnevnike za funkcionalno odpravljanje napak. Ti dnevniki lahko vsebujejo podatke, ki so jih zapisale aplikacije in storitve v vaši napravi."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne prikaži več"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Aplikacija <xliff:g id="APP_0">%1$s</xliff:g> želi prikazati izreze aplikacije <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Uredi"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Vibriranje bo vklopljeno za klice in obvestila"</string>
@@ -2121,10 +2122,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Dotaknite se za vklop"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Nobena delovna aplikacija ni na voljo"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Nobena osebna aplikacija"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Želite aplikacijo <xliff:g id="APP">%s</xliff:g> odpreti v osebnem profilu?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Želite aplikacijo <xliff:g id="APP">%s</xliff:g> odpreti v delovnem profilu?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Uporabi osebni brskalnik"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Uporabi delovni brskalnik"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"Koda PIN za odklepanje omrežja kartice SIM"</string>
@@ -2259,4 +2258,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> se izvaja v ozadju in porablja energijo baterije. Dotaknite se za pregled."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> se dolgo časa izvaja v ozadju. Dotaknite se za pregled."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Preverite aktivne aplikacije"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 855e93a..ec07f41 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Fut kyçjen e ekranit për të vazhduar"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"U zbulua gjurmë gishti e pjesshme"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Gjurma e gishtit nuk mund të përpunohej. Provo përsëri."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Pastro sensorin"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Mbaje dhe pak"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Gishti lëvizi shumë ngadalë. Provo përsëri."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Provo një gjurmë gishti tjetër"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Me shumë ndriçim"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Ndrysho pak pozicionin e gishtit çdo herë"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Gjurma e gishtit u vërtetua"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Fytyra u vërtetua"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Fytyra u vërtetua, shtyp \"Konfirmo\""</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Kapërce"</string>
<string name="no_matches" msgid="6472699895759164599">"Asnjë përputhje"</string>
<string name="find_on_page" msgid="5400537367077438198">"Gjej brenda faqes"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# përputhje}other{# nga {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"U krye"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Po fshin hapësirën ruajtëse të brendshme…"</string>
<string name="share" msgid="4157615043345227321">"Shpërndaj"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aktivizo"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacioni nuk ofrohet"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> nuk ofrohet për momentin."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nuk ofrohet"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Qasja është e pamundur në <xliff:g id="DEVICE">%1$s</xliff:g> për momentin. Provoje në pajisjen Android TV më mirë."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Qasja është e pamundur në <xliff:g id="DEVICE">%1$s</xliff:g> për momentin. Provoje në tablet më mirë."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Qasja është e pamundur në <xliff:g id="DEVICE">%1$s</xliff:g> për momentin. Provoje në telefon më mirë."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ky aplikacion është ndërtuar për një version më të vjetër të Android dhe mund të mos funksionojë mirë. Provo të kontrollosh për përditësime ose kontakto me zhvilluesin."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Kontrollo për përditësim"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Ke mesazhe të reja"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ÇINSTALO"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"HAPE GJITHSESI"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"U gjet aplikacion i dëmshëm"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Kërkesë për qasje te evidenca e sistemit"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Vetëm këtë herë"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Mos lejo"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> kërkon evidenca të sistemit për korrigjim funksional. Këto evidenca mund të përmbajnë informacione që kanë shkruar aplikacionet dhe shërbimet në pajisjen tënde."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Mos e shfaq më"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> dëshiron të shfaqë pjesë të <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Modifiko"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Do të lëshojë dridhje për telefonatat dhe njoftimet"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialogu i energjisë"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ekrani i kyçjes"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Pamja e ekranit"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Grepi i kufjeve me mikrofon"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Shkurtorja e qasshmërisë në ekran"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Zgjedhësi i shkurtores së qasshmërisë në ekran"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Shkurtorja e qasshmërisë"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Hiq \"Strehën e njoftimeve\""</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Lart në bllokun e drejtimit"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Poshtë në bllokun e drejtimit"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Majtas në bllokun e drejtimit"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Djathtas në bllokun e drejtimit"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Qendra e bllokut të drejtimit"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Shiriti i nëntitullit të <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> është vendosur në grupin E KUFIZUAR"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Trokit për ta aktivizuar"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Nuk ka aplikacione pune"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Nuk ka aplikacione personale"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Të hapet <xliff:g id="APP">%s</xliff:g> në profilin tënd personal?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Të hapet <xliff:g id="APP">%s</xliff:g> në profilin tënd të punës?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Përdor shfletuesin personal"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Përdor shfletuesin e punës"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"Kodi PIN i shkyçjes së rrjetit të kartës SIM"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> po ekzekutohet në sfond dhe po shkarkon baterinë. Trokit për ta shqyrtuar."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> po ekzekutohet në sfond për një kohe të gjatë. Trokit për ta shqyrtuar."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Kontrollo aplikacionet aktive"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 527ead8..caac95b 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -77,7 +77,7 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"ИД позиваоца подразумевано није ограничен. Следећи позив: Није ограничен."</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Услуга није добављена."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Не можете да промените подешавање ИД-а корисника."</string>
- <string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Нема услуге преноса података преко мобилног оператера"</string>
+ <string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Нема услуге мобилних података"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Хитни позиви нису доступни"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Нема гласовне услуге"</string>
<string name="RestrictedOnAllVoiceTitle" msgid="3982069078579103087">"Нема гласовне услуге ни хитних позива"</string>
@@ -589,8 +589,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Употребите закључавање екрана да бисте наставили"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Откривен је делимичан отисак прста"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Није успела обрада отиска прста. Пробајте поново."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Обришите сензор"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Задржите мало дуже"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Превише споро сте померили прст. Пробајте поново."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Пробајте са другим отиском прста"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Превише је светло"</string>
@@ -598,6 +602,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Сваки пут лагано промените положај прста"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Отисак прста је потврђен"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Лице је потврђено"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Лице је потврђено. Притисните Потврди"</string>
@@ -1501,7 +1509,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Прескочи"</string>
<string name="no_matches" msgid="6472699895759164599">"Нема подударања"</string>
<string name="find_on_page" msgid="5400537367077438198">"Пронађи на страници"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# подударање}one{# од {total}}few{# од {total}}other{# of {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Готово"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Брише се дељени меморијски простор…"</string>
<string name="share" msgid="4157615043345227321">"Дели"</string>
@@ -1929,6 +1938,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Укључи"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Апликација није доступна"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> тренутно није доступна."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> – није доступно"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Овој апликацији тренутно не може да се приступи са уређаја <xliff:g id="DEVICE">%1$s</xliff:g>. Пробајте на Android TV уређају."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Овој апликацији тренутно не може да се приступи са уређаја <xliff:g id="DEVICE">%1$s</xliff:g>. Пробајте на таблету."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Овој апликацији тренутно не може да се приступи са уређаја <xliff:g id="DEVICE">%1$s</xliff:g>. Пробајте на телефону."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ова апликација је направљена за старију верзију Android-а, па можда неће радити исправно. Потражите ажурирања или контактирајте програмера."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Потражи ажурирање"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Имате нове поруке"</string>
@@ -2018,16 +2031,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ДЕИНСТАЛИРАЈ"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"ИПАК ОТВОРИ"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Откривена је штетна апликација"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Захтев за приступ системској евиденцији"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Само овај пут"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Не дозволи"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> захтева евиденције система ради отклањања грешака у функцијама. Те евиденције могу да садрже информације које су апликације и услуге на уређају записале."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Не приказуј поново"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Апликација <xliff:g id="APP_0">%1$s</xliff:g> жели да приказује исечке из апликације <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Измени"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Вибрација за позиве и обавештења је укључена"</string>
@@ -2090,22 +2098,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Дијалог напајања"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Закључани екран"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Снимак екрана"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Кука за слушалице"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Пречица за приступачност на екрану"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Алатка за бирање пречица за приступачност на екрану"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Пречица за приступачност"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Одбаци траку са обавештењима"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"нагоре на D-pad-у"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"надоле на D-pad-у"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"налево на D-pad-у"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"надесно на D-pad-у"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"центар на D-pad-у"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Трака са насловима апликације <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> је додат у сегмент ОГРАНИЧЕНО"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2126,10 +2128,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Додирните да бисте укључили"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Нема пословних апликација"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Нема личних апликација"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Желите да на личном профилу отворите: <xliff:g id="APP">%s</xliff:g>?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Желите да на пословном профилу отворите: <xliff:g id="APP">%s</xliff:g>?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Користи лични прегледач"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Користи пословни прегледач"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"PIN за откључавање SIM мреже"</string>
@@ -2264,4 +2264,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"Апликација <xliff:g id="APP">%1$s</xliff:g> је покренута у позадини и троши батерију. Додирните да бисте прегледали."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"Апликација <xliff:g id="APP">%1$s</xliff:g> је предуго покренута у позадини. Додирните да бисте прегледали."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Проверите активне апликације"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 0e46502..4adcc47 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Fortsätt med hjälp av ditt skärmlås"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Ofullständigt fingeravtryck upptäcktes"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Det gick inte att bearbeta fingeravtrycket. Försök igen."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Rengör sensorn"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Håll kvar fingret lite längre"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Du rörde fingret för långsamt. Försök igen."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Testa ett annat fingeravtryck"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Det är för ljust"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Flytta fingret lite varje gång"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingeravtrycket har autentiserats"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Ansiktet har autentiserats"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Ansiktet har autentiserats. Tryck på Bekräfta"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Hoppa över"</string>
<string name="no_matches" msgid="6472699895759164599">"Inga träffar"</string>
<string name="find_on_page" msgid="5400537367077438198">"Sök på sidan"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# matchning}other{# av {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Klar"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Delat lagringsutrymme rensas …"</string>
<string name="share" msgid="4157615043345227321">"Dela"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aktivera"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Appen är inte tillgänglig"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> är inte tillgängligt just nu."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> är inte tillgänglig"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Det går inte att streama detta till <xliff:g id="DEVICE">%1$s</xliff:g> för närvarande. Testa med Android TV-enheten i stället."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Det går inte att streama detta till <xliff:g id="DEVICE">%1$s</xliff:g> för närvarande. Testa med surfplattan i stället."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Det går inte att streama detta till <xliff:g id="DEVICE">%1$s</xliff:g> för närvarande. Testa med telefonen i stället."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Appen har utvecklats för en äldre version av Android och kanske inte fungerar som den ska. Testa att söka efter uppdateringar eller kontakta utvecklaren."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Sök efter uppdateringar"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Du har nya meddelanden"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"AVINSTALLERA"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"ÖPPNA ÄNDÅ"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"En skadlig app har upptäckts"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Begäran om åtkomst till systemloggar"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Bara den här gången"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Tillåt inte"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> begär systemloggar i syfte att felsöka funktioner. Dessa loggar kan innehålla information som har skrivits på enheten av appar och tjänster."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Visa inte igen"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> vill kunna visa bitar av <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Redigera"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Vibrerar vid samtal och aviseringar"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialogruta för ström"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Låsskärm"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skärmbild"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Krok till headset"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Tillgänglighetsgenväg på skärmen"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Valfunktion för tillgänglighetsgenväg på skärmen"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Aktivera tillgänglighet snabbt"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Stäng meddelandepanelen"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Styrkors, upp"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Styrkors, ned"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Styrkors, vänster"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Styrkors, höger"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Styrkors, mitten"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Textningsfält för <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> har placerats i hinken RESTRICTED"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Tryck för att aktivera"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Inga jobbappar"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Inga privata appar"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Vill du öppna <xliff:g id="APP">%s</xliff:g> i din privata profil?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Vill du öppna <xliff:g id="APP">%s</xliff:g> i din jobbprofil?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Använd privat webbläsare"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Använd jobbwebbläsare"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"Pinkod för upplåsning av nätverk för SIM-kort"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> körs i bakgrunden så att batteriet tar slut fortare. Tryck för att granska."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> har körts i bakgrunden under lång tid. Tryck för att granska."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Kontrollera aktiva appar"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index dcbb1ac..02572b0 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Weka mbinu yako ya kufunga skrini ili uendelee"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Kimetambua sehemu ya alama ya kidole"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Imeshindwa kuchakata alama ya kidole. Tafadhali jaribu tena."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Safisha kitambuzi cha alama ya kidole"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Endelea kushikilia kwa muda zaidi"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Kidole kilisogezwa polepole zaidi. Tafadhali jaribu tena."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Jaribu alama nyingine ya kidole"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Inang\'aa mno"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Badilisha mkao wa kidole chako kiasi kila wakati"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Imethibitisha alama ya kidole"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Uso umethibitishwa"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Uso umethibitishwa, tafadhali bonyeza thibitisha"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Ruka"</string>
<string name="no_matches" msgid="6472699895759164599">"Hakuna vinavyolingana"</string>
<string name="find_on_page" msgid="5400537367077438198">"Pata kwenye ukurasa"</string>
- <string name="matches_found" msgid="7912910457231705587">"Mechi{count,plural, =1{#}other{# kati ya {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Nimemaliza"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Inafuta hifadhi iliyoshirikiwa…"</string>
<string name="share" msgid="4157615043345227321">"Shiriki"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Washa"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Programu haipatikani"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> haipatikani hivi sasa."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> haipatikani"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Programu hii haiwezi kufikiwa kwenye <xliff:g id="DEVICE">%1$s</xliff:g> kwa muda huu. Badala yake jaribu kwenye kifaa chako cha Android TV."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Programu hii haiwezi kufikiwa kwenye <xliff:g id="DEVICE">%1$s</xliff:g> kwa muda huu. Badala yake jaribu kwenye kompyuta kibao yako."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Programu hii haiwezi kufikiwa kwenye <xliff:g id="DEVICE">%1$s</xliff:g> kwa muda huu. Badala yake jaribu kwenye simu yako."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Programu hii iliundwa kwa ajili ya toleo la zamani la Android na huenda isifanye kazi vizuri. Jaribu kuangalia masasisho au uwasiliane na msanidi programu."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Angalia masasisho"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Una ujumbe mpya"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ONDOA"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"FUNGUA TU"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Imetambua programu hatari"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Ombi la ufikiaji wa kumbukumbu ya mfumo"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Mara hii pekee"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Usiruhusu"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> huomba kumbukumbu za mfumo ili kutatua hitilafu za utendaji kazi. Kumbukumbu hizi zinaweza kuwa na maelezo ambayo programu na huduma ziliandika kwenye kifaa chako."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Usionyeshe tena"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> inataka kuonyesha vipengee <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Badilisha"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Itatetema arifa ikitumwa au simu ikipigwa"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Kidirisha cha Nishati"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Skrini Iliyofungwa"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Picha ya skrini"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Kishika vifaa vya sauti"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Njia ya Mkato ya Ufikivu kwenye Skrini"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Kichagua Njia ya Mkato ya Ufikivu kwenye Skrini"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Njia ya Mkato ya Ufikivu"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Ondoa Sehemu ya Arifa"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Kitufe cha juu cha Dpad"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Kitufe cha chini cha Dpad"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Kitufe cha kushoto cha Dpad"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Kitufe cha kulia cha Dpad"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Kitufe cha katikati cha Dpad"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Upau wa manukuu wa <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> kimewekwa katika kikundi KILICHODHIBITIWA"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Gusa ili uwashe"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Hakuna programu za kazini"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Hakuna programu za binafsi"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Je, unataka kufungua <xliff:g id="APP">%s</xliff:g> katika wasifu wako binafsi?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Je, unataka kufungua <xliff:g id="APP">%s</xliff:g> katika wasifu wako wa kazi?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Tumia kivinjari cha binafsi"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Tumia kivinjari cha kazini"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"PIN ya kufungua mtandao wa SIM"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> inatumika chinichini na kumaliza nishati ya betri. Gusa ili ukague."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> inatumika chinichini kwa muda mrefu. Gusa ili ukague."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Angalia programu zinazotumika"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 7a46d45..9acbac6 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -304,10 +304,8 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"கேலெண்டரை அணுகலாம்"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS அனுப்பலாம், வந்த SMSகளைப் பார்க்கலாம்"</string>
- <!-- no translation found for permgrouplab_storage (9173334109512154196) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (8352226729501080525) -->
- <skip />
+ <string name="permgrouplab_storage" msgid="9173334109512154196">"ஃபைல்கள் & ஆவணங்கள்"</string>
+ <string name="permgroupdesc_storage" msgid="8352226729501080525">"சாதனத்திலுள்ள ஃபைல்களையும் ஆவணங்களையும் அணுகும்"</string>
<string name="permgrouplab_readMediaAural" msgid="5885210465560755316">"இசை & பிற ஆடியோ"</string>
<string name="permgroupdesc_readMediaAural" msgid="1170143315714662822">"உங்கள் சாதனத்திலுள்ள ஆடியோ ஃபைல்களை அணுகும்"</string>
<string name="permgrouplab_readMediaVisual" msgid="9137695801926624061">"படங்கள் & வீடியோக்கள்"</string>
@@ -588,8 +586,9 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"தொடர்வதற்கு உங்கள் திரைப் பூட்டை உள்ளிடுங்கள்"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"பகுதியளவு கைரேகை கண்டறியப்பட்டது"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"கைரேகையைச் செயலாக்க முடியவில்லை. மீண்டும் முயலவும்."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"சென்சாரைச் சுத்தம் செய்யவும்"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"இன்னும் சிறிது நேரம் விரலை வைத்திருங்கள்"</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"கைரேகை சென்சாரைச் சுத்தம் செய்துவிட்டு மீண்டும் முயலவும்"</string>
+ <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"சென்சாரைச் சுத்தம் செய்துவிட்டு மீண்டும் முயலவும்"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"சென்சாரின் மீது நன்றாக அழுத்தவும்"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"விரலை மிகவும் மெதுவாக நகர்த்திவிட்டீர்கள். மீண்டும் முயற்சிக்கவும்."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"வேறு கைரேகையை முயலவும்"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"அதிக வெளிச்சமாக உள்ளது"</string>
@@ -597,6 +596,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"ஒவ்வொரு முறையும் விரலின் நிலையைச் சிறிதளவு மாற்றுங்கள்"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"கைரேகை அங்கீகரிக்கப்படவில்லை"</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="4709197752023550709">"சென்சாரின் மீது நன்றாக அழுத்தவும்"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"கைரேகை அங்கீகரிக்கப்பட்டது"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"முகம் அங்கீகரிக்கப்பட்டது"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"முகம் அங்கீகரிக்கப்பட்டது. ’உறுதிப்படுத்துக’ என்பதை அழுத்துக"</string>
@@ -1500,7 +1501,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"தவிர்"</string>
<string name="no_matches" msgid="6472699895759164599">"பொருத்தம் ஏதுமில்லை"</string>
<string name="find_on_page" msgid="5400537367077438198">"பக்கத்தில் கண்டறி"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# match}other{# / {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"முடிந்தது"</string>
<string name="progress_erasing" msgid="6891435992721028004">"பகிர்ந்த சேமிப்பகத்தை அழிக்கிறது…"</string>
<string name="share" msgid="4157615043345227321">"பகிர்"</string>
@@ -1928,6 +1930,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"இயக்கு"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"இந்த ஆப்ஸ் இப்போது கிடைப்பதில்லை"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸ் இப்போது கிடைப்பதில்லை."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> இல்லை"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"தற்போது உங்கள் <xliff:g id="DEVICE">%1$s</xliff:g> சாதனத்தில் இதை அணுக முடியாது. அதற்குப் பதிலாக Android TV சாதனத்தில் பயன்படுத்திப் பாருங்கள்."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"தற்போது உங்கள் <xliff:g id="DEVICE">%1$s</xliff:g> சாதனத்தில் இதை அணுக முடியாது. அதற்குப் பதிலாக உங்கள் டேப்லெட்டில் பயன்படுத்திப் பாருங்கள்."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"தற்போது உங்கள் <xliff:g id="DEVICE">%1$s</xliff:g> சாதனத்தில் இதை அணுக முடியாது. அதற்குப் பதிலாக உங்கள் மொபைலில் பயன்படுத்திப் பாருங்கள்."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"இந்த ஆப்ஸ் Android இன் பழைய பதிப்புக்காக உருவாக்கப்பட்டதால், சரியாக வேலை செய்யாமல் போகலாம். புதுப்பிப்புகள் ஏதேனும் உள்ளதா எனப் பார்க்கவும் அல்லது டெவெலப்பரைத் தொடர்புகொள்ளவும்."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"புதுப்பிப்பு உள்ளதா எனப் பார்"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"புதிய செய்திகள் வந்துள்ளன"</string>
@@ -2017,16 +2023,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"நிறுவல் நீக்கு"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"பரவாயில்லை, திற"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"தீங்கிழைக்கும் ஆப்ஸ் உள்ளது"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"சிஸ்டம் பதிவை அணுகுவதற்கான கோரிக்கை"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"இப்போது மட்டும்"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"அனுமதிக்க வேண்டாம்"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"பிழைதிருத்தச் செயல்பாட்டிற்கான சிஸ்டம் பதிவுகளை <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ஆப்ஸ் கோருகிறது. இந்தப் பதிவுகள் உங்கள் சாதனத்தில் ஆப்ஸ் மற்றும் சேவைகளில் உள்ள எழுத்துப்பூர்வமான தகவல்களைக் கொண்டிருக்கக்கூடும்."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"மீண்டும் காட்டாதே"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_2">%2$s</xliff:g> ஆப்ஸின் விழிப்பூட்டல்களைக் காண்பிக்க, <xliff:g id="APP_0">%1$s</xliff:g> அனுமதி கேட்கிறது"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"திருத்து"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"அழைப்புகள் மற்றும் அறிவிப்புகளுக்கு அதிரும்"</string>
@@ -2119,10 +2120,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"ஆன் செய்யத் தட்டுக"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"பணி ஆப்ஸ் எதுவுமில்லை"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"தனிப்பட்ட ஆப்ஸ் எதுவுமில்லை"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"உங்கள் தனிப்பட்ட கணக்கில் <xliff:g id="APP">%s</xliff:g> ஆப்ஸைத் திறக்கவா?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"உங்கள் பணிக் கணக்கில் <xliff:g id="APP">%s</xliff:g> ஆப்ஸைத் திறக்கவா?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"தனிப்பட்ட உலாவியைப் பயன்படுத்து"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"பணி உலாவியைப் பயன்படுத்து"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"சிம் நெட்வொர்க் அன்லாக் பின்"</string>
@@ -2257,4 +2256,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> ஆப்ஸ் பின்னணியில் இயங்குவதுடன் பேட்டரியை அதிகமாகப் பயன்படுத்துகிறது. பார்க்க தட்டவும்."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> ஆப்ஸ் நீண்ட நேரமாகப் பின்னணியில் இயங்குகிறது. பார்க்க தட்டவும்."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"செயலிலுள்ள ஆப்ஸைப் பாருங்கள்"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 39f36ed..6e4ef59 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -304,10 +304,8 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"మీ క్యాలెండర్ను యాక్సెస్ చేయడానికి"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS మెసేజ్లను పంపడం, వీక్షించడం"</string>
- <!-- no translation found for permgrouplab_storage (9173334109512154196) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (8352226729501080525) -->
- <skip />
+ <string name="permgrouplab_storage" msgid="9173334109512154196">"ఫైల్స్ & డాక్యుమెంట్లు"</string>
+ <string name="permgroupdesc_storage" msgid="8352226729501080525">"మీ పరికరంలోని ఫైల్లు, డాక్యుమెంట్లను యాక్సెస్ చేయండి"</string>
<string name="permgrouplab_readMediaAural" msgid="5885210465560755316">"మ్యూజిక్ & ఇతర ఆడియో"</string>
<string name="permgroupdesc_readMediaAural" msgid="1170143315714662822">"మీ పరికరంలోని ఆడియో ఫైల్లను యాక్సెస్ చేయండి"</string>
<string name="permgrouplab_readMediaVisual" msgid="9137695801926624061">"ఫోటోలు & వీడియోలు"</string>
@@ -588,8 +586,9 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"కొనసాగించడానికి మీ స్క్రీన్ లాక్ను ఎంటర్ చేయండి"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"పాక్షిక వేలిముద్ర గుర్తించబడింది"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"వేలిముద్రను ప్రాసెస్ చేయడం సాధ్యపడలేదు. దయచేసి మళ్లీ ప్రయత్నించండి."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"సెన్సార్ను శుభ్రం చేయండి"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"కొంచెం ఎక్కువసేపు పట్టుకోండి"</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"వేలిముద్ర సెన్సార్ను క్లీన్ చేసి, మళ్లీ ట్రై చేయండి"</string>
+ <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"సెన్సార్ను క్లీన్ చేసి, మళ్లీ ట్రై చేయండి"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"సెన్సార్ మీద గట్టిగా నొక్కండి"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"వేలిని చాలా నెమ్మదిగా కదిలించారు. దయచేసి మళ్లీ ప్రయత్నించండి."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"మరొక వేలిముద్రను ట్రై చేయండి"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"వెలుతురు అధికంగా ఉంది"</string>
@@ -597,6 +596,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"ప్రతిసారీ మీ వేళ్ల స్థానాన్ని కొద్దిగా మార్చండి"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"వేలిముద్ర గుర్తించబడలేదు"</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="4709197752023550709">"సెన్సార్ మీద గట్టిగా నొక్కండి"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"వేలిముద్ర ప్రమాణీకరించబడింది"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"ముఖం ప్రమాణీకరించబడింది"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"ముఖం ప్రమాణీకరించబడింది, దయచేసి ధృవీకరించును నొక్కండి"</string>
@@ -1500,7 +1501,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"దాటవేయి"</string>
<string name="no_matches" msgid="6472699895759164599">"సరిపోలికలు లేవు"</string>
<string name="find_on_page" msgid="5400537367077438198">"పేజీలో కనుగొనండి"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# {total}లో #}other{ మ్యాచ్ }} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"పూర్తయింది"</string>
<string name="progress_erasing" msgid="6891435992721028004">"షేర్ చేసిన నిల్వను తొలగిస్తోంది…"</string>
<string name="share" msgid="4157615043345227321">"షేర్"</string>
@@ -1928,6 +1930,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"ఆన్ చేయి"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"యాప్ అందుబాటులో లేదు"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ప్రస్తుతం అందుబాటులో లేదు."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> అందుబాటులో లేదు"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"ఈ సమయంలో మీ <xliff:g id="DEVICE">%1$s</xliff:g>లో దీన్ని యాక్సెస్ చేయడం సాధ్యపడదు. బదులుగా మీ Android TV పరికరంలో ట్రై చేయండి."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"ఈ సమయంలో మీ <xliff:g id="DEVICE">%1$s</xliff:g>లో దీన్ని యాక్సెస్ చేయడం సాధ్యపడదు. బదులుగా మీ టాబ్లెట్లో ట్రై చేయండి."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"ఈ సమయంలో మీ <xliff:g id="DEVICE">%1$s</xliff:g>లో దీన్ని యాక్సెస్ చేయడం సాధ్యపడదు. బదులుగా మీ ఫోన్లో ట్రై చేయండి."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ఈ యాప్ పాత వెర్షన్ Android కోసం రూపొందించబడింది మరియు అది సరిగ్గా పని చేయకపోవచ్చు. అప్డేట్ల కోసం తనిఖీ చేయడానికి ప్రయత్నించండి లేదా డెవలపర్ని సంప్రదించండి."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"అప్డేట్ కోసం తనిఖీ చేయండి"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"మీకు కొత్త మెసేజ్లు ఉన్నాయి"</string>
@@ -2017,16 +2023,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"అన్ఇన్స్టాల్ చేయండి"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"ఏదేమైనా తెరువు"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"హానికరమైన యాప్ గుర్తించబడింది"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"సిస్టమ్ లాగ్ యాక్సెస్ రిక్వెస్ట్"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"ఈ ఒక్కసారి మాత్రమే"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"అనుమతించవద్దు"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"ఫంక్షనల్ డీబగ్గింగ్ కోసం, <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> సిస్టమ్ లాగ్లను రిక్వెస్ట్ చేస్తుంది. ఈ లాగ్లు, మీ పరికరంలోని యాప్లు, సర్వీస్లు రాసిన సమాచారాన్ని కలిగి ఉండవచ్చు."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"మళ్లీ చూపవద్దు"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> <xliff:g id="APP_2">%2$s</xliff:g> స్లైస్లను చూపించాలనుకుంటోంది"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"ఎడిట్ చేయండి"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"కాల్స్ మరియు నోటిఫికేషన్లు వైబ్రేట్ అవుతాయి"</string>
@@ -2119,10 +2120,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"ఆన్ చేయడానికి ట్యాప్ చేయి"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"వర్క్ యాప్లు లేవు"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"వ్యక్తిగత యాప్లు లేవు"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"<xliff:g id="APP">%s</xliff:g>ను మీ వ్యక్తిగత ప్రొఫైల్లో తెరవాలా?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"<xliff:g id="APP">%s</xliff:g>ను మీ వర్క్ ప్రొఫైల్లో తెరవాలా?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"వ్యక్తిగత బ్రౌజర్ను ఉపయోగించు"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"వర్క్ బ్రౌజర్ను ఉపయోగించు"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM నెట్వర్క్ అన్లాక్ పిన్"</string>
@@ -2257,4 +2256,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> బ్యాక్గ్రౌండ్లో రన్ అవుతోంది, బ్యాటరీని ఎక్కువగా వాడుతోంది. రివ్యూ చేయడానికి ట్యాప్ చేయండి."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> చాలా సమయం నుండి బ్యాక్గ్రౌండ్లో రన్ అవుతోంది. రివ్యూ చేయడానికి ట్యాప్ చేయండి."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"యాక్టివ్గా ఉన్న యాప్లను చెక్ చేయండి"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 039c7f7..4b33e95 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"ป้อนข้อมูลการล็อกหน้าจอเพื่อดำเนินการต่อ"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"ตรวจพบลายนิ้วมือบางส่วน"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ประมวลผลลายนิ้วมือไม่ได้ โปรดลองอีกครั้ง"</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"ทำความสะอาดเซ็นเซอร์"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"วางนิ้วให้นานขึ้นอีกนิด"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"นิ้วเคลื่อนที่ช้าเกินไป โปรดลองอีกครั้ง"</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"ลองลายนิ้วมืออื่น"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"สว่างเกินไป"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"เปลี่ยนตำแหน่งของนิ้วเล็กน้อยไปเรื่อยๆ ทุกครั้ง"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ตรวจสอบสิทธิ์ลายนิ้วมือแล้ว"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"ตรวจสอบสิทธิ์ใบหน้าแล้ว"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"ตรวจสอบสิทธิ์ใบหน้าแล้ว โปรดกดยืนยัน"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"ข้าม"</string>
<string name="no_matches" msgid="6472699895759164599">"ไม่พบรายการที่ตรงกัน"</string>
<string name="find_on_page" msgid="5400537367077438198">"ค้นหาบนหน้า"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{ตรงกัน # รายการ}other{# จาก {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"เสร็จสิ้น"</string>
<string name="progress_erasing" msgid="6891435992721028004">"กำลังลบพื้นที่เก็บข้อมูลที่แชร์…"</string>
<string name="share" msgid="4157615043345227321">"แชร์"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"เปิด"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"แอปไม่พร้อมใช้งาน"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ไม่พร้อมใช้งานในขณะนี้"</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ไม่พร้อมใช้งาน"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"เข้าถึงแอปนี้ใน <xliff:g id="DEVICE">%1$s</xliff:g> ของคุณไม่ได้ในขณะนี้ โปรดลองเข้าถึงในอุปกรณ์ Android TV แทน"</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"เข้าถึงแอปนี้ใน <xliff:g id="DEVICE">%1$s</xliff:g> ของคุณไม่ได้ในขณะนี้ โปรดลองเข้าถึงในแท็บเล็ตแทน"</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"เข้าถึงแอปนี้ใน <xliff:g id="DEVICE">%1$s</xliff:g> ของคุณไม่ได้ในขณะนี้ โปรดลองเข้าถึงในโทรศัพท์แทน"</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"แอปนี้สร้างขึ้นเพื่อ Android เวอร์ชันเก่าและอาจทำงานผิดปกติ โปรดลองตรวจหาการอัปเดตหรือติดต่อนักพัฒนาซอฟต์แวร์"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"ตรวจสอบอัปเดต"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"คุณมีข้อความใหม่"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ถอนการติดตั้ง"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"เปิดต่อไป"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"ตรวจพบแอปที่เป็นอันตราย"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"คำขอเข้าถึงบันทึกของระบบ"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"เฉพาะครั้งนี้"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"ไม่อนุญาต"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ขอบันทึกของระบบเพื่อแก้ไขข้อบกพร่องเกี่ยวกับการทำงาน บันทึกเหล่านี้อาจมีข้อมูลที่เขียนโดยแอปและบริการในอุปกรณ์"</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"ไม่ต้องแสดงอีก"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ต้องการแสดงส่วนต่างๆ ของ <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"แก้ไข"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"สายเรียกเข้าและการแจ้งเตือนจะสั่น"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"กล่องโต้ตอบพลังงาน"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"หน้าจอล็อก"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ภาพหน้าจอ"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Hook ชุดหูฟัง"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"ทางลัดการช่วยเหลือพิเศษบนหน้าจอ"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"ตัวเลือกทางลัดการช่วยเหลือพิเศษบนหน้าจอ"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"ทางลัดการช่วยเหลือพิเศษ"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"ปิดหน้าต่างแจ้งเตือน"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Dpad ขึ้น"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Dpad ลง"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad ซ้าย"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad ขวา"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad กึ่งกลาง"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"แถบคำบรรยาย <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"ใส่ <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ในที่เก็บข้อมูลที่ถูกจำกัดแล้ว"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"แตะเพื่อเปิด"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"ไม่มีแอปงาน"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"ไม่มีแอปส่วนตัว"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"เปิด <xliff:g id="APP">%s</xliff:g> ในโปรไฟล์ส่วนตัวไหม"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"เปิด <xliff:g id="APP">%s</xliff:g> ในโปรไฟล์งานไหม"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"ใช้เบราว์เซอร์ส่วนตัว"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"ใช้เบราว์เซอร์งาน"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"PIN ปลดล็อกเครือข่ายที่ใช้กับ SIM"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> กำลังทำงานอยู่ในเบื้องหลังและทำให้เปลืองแบตเตอรี่ แตะเพื่อตรวจสอบ"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> ทำงานอยู่ในเบื้องหลังเป็นเวลานาน แตะเพื่อตรวจสอบ"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"ตรวจสอบแอปที่ใช้งานอยู่"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 0200548..e443676 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Ilagay ang iyong lock ng screen para magpatuloy"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Hindi buo ang natukoy na fingerprint"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Hindi maproseso ang fingerprint. Pakisubukan ulit."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Linisin ang sensor"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"I-hold nang mas matagal nang kaunti"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Masyadong mabagal ang paggalaw ng daliri. Pakisubukan ulit."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Sumubok ng ibang fingerprint"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Masyadong maliwanag"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Bahagyang baguhin ang posisyon ng iyong daliri sa bawat pagkakataon"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Na-authenticate ang fingerprint"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Na-authenticate ang mukha"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Na-authenticate ang mukha, pakipindot ang kumpirmahin"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Laktawan"</string>
<string name="no_matches" msgid="6472699895759164599">"Walang mga tugma"</string>
<string name="find_on_page" msgid="5400537367077438198">"Maghanap sa pahina"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# tugma}one{# sa {total}}other{# sa {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Tapos na"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Binubura ang nakabahaging storage…"</string>
<string name="share" msgid="4157615043345227321">"Ibahagi"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"I-on"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Hindi available ang app"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Hindi available sa ngayon ang <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"Hindi available ang <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Hindi ito maa-access sa iyong <xliff:g id="DEVICE">%1$s</xliff:g> sa ngayon. Subukan na lang sa iyong Android TV device."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Hindi ito maa-access sa iyong <xliff:g id="DEVICE">%1$s</xliff:g> sa ngayon. Subukan na lang sa iyong tablet."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Hindi ito maa-access sa iyong <xliff:g id="DEVICE">%1$s</xliff:g> sa ngayon. Subukan na lang sa iyong telepono."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ang app na ito ay ginawa para sa mas lumang bersyon ng Android at maaaring hindi gumana nang maayos. Subukang tingnan kung may mga update, o makipag-ugnayan sa developer."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Tingnan kung may update"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Mayroon kang mga bagong mensahe"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"I-UNINSTALL"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"BUKSAN PA RIN"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"May na-detect na mapaminsalang app"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Kahilingan sa access sa log ng system"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Ngayon lang"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Huwag payagan"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"Humihiling ang <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ng mga log ng system para sa functional na pag-debug. Posibleng maglaman ang mga log na ito ng impormasyong isinulat ng mga app at serbisyo sa iyong device."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Huwag ipakita ulit"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Gustong ipakita ng <xliff:g id="APP_0">%1$s</xliff:g> ang mga slice ng <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"I-edit"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Magva-vibrate ang mga tawag at notification"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialog ng Power"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Headset Hook"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Shortcut ng Accessibility sa Screen"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Tagapili ng Shortcut ng Accessibility sa Screen"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Shortcut ng Accessibility"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"I-dismiss ang Notification Shade"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Dpad Up"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Dpad Down"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad Left"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad Right"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad Center"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar ng <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Inilagay ang <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> sa PINAGHIHIGPITANG bucket"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"I-tap para i-on"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Walang app para sa trabaho"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Walang personal na app"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Buksan ang <xliff:g id="APP">%s</xliff:g> sa iyong personal na profile?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Buksan ang <xliff:g id="APP">%s</xliff:g> sa iyong profile sa trabaho?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Gamitin ang personal na browser"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Gamitin ang browser sa trabaho"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"PIN para sa pag-unlock ng network ng SIM"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"Gumagana ang <xliff:g id="APP">%1$s</xliff:g> sa background at gumagamit ito ng baterya I-tap para suriin."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"Napakatagal nang gumagana ang <xliff:g id="APP">%1$s</xliff:g> sa background. I-tap para suriin."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Tingnan ang mga aktibong app"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 90a7668..9546de4 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Devam etmek için ekran kilidinizi girin"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Parmak izinin tümü algılanamadı"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Parmak izi işlenemedi. Lütfen tekrar deneyin."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Sensörü temizleyin"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Biraz daha uzun basılı tutun"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Parmak hareketi çok yavaştı. Lütfen tekrar deneyin."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Başka bir parmak izi deneyin"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Çok parlak"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Her defasında parmağınızın konumunu biraz değiştirin"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Parmak izi kimlik doğrulaması yapıldı"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Yüz kimliği doğrulandı"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Yüz kimliği doğrulandı, lütfen onayla\'ya basın"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Atla"</string>
<string name="no_matches" msgid="6472699895759164599">"Eşleşme yok"</string>
<string name="find_on_page" msgid="5400537367077438198">"Sayfada bul"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# eşleşme}other{#/{total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Bitti"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Paylaşılan depolama alanı siliniyor…"</string>
<string name="share" msgid="4157615043345227321">"Paylaş"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aç"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Uygulama kullanılamıyor"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulaması şu anda kullanılamıyor."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> kullanılamıyor"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Bu uygulamaya şu anda <xliff:g id="DEVICE">%1$s</xliff:g> cihazınızdan erişilemiyor. Bunun yerine Android TV cihazınızı kullanmayı deneyin."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Bu uygulamaya şu anda <xliff:g id="DEVICE">%1$s</xliff:g> cihazınızdan erişilemiyor. Bunun yerine tabletinizi kullanmayı deneyin."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Bu uygulamaya şu anda <xliff:g id="DEVICE">%1$s</xliff:g> cihazınızdan erişilemiyor. Bunun yerine telefonunuzu kullanmayı deneyin."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Bu uygulama Android\'in daha eski bir sürümü için oluşturuldu ve düzgün çalışmayabilir. Güncellemeleri kontrol etmeyi deneyin veya geliştiriciyle iletişime geçin."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Güncellemeleri denetle"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Yeni mesajlarınız var"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"YÜKLEMEYİ KALDIR"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"YİNE DE AÇ"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Zararlı uygulama tespit edildi"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Sistem günlük kayıtlarına erişim isteği"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Yalnız bu sefer"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"İzin verme"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> uygulaması işlevsel hata ayıklama için sistem günlük kayıtlarını istiyor. Bu günlükler, cihazınızdaki uygulama ve hizmetler tarafından yazılan bilgileri içerebilir."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Bir daha gösterme"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> uygulaması, <xliff:g id="APP_2">%2$s</xliff:g> dilimlerini göstermek istiyor"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Düzenle"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Aramalar ve bildirimler titreşim yapacak"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Güç İletişim Kutusu"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Kilit Ekranı"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekran görüntüsü"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Mikrofonlu Kulaklık Kancası"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Ekran Erişilebilirlik Kısayolu"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Ekran Erişilebilirlik Kısayol Seçici"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Erişilebilirlik Kısayolu"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Bildirim Gölgesini Kapat"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Dpad Yukarı"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Dpad Aşağı"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad Sol"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad Sağ"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad Orta"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulamasının başlık çubuğu."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> KISITLANMIŞ gruba yerleştirildi"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Açmak için dokunun"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"İş uygulaması yok"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Kişisel uygulama yok"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"<xliff:g id="APP">%s</xliff:g> uygulaması kişisel profilinizde açılsın mı?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"<xliff:g id="APP">%s</xliff:g> uygulaması iş profilinizde açılsın mı?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Kişisel tarayıcıyı kullan"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"İş tarayıcısını kullan"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM ağ kilidi açma PIN kodu"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> arka planda çalışıyor ve pil tüketiyor. İncelemek için dokunun."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> uzun süredir arka planda çalışıyor. İncelemek için dokunun."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Etkin uygulamaları kontrol edin"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 1b72d96..cc763ad 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -590,8 +590,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Щоб продовжити, введіть дані для розблокування екрана"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Виявлено частковий відбиток пальця"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Не вдалось обробити відбиток пальця. Повторіть спробу."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Очистьте сканер"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Тримайте палець трохи довше"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Ви провели пальцем надто повільно. Повторіть спробу."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Спробуйте інший відбиток пальця"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Надто яскраво"</string>
@@ -599,6 +603,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Щоразу трохи змінюйте положення пальця"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Відбиток пальця автентифіковано"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Обличчя автентифіковано"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Обличчя автентифіковано. Натисніть \"Підтвердити\""</string>
@@ -1502,7 +1510,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Пропустити"</string>
<string name="no_matches" msgid="6472699895759164599">"Немає збігів"</string>
<string name="find_on_page" msgid="5400537367077438198">"Знайти на сторінці"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# збіг}one{# з {total}}few{# з {total}}many{# з {total}}other{# з {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Готово"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Стирання спільної пам’яті…"</string>
<string name="share" msgid="4157615043345227321">"Надіслати"</string>
@@ -1930,6 +1939,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Увімкнути"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Додаток недоступний"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> зараз недоступний."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"Недоступно: <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Цей додаток зараз недоступний на вашому <xliff:g id="DEVICE">%1$s</xliff:g>. Спробуйте натомість скористатися пристроєм Android TV."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Цей додаток зараз недоступний на вашому <xliff:g id="DEVICE">%1$s</xliff:g>. Спробуйте натомість скористатися планшетом."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Цей додаток зараз недоступний на вашому <xliff:g id="DEVICE">%1$s</xliff:g>. Спробуйте натомість скористатися телефоном."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Цей додаток створений для старішої версії Android і може працювати неналежним чином. Спробуйте знайти оновлення або зв’яжіться з розробником."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Шукати оновлення"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"У вас є нові повідомлення"</string>
@@ -2019,16 +2032,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ВИДАЛИТИ"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"УСЕ ОДНО ВІДКРИТИ"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Виявлено шкідливий додаток"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Запит на доступ до системних журналів"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Лише цього разу"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Не дозволяти"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"Для функціонального налагодження додатку <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> потрібен доступ до системних журналів. Вони можуть містити інформацію, записану додатками й сервісами на вашому пристрої."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Більше не показувати"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> хоче показати фрагменти додатка <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Редагувати"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Вібросигнал для викликів і сповіщень увімкнено"</string>
@@ -2091,22 +2099,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Відкрити вікно"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заблокувати екран"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Знімок екрана"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Гачок для гарнітури"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Екранний засіб спеціальних можливостей"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Вибір екранного засобу спеціальних можливостей"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Засіб спеціальних можливостей"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Закрити панель сповіщень"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Кнопка \"вгору\" панелі керування"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Кнопка \"вниз\" панелі керування"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Кнопка \"вліво\" панелі керування"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Кнопка \"вправо\" панелі керування"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Центральна кнопка панелі керування"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Смуга із субтитрами для додатка <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" додано в сегмент з обмеженнями"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2127,10 +2129,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Торкніться, щоб увімкнути"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Немає робочих додатків"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Немає особистих додатків"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Відкрити додаток <xliff:g id="APP">%s</xliff:g> в особистому профілі?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Відкрити додаток <xliff:g id="APP">%s</xliff:g> у робочому профілі?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Використати особистий веб-переглядач"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Використати робочий веб-переглядач"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"PIN-код розблокування мережі SIM-карти"</string>
@@ -2265,4 +2265,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"Додаток <xliff:g id="APP">%1$s</xliff:g> працює у фоновому режимі та розряджає акумулятор. Натисніть, щоб переглянути."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"Додаток <xliff:g id="APP">%1$s</xliff:g> довго працює у фоновому режимі. Натисніть, щоб переглянути."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Перевірте активні додатки"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 6c53d79..8636572 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -304,10 +304,8 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"اپنے کیلنڈر تک رسائی حاصل کریں"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS پیغامات بھیجیں اور دیکھیں"</string>
- <!-- no translation found for permgrouplab_storage (9173334109512154196) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (8352226729501080525) -->
- <skip />
+ <string name="permgrouplab_storage" msgid="9173334109512154196">"فائلز اور دستاویزات"</string>
+ <string name="permgroupdesc_storage" msgid="8352226729501080525">"آپ کے آلے پر فائلز اور دستاویزات تک رسائی حاصل کریں"</string>
<string name="permgrouplab_readMediaAural" msgid="5885210465560755316">"موسیقی اور دیگر آڈیو"</string>
<string name="permgroupdesc_readMediaAural" msgid="1170143315714662822">"آپ کے آلے پر آڈیو فائلز تک رسائی حاصل کریں"</string>
<string name="permgrouplab_readMediaVisual" msgid="9137695801926624061">"تصاویر اور ویڈیوز"</string>
@@ -588,8 +586,9 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"جاری رکھنے کے لیے اپنا اسکرین لاک درج کریں"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"جزوی فنگر پرنٹ کا پتہ چلا"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"فنگر پرنٹ پر کارروائی نہیں کی جا سکی۔ براہ کرم دوبارہ کوشش کریں۔"</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"سینسر صاف کریں"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"تھوڑی دیر دبائے رکھیں"</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"فنگر پرنٹ سینسر صاف کریں اور دوبارہ کوشش کریں"</string>
+ <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"سینسر صاف کریں اور دوبارہ کوشش کریں"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"سینسر پر اچھی طرح دبائیں"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"انگلی کو بہت آہستہ ہٹایا گیا۔ براہ کرم دوبارہ کوشش کریں۔"</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"دوسرا فنگر پرنٹ آزمائیں"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"کافی روشنی ہے"</string>
@@ -597,6 +596,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"ہر بار اپنی انگلی کی پوزیشن کو تھوڑا تبدیل کریں"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"فنگر پرنٹ کی شناخت نہیں ہو سکی"</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="4709197752023550709">"سینسر پر اچھی طرح دبائیں"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"فنگر پرنٹ کی تصدیق ہو گئی"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"چہرے کی تصدیق ہو گئی"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"چہرے کی تصدیق ہو گئی، براہ کرم \'تصدیق کریں\' کو دبائيں"</string>
@@ -1500,7 +1501,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"نظر انداز کریں"</string>
<string name="no_matches" msgid="6472699895759164599">"کوئی مماثلتیں نہیں ہیں"</string>
<string name="find_on_page" msgid="5400537367077438198">"صفحہ پر تلاش کریں"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# مماثل کریں}other{# میں سے {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"ہو گیا"</string>
<string name="progress_erasing" msgid="6891435992721028004">"اشتراک کردہ اسٹوریج کو صاف کیا جا رہا ہے…"</string>
<string name="share" msgid="4157615043345227321">"اشتراک کریں"</string>
@@ -1928,6 +1930,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"آن کریں"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ایپ دستیاب نہیں ہے"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ابھی دستیاب نہیں ہے۔"</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> دستیاب نہیں ہے"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"اس وقت آپ کے <xliff:g id="DEVICE">%1$s</xliff:g> پر اس تک رسائی نہیں مل سکتی۔ اس کے بجائے اپنے Android TV آلے پر کوشش کریں۔"</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"اس وقت آپ کے <xliff:g id="DEVICE">%1$s</xliff:g> پر اس تک رسائی نہیں مل سکتی۔ اس کے بجائے اپنے ٹیبلیٹ پر کوشش کریں۔"</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"اس وقت آپ کے <xliff:g id="DEVICE">%1$s</xliff:g> پر اس تک رسائی نہیں مل سکتی۔ اس کے بجائے اپنے فون پر کوشش کریں۔"</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"یہ ایپ Android کے پرانے ورژن کے لئے بنائی گئی ہے اور ہو سکتا ہے صحیح طور پر کام نہ کرے۔ اپ ڈیٹس چیک کر کے آزمائیں یا ڈویلپر سے رابطہ کریں۔"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"اپ ڈیٹ چیک کریں"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"آپ کے پاس نئے پیغامات ہیں"</string>
@@ -2017,16 +2023,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"اَن انسٹال کریں"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"بہر صورت کھولیں"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"ضرر رساں ایپ کا پتہ چلا"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"سسٹم لاگ تک رسائی کی درخواست"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"صرف اس وقت"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"اجازت نہ دیں"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"فنکشنل ڈیبگنگ کے لیے <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> سسٹم لاگز کی درخواست کر رہی ہے۔ ان لاگز میں آپ کے آلے پر موجود ایپس اور سروسز کی معلومات شامل ہو سکتی ہیں۔"</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"دوبارہ نہ دکھائیں"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> <xliff:g id="APP_2">%2$s</xliff:g> کے سلائسز دکھانا چاہتی ہے"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"ترمیم کریں"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"کالز اور اطلاعات پر وائبریٹ کرے گا"</string>
@@ -2119,10 +2120,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"آن کرنے کیلئے تھپتھپائیں"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"کوئی ورک ایپ نہیں"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"کوئی ذاتی ایپ نہیں"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"اپنی ذاتی پروفائل میں <xliff:g id="APP">%s</xliff:g> کھولیں؟"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"اپنی دفتری پروفائل میں <xliff:g id="APP">%s</xliff:g> کھولیں؟"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"ذاتی براؤزر استعمال کریں"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"ورک براؤزر استعمال کریں"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM نیٹ ورک غیر مقفل کرنے کا PIN"</string>
@@ -2257,4 +2256,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> پس منظر میں چل رہی ہے اور بیٹری ختم ہو رہی ہے۔ جائزے کے لیے تھپتھپائیں۔"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> کافی وقت سے پس منظر میں چل رہی ہے۔ جائزے کے لیے تھپتھپائیں۔"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"فعال ایپس چیک کریں"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index e57c7c8..e09f634 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Ekran qulfini kiritish bilan davom eting"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Barmoq izi qismi aniqlandi"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Barmoq izi aniqlanmadi. Qaytadan urining."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Sensorni tozalang"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Biroz koʻproq bosib turing"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Barmoq juda sekin harakatlandi. Qayta urinib ko‘ring."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Boshqa barmoq izi bilan urining"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Juda yorqin"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Barmoqni har safar biroz surib joylang"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Barmoq izi tekshirildi"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Yuzingiz aniqlandi"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Yuzingiz aniqlandi, tasdiqlash uchun bosing"</string>
@@ -909,7 +917,7 @@
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Qulfni ochish uchun \"Menyu\"ga bosing."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Qulfni ochish uchun grafik kalitni chizing"</string>
<string name="lockscreen_emergency_call" msgid="7549683825868928636">"Favqulodda chaqiruv"</string>
- <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Qo‘ng‘iroqni qaytarish"</string>
+ <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Chaqiruvga qaytish"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"To‘g‘ri!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Qaytadan urining"</string>
<string name="lockscreen_password_wrong" msgid="8605355913868947490">"Qaytadan urining"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Tashlab o‘tish"</string>
<string name="no_matches" msgid="6472699895759164599">"Topilmadi"</string>
<string name="find_on_page" msgid="5400537367077438198">"Sahifadan topish"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# ta natija}other{# / {total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Tayyor"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Umumiy xotira tozalanmoqda…"</string>
<string name="share" msgid="4157615043345227321">"Yuborish"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Yoqish"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Ilova ishlamayapti"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Ayni vaqtda <xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi ishlamayapti."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> kanali ish faoliyatida emas"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Ayni vaqtda bu translatsiya <xliff:g id="DEVICE">%1$s</xliff:g> qurilmangizda ishlamaydi. Android TV qurilmasi orqali urinib koʻring."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Ayni vaqtda bu translatsiya <xliff:g id="DEVICE">%1$s</xliff:g> qurilmangizda ishlamaydi. Planshet orqali urinib koʻring."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Ayni vaqtda bu translatsiya <xliff:g id="DEVICE">%1$s</xliff:g> qurilmangizda ishlamaydi. Telefon orqali urininb koʻring."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Bu ilova eskiroq Android versiyalariga chiqarilgan va xato ishlashi mumkin. Yangilanishlarini tekshiring yoki dasturchi bilan bog‘laning."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Yangilanish borligini tekshirish"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Sizga yangi SMS keldi"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"O‘CHIRIB TASHLASH"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"BARIBIR OCHILSIN"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Zararli ilova aniqlandi"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Tizim jurnaliga kirish soʻrovi"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Faqat shu safar"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Rad etish"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> funksional nosozliklarni tuzatish uchun tizim jurnallarini soʻramoqda. Bu jurnallarda qurilmangizdagi ilovalar va xizmatlar yozilgan maʼlumotlar boʻlishi mumkin."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Boshqa chiqmasin"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ilovasi <xliff:g id="APP_2">%2$s</xliff:g> ilovasidan fragmentlar ko‘rsatish uchun ruxsat so‘ramoqda"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Tahrirlash"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Chaqiruvlar va bildirishnomalar tebranadi"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Quvvat muloqot oynasi"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ekran qulfi"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skrinshot"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Garniturani osib qoʻyish"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Ekranda tezkor ishga tushirish"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Ekranda tezkor ishga tushirishni tanlagich"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Tezkor ishga tushirish"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Eslatma soyasini yopish"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Dpad – tepaga"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Dpad – pastga"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad – chapga"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad – oʻngga"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad – markazga"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> taglavhalar paneli."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> cheklangan turkumga joylandi"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Yoqish uchun bosing"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Ishga oid ilovalar topilmadi"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Shaxsiy ilovalar topilmadi"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"<xliff:g id="APP">%s</xliff:g> shaxsiy profilda ochilsinmi?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"<xliff:g id="APP">%s</xliff:g> shaxsiy profilda ochilsinmi?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Shaxsiy brauzerdan foydalanish"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Ishga oid brauzerdan foydalanish"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM kartaning tarmoqdagi qulfini ochish uchun PIN kod"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> orqa fonda ishlamoqda va batareyani ortiqcha sarflamoqda. Tekshirish uchun bosing."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> uzoq vaqt orqa fonda ishlamoqda. Tekshirish uchun bosing."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Faol ilovalarni tekshiring"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 067a12f..329f193 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Hãy nhập phương thức khóa màn hình của bạn để tiếp tục"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Phát hiện thấy một phần vân tay"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Không thể xử lý vân tay. Vui lòng thử lại."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Hãy vệ sinh cảm biến"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Hãy giữ tay lâu hơn một chút"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Di chuyển ngón tay quá chậm. Vui lòng thử lại."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Hãy thử một vân tay khác"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Quá sáng"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Mỗi lần, hãy thay đổi vị trí ngón tay một chút"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Đã xác thực vân tay"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Đã xác thực khuôn mặt"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Đã xác thực khuôn mặt, vui lòng nhấn để xác nhận"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Bỏ qua"</string>
<string name="no_matches" msgid="6472699895759164599">"Không có kết quả nào phù hợp"</string>
<string name="find_on_page" msgid="5400537367077438198">"Tìm kiếm trên trang"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# kết quả phù hợp}other{#/{total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Xong"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Đang xóa bộ nhớ dùng chung…"</string>
<string name="share" msgid="4157615043345227321">"Chia sẻ"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Bật"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Ứng dụng này không dùng được"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> hiện không dùng được."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"Không hỗ trợ <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Hiện tại, bạn không thể truy cập vào ứng dụng này trên <xliff:g id="DEVICE">%1$s</xliff:g>. Hãy thử trên thiết bị Android TV."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Hiện tại, bạn không thể truy cập vào ứng dụng này trên <xliff:g id="DEVICE">%1$s</xliff:g>. Hãy thử trên máy tính bảng."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Hiện tại, bạn không thể truy cập vào ứng dụng này trên <xliff:g id="DEVICE">%1$s</xliff:g>. Hãy thử trên điện thoại."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ứng dụng này được xây dựng cho một phiên bản Android cũ hơn và có thể hoạt động không bình thường. Hãy thử kiểm tra các bản cập nhật hoặc liên hệ với nhà phát triển."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Kiểm tra bản cập nhật"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Bạn có tin nhắn mới"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"GỠ CÀI ĐẶT"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"VẪN MỞ"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Đã phát hiện ứng dụng độc hại"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Yêu cầu truy cập vào nhật ký hệ thống"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Chỉ lần này"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Không cho phép"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> cần truy cập vào nhật ký hệ thống để gỡ lỗi về chức năng. Những nhật ký này có thể chứa thông tin mà ứng dụng và dịch vụ trên thiết bị của bạn đã ghi lại."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Không hiện lại"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> muốn hiển thị các lát của <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Chỉnh sửa"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Cuộc gọi và thông báo sẽ rung"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Hộp thoại thao tác với nguồn"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Khóa màn hình"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Chụp ảnh màn hình"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Giá treo tai nghe"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Phím tắt hỗ trợ tiếp cận trên màn hình"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Bộ chọn phím tắt hỗ trợ tiếp cận trên màn hình"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Phím tắt hỗ trợ tiếp cận"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Đóng Ngăn thông báo"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Chuyển lên trên bằng bàn phím di chuyển"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Chuyển xuống dưới bằng bàn phím di chuyển"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Chuyển sang trái bằng bàn phím di chuyển"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Chuyển sang phải bằng bàn phím di chuyển"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Căn giữa bằng bàn phím di chuyển"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Thanh phụ đề của <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Đã đưa <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> vào bộ chứa BỊ HẠN CHẾ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Nhấn để bật"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Không có ứng dụng công việc"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Không có ứng dụng cá nhân"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Mở <xliff:g id="APP">%s</xliff:g> trong hồ sơ cá nhân của bạn?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Mở <xliff:g id="APP">%s</xliff:g> trong hồ sơ công việc của bạn?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Dùng trình duyệt cá nhân"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Dùng trình duyệt công việc"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"Mã PIN mở khóa mạng SIM"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> đang chạy trong nền và làm tiêu hao pin. Nhấn để xem lại."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> đang chạy trong nền trong thời gian dài. Nhấn để xem lại."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Xem các ứng dụng đang hoạt động"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index ff1ed87..dbfef83 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"输入您的屏幕锁定凭据才能继续"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"检测到局部指纹"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"无法处理指纹,请重试。"</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"请将传感器擦干净"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"按久一点"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"手指移动太慢,请重试。"</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"请试试其他指纹"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"光线太亮"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"请在每次放手指时略微更改手指的位置"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"已验证指纹"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"面孔已验证"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"面孔已验证,请按确认按钮"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"跳过"</string>
<string name="no_matches" msgid="6472699895759164599">"无匹配项"</string>
<string name="find_on_page" msgid="5400537367077438198">"在网页上查找"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# 场比赛}other{# 场比赛(共 {total} 场)}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"完成"</string>
<string name="progress_erasing" msgid="6891435992721028004">"正在清空共享的存储空间…"</string>
<string name="share" msgid="4157615043345227321">"分享"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"开启"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"应用无法使用"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g>目前无法使用。"</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g>不可用"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"目前无法在您的<xliff:g id="DEVICE">%1$s</xliff:g>上访问此内容。您可以尝试在 Android TV 设备上访问。"</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"目前无法在您的<xliff:g id="DEVICE">%1$s</xliff:g>上访问此内容。您可以尝试在平板电脑上访问。"</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"目前无法在您的<xliff:g id="DEVICE">%1$s</xliff:g>上访问此内容。您可以尝试在手机上访问。"</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"此应用专为旧版 Android 打造,因此可能无法正常运行。请尝试检查更新或与开发者联系。"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"检查更新"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"您有新消息"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"卸载"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"仍然打开"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"检测到有害应用"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"系统日志访问请求"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"仅限这一次"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"不允许"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>请求访问系统日志,以进行功能调试。这些日志可能包含设备上的应用和服务写入的信息。"</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"不再显示"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"“<xliff:g id="APP_0">%1$s</xliff:g>”想要显示“<xliff:g id="APP_2">%2$s</xliff:g>”图块"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"编辑"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"有来电和通知时会振动"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"电源对话框"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"锁定屏幕"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"屏幕截图"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"耳机挂钩"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"屏幕上的无障碍功能快捷方式"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"屏幕上的无障碍功能快捷方式选择器"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"无障碍功能快捷方式"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"关闭通知栏"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"向上方向键"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"向下方向键"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"向左方向键"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"向右方向键"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"方向键中心"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>的标题栏。"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 已被放入受限存储分区"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"点按即可开启"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"没有支持该内容的工作应用"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"没有支持该内容的个人应用"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"要使用个人资料打开 <xliff:g id="APP">%s</xliff:g> 吗?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"要使用工作资料打开 <xliff:g id="APP">%s</xliff:g> 吗?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"使用个人浏览器"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"使用工作浏览器"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM 网络解锁 PIN 码"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> 正在后台运行,并且消耗了大量电池电量。点按即可查看。"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> 已在后台运行较长时间。点按即可查看。"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"查看使用中的应用"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 52ba4ef..c4fa7a0 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"如要繼續操作,請輸入螢幕鎖定解鎖憑證"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"只偵測到部分指紋"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"無法處理指紋。請再試一次。"</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"清潔感應器"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"請按住更長時間"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"手指移動太慢,請重試。"</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"改用其他指紋"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"太亮"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"每次掃瞄時請稍微變更手指的位置"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"驗證咗指紋"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"面孔已經驗證"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"面孔已經驗證,請㩒一下 [確認]"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"略過"</string>
<string name="no_matches" msgid="6472699895759164599">"沒有相符的結果"</string>
<string name="find_on_page" msgid="5400537367077438198">"在頁面中尋找"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# 個相符的項目}other{# 個相符的項目 (共 {total} 個)}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"完成"</string>
<string name="progress_erasing" msgid="6891435992721028004">"正在清除共用儲存空間資料…"</string>
<string name="share" msgid="4157615043345227321">"分享"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"開啟"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"無法使用應用程式"</string>
<string name="app_blocked_message" msgid="542972921087873023">"目前無法使用「<xliff:g id="APP_NAME">%1$s</xliff:g>」。"</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"無法使用「<xliff:g id="ACTIVITY">%1$s</xliff:g>」"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"目前無法在 <xliff:g id="DEVICE">%1$s</xliff:g> 上存取此應用程式,請改用 Android TV 裝置存取。"</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"目前無法在 <xliff:g id="DEVICE">%1$s</xliff:g> 上存取此應用程式,請改用平板電腦存取。"</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"目前無法在 <xliff:g id="DEVICE">%1$s</xliff:g> 上存取此應用程式,請改用手機存取。"</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"此應用程式專為舊版 Android 打造,因此可能無法正常運作。請嘗試檢查更新,或與開發人員聯絡。"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"檢查更新"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"您有新的訊息"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"解除安裝"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"仍要開啟"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"偵測到有害的應用程式"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"系統記錄存取要求"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"僅限這次"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"不允許"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"「<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>」需要系統記錄才能進行功能偵錯。這些記錄可能包含裝置上應用程式和服務寫入的資料。"</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"不要再顯示"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"「<xliff:g id="APP_0">%1$s</xliff:g>」想顯示「<xliff:g id="APP_2">%2$s</xliff:g>」的快訊"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"編輯"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"有來電和通知時會震動"</string>
@@ -2119,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"輕按即可啟用"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"沒有適用的工作應用程式"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"沒有適用的個人應用程式"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"要在個人設定檔中開啟「<xliff:g id="APP">%s</xliff:g>」嗎?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"要在工作設定檔中開啟「<xliff:g id="APP">%s</xliff:g>」嗎?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"使用個人瀏覽器"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"使用工作瀏覽器"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM 網絡解鎖 PIN"</string>
@@ -2257,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"<xliff:g id="APP">%1$s</xliff:g> 正在背景執行並大量耗電。輕按即可查看。"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"<xliff:g id="APP">%1$s</xliff:g> 已長時間在背景執行。輕按即可查看。"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"查看使用中的應用程式"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index cad12e3..843c751 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -588,8 +588,12 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"如要繼續操作,請輸入螢幕鎖定憑證"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"僅偵測到局部指紋"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"無法處理指紋,請再試一次。"</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"清潔感應器"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"按久一點"</string>
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1770676120848224250) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty_alt (9169582140486372897) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (1628459767349116104) -->
+ <skip />
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"手指移動速度過慢,請再試一次。"</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"改用其他指紋"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"太亮"</string>
@@ -597,6 +601,10 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"每次掃描時請稍微變更手指的位置"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_not_match (4599441812893438961) -->
+ <skip />
+ <!-- no translation found for fingerprint_udfps_error_not_match (4709197752023550709) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="2024862866860283100">"指紋驗證成功"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"臉孔驗證成功"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"臉孔驗證成功,請按下 [確認] 按鈕"</string>
@@ -1500,7 +1508,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"略過"</string>
<string name="no_matches" msgid="6472699895759164599">"沒有相符項目"</string>
<string name="find_on_page" msgid="5400537367077438198">"在頁面中尋找"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# 個相符的項目}other{# 個相符的項目 (共 {total} 個)}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"完成"</string>
<string name="progress_erasing" msgid="6891435992721028004">"正在清除共用儲存空間…"</string>
<string name="share" msgid="4157615043345227321">"分享"</string>
@@ -1928,6 +1937,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"開啟"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"應用程式無法使用"</string>
<string name="app_blocked_message" msgid="542972921087873023">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」目前無法使用。"</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"無法存取「<xliff:g id="ACTIVITY">%1$s</xliff:g>」"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"目前無法在 <xliff:g id="DEVICE">%1$s</xliff:g> 上存取這個應用程式,請改用 Android TV 裝置。"</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"目前無法在 <xliff:g id="DEVICE">%1$s</xliff:g> 上存取這個應用程式,請改用平板電腦。"</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"目前無法在 <xliff:g id="DEVICE">%1$s</xliff:g> 上存取這個應用程式,請改用手機。"</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"這個應用程式是專為舊版 Android 所打造,因此可能無法正常運作。請嘗試檢查更新,或是與開發人員聯絡。"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"檢查更新"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"你有新訊息"</string>
@@ -2017,16 +2030,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"解除安裝"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"仍要開啟"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"偵測到有害應用程式"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"系統記錄存取要求"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"僅允許這一次"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"不允許"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"「<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>」要求存取系統記錄以進行功能偵錯。這些記錄可能包含應用程式和服務在你裝置上寫入的資訊。"</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"不要再顯示"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"「<xliff:g id="APP_0">%1$s</xliff:g>」想要顯示「<xliff:g id="APP_2">%2$s</xliff:g>」的區塊"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"編輯"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"有來電和通知時會震動"</string>
@@ -2089,22 +2097,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"開啟電源對話方塊"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"螢幕鎖定"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"螢幕截圖"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"耳機掛鉤"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"螢幕上的無障礙捷徑"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"螢幕上的無障礙捷徑選擇器"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"無障礙捷徑"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"關閉通知欄"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Dpad 向上移"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Dpad 向下移"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad 向左移"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad 向右移"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad 置中"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」的說明文字列。"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"已將「<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>」移入受限制的值區"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2127,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"輕觸即可啟用"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"沒有適用的工作應用程式"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"沒有適用的個人應用程式"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"要在個人資料夾中開啟「<xliff:g id="APP">%s</xliff:g>」嗎?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"要在工作資料夾中開啟「<xliff:g id="APP">%s</xliff:g>」嗎?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"使用個人瀏覽器"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"使用工作瀏覽器"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM 卡網路解鎖 PIN 碼"</string>
@@ -2263,4 +2263,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"「<xliff:g id="APP">%1$s</xliff:g>」正在背景運作且耗用大量電力。輕觸即可查看。"</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"「<xliff:g id="APP">%1$s</xliff:g>」已長時間在背景運作。輕觸即可查看。"</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"查看使用中的應用程式"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 4b2387a..41cd8b0 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -304,10 +304,8 @@
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"finyelela kukhalenda yakho"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"I-SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"thumela uphinde ubuke imilayezo ye-SMS"</string>
- <!-- no translation found for permgrouplab_storage (9173334109512154196) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (8352226729501080525) -->
- <skip />
+ <string name="permgrouplab_storage" msgid="9173334109512154196">"Amafayela namadokhumenti"</string>
+ <string name="permgroupdesc_storage" msgid="8352226729501080525">"finyelela amafayela namadokhumenti kudivayisi yakho"</string>
<string name="permgrouplab_readMediaAural" msgid="5885210465560755316">"Umculo neminye imisindo"</string>
<string name="permgroupdesc_readMediaAural" msgid="1170143315714662822">"finyelela amafayela okulalelwayo edivayisini yakho"</string>
<string name="permgrouplab_readMediaVisual" msgid="9137695801926624061">"Izithombe namavidiyo"</string>
@@ -588,8 +586,9 @@
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Faka ukukhiya isikrini kwakho ukuze uqhubeke"</string>
<string name="fingerprint_acquired_partial" msgid="694598777291084823">"Kutholwe ingxenye yesigxivizo somunwe"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Ayikwazanga ukucubungula izigxivizo zeminwe. Sicela uzame futhi."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"Hlanza inzwa"</string>
- <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"Bamba isikhashana esingeziwe"</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Hlanza inzwa yesigxivizo somunwe bese uzame futhi"</string>
+ <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Hlanza inzwa bese uzame futhi"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Cindezela ngokuqinile kunzwa"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Umnwe uhanjiswe kancane kakhulu. Sicela uzame futhi."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Zama ezinye izigxivizo zeminwe"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Kukhanya kakhulu"</string>
@@ -597,6 +596,8 @@
<string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Shintsha indawo yomunwe wakho kancane isikhathi ngasinye"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
+ <string name="fingerprint_error_not_match" msgid="4599441812893438961">"Isigxivizo somunwe asaziwa"</string>
+ <string name="fingerprint_udfps_error_not_match" msgid="4709197752023550709">"Cindezela ngokuqinile kunzwa"</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Izigxivizo zeminwe zigunyaziwe"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Ubuso bufakazelwe ubuqiniso"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Ukuqinisekiswa kobuso, sicela ucindezele okuthi qinisekisa"</string>
@@ -1500,7 +1501,8 @@
<string name="skip_button_label" msgid="3566599811326688389">"Yeqa"</string>
<string name="no_matches" msgid="6472699895759164599">"Akukho okufanayo"</string>
<string name="find_on_page" msgid="5400537367077438198">"Thola ekhasini"</string>
- <string name="matches_found" msgid="7912910457231705587">"{count,plural, =1{# okufanayo}one{# kokungu-{total}}other{# kokungu-{total}}} }"</string>
+ <!-- no translation found for matches_found (2296462299979507689) -->
+ <skip />
<string name="action_mode_done" msgid="2536182504764803222">"Kwenziwe"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Isusa isitoreji esabiwe…"</string>
<string name="share" msgid="4157615043345227321">"Yabelana"</string>
@@ -1928,6 +1930,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Vula"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Uhlelo lokusebenza alutholakali"</string>
<string name="app_blocked_message" msgid="542972921087873023">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> ayitholakali khona manje."</string>
+ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"okungatholakali <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
+ <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Lokhu akukwazi ukufinyelelwa ku-<xliff:g id="DEVICE">%1$s</xliff:g> yakho ngalesi sikhathi. Zama kudivayisi yakho ye-Android TV kunalokho."</string>
+ <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Lokhu akukwazi ukufinyelelwa ku-<xliff:g id="DEVICE">%1$s</xliff:g> yakho ngalesi sikhathi. Zama kuthebhulethi yakho kunalokho."</string>
+ <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Lokhu akukwazi ukufinyelelwa ku-<xliff:g id="DEVICE">%1$s</xliff:g> yakho ngalesi sikhathi. Zama efonini yakho kunalokho."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Lolu hlelo lokusebenza belakhelwe inguqulo endala ye-Android futhi kungenzeka lungasebenzi kahle. Zama ukuhlolela izibuyekezo, noma uxhumane nonjiniyela."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Hlola izibuyekezo"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Unemilayezo emisha"</string>
@@ -2017,16 +2023,11 @@
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"KHIPHA"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"VULA NOMA KUNJALO"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Uhlelo lokusebenza oluyingozi lutholakele"</string>
- <!-- no translation found for log_access_confirmation_title (3143035474800851565) -->
- <skip />
- <!-- no translation found for log_access_confirmation_allow (143157286283302512) -->
- <skip />
- <!-- no translation found for log_access_confirmation_deny (7685790957455099845) -->
- <skip />
- <!-- no translation found for log_access_confirmation_body (7599059550906238538) -->
- <skip />
- <!-- no translation found for log_access_do_not_show_again (1058690599083091552) -->
- <skip />
+ <string name="log_access_confirmation_title" msgid="3143035474800851565">"Isicelo sokufinyelela ilogu yesistimu"</string>
+ <string name="log_access_confirmation_allow" msgid="143157286283302512">"Kulokhu kuphela"</string>
+ <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ungavumeli"</string>
+ <string name="log_access_confirmation_body" msgid="7599059550906238538">"I-<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> icela amalogu wesistimu ukuze alungise iphutha. Lawa malogu angase aqukathe ulwazi olubhalwe ama-app namasevisi kudivayisi yakho."</string>
+ <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ungabonisi futhi"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"I-<xliff:g id="APP_0">%1$s</xliff:g> ifuna ukubonisa izingcezu ze-<xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Hlela"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Amakholi nezaziso zizodlidliza"</string>
@@ -2089,22 +2090,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Ibhokisi lamandla"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Khiya isikrini"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Isithombe-skrini"</string>
- <!-- no translation found for accessibility_system_action_headset_hook_label (8524691721287425468) -->
- <skip />
+ <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Ihhuku yama-earphone"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Isinqamuleli sokufinyeleleka kusikrini"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Isikhethi sesinqamuleli sokufinyeleleka kusikrini"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Isinqamuleli sokufinyeleleka"</string>
<string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Cashisa Umthunzi Wesaziso"</string>
- <!-- no translation found for accessibility_system_action_dpad_up_label (1029042950229333782) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_down_label (3441918448624921461) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_left_label (6557647179116479152) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_right_label (9180196950365804081) -->
- <skip />
- <!-- no translation found for accessibility_system_action_dpad_center_label (8149791419358224893) -->
- <skip />
+ <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Phezulu kwe-Dpad"</string>
+ <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Phansi kwe-Dpad"</string>
+ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Ngakwesokunxele se-Dpad"</string>
+ <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Ngakwesokudla se-Dpad"</string>
+ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Isikhungo se-Dpad"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Ibha yamazwibela we-<xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"I-<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ifakwe kubhakede LOKUKHAWULELWE"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
@@ -2125,10 +2120,8 @@
<string name="resolver_switch_on_work" msgid="463709043650610420">"Thepha ukuze uvule"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Awekho ama-app womsebenzi"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Awekho ama-app womuntu siqu"</string>
- <!-- no translation found for miniresolver_open_in_personal (3874522693661065566) -->
- <skip />
- <!-- no translation found for miniresolver_open_in_work (4415223793669536559) -->
- <skip />
+ <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Vula i-<xliff:g id="APP">%s</xliff:g> kwiphrofayela yakho siqu?"</string>
+ <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Vula i-<xliff:g id="APP">%s</xliff:g> kwiphrofayela yakho yomsebenzi?"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Sebenzisa isiphequluli somuntu siqu"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Sebenzisa isiphequluli somsebenzi"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"Iphinikhodi yokuvula inethiwekhi ye-SIM"</string>
@@ -2263,4 +2256,6 @@
<string name="notification_content_abusive_bg_apps" msgid="5572096708044958249">"I-<xliff:g id="APP">%1$s</xliff:g> isebenza ngemuva futhi idla ibhethri. Thepha ukuze ubuyekeze."</string>
<string name="notification_content_long_running_fgs" msgid="8878031652441570178">"I-<xliff:g id="APP">%1$s</xliff:g> isebenza ngemuva isikhathi eside. Thepha ukuze ubuyekeze."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Hlola ama-app asebenzayo"</string>
+ <!-- no translation found for vdm_camera_access_denied (6345652513729130490) -->
+ <skip />
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 68ddbe6..fca2bd1 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3921,6 +3921,8 @@
<!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_MULTI_FINGER_GESTURES}. -->
<flag name="flagRequestMultiFingerGestures" value="0x00001000" />
<flag name="flagSendMotionEvents" value="0x0004000" />
+ <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_INPUT_METHOD_EDITOR}. -->
+ <flag name="flagInputMethodEditor" value="0x0008000" />
</attr>
<!-- Component name of an activity that allows the user to modify
the settings for this service. This setting cannot be changed at runtime. -->
@@ -3987,31 +3989,34 @@
<attr name="isAccessibilityTool" format="boolean" />
<!-- Animated image of the accessibility service purpose or behavior, to help users
- understand how the service can help them.-->
+ understand how the service can help them. -->
<attr name="animatedImageDrawable" format="reference"/>
- <!-- Html description of the accessibility service, to help users understand
- how the service can help them.-->
+ <!-- Html description of the accessibility service usage, availability, or limitations (e.g.
+ isn't supported by all apps). -->
<attr name="htmlDescription" format="reference"/>
-
- <!-- Short description of the accessibility service purpose or behavior.-->
+ <!-- Description of the accessibility service usage, availability, or limitations (e.g.
+ isn't supported by all apps). -->
<attr name="description" />
<!-- Brief summary of the accessibility service purpose or behavior. -->
<attr name="summary" />
+ <!-- Detailed intro of the accessibility service purpose or behavior. -->
+ <attr name="intro" format="reference" />
</declare-styleable>
<!-- Use <code>accessibility-shortcut-target</code> as the root tag of the XML resource that
describes an activity, which is referenced from the
<code>android.accessibilityshortcut.target</code> meta-data entry. -->
<declare-styleable name="AccessibilityShortcutTarget">
- <!-- Short description of the target of accessibility shortcut purpose or behavior.-->
+ <!-- Description of the target of accessibility shortcut usage, availability, or limitations
+ (e.g. isn't supported by all apps). -->
<attr name="description" />
<!-- Brief summary of the target of accessibility shortcut purpose or behavior. -->
<attr name="summary" />
<!-- Animated image of the target of accessibility shortcut purpose or behavior, to help
users understand how the target of accessibility shortcut can help them.-->
<attr name="animatedImageDrawable" format="reference"/>
- <!-- Html description of the target of accessibility shortcut purpose or behavior, to help
- users understand how the target of accessibility shortcut can help them. -->
+ <!-- Html description of the target of accessibility shortcut usage, availability, or
+ limitations (e.g. isn't supported by all apps). -->
<attr name="htmlDescription" format="reference"/>
<!-- Component name of an activity that allows the user to modify the settings for this
target of accessibility shortcut. -->
@@ -4021,6 +4026,8 @@
settings to remind users this accessibility service has a
{@link android.service.quicksettings.TileService}. -->
<attr name="tileService" format="string" />
+ <!-- Detailed intro of the target of accessibility shortcut purpose or behavior. -->
+ <attr name="intro" format="reference" />
</declare-styleable>
<!-- Use <code>print-service</code> as the root tag of the XML resource that
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index cb40e86..6dc975b 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1048,6 +1048,24 @@
<p>The default value of this attribute is <code>false</code>. -->
<attr name="allowEmbedded" format="boolean" />
+ <!-- A reference to an array resource containing the signing certificate digests, one of which a
+ client is required to be signed with in order to embed the activity. If the client is not
+ signed with one of the certificates in the set, and the activity does not allow embedding
+ by untrusted hosts via {@link android.R.attr#allowUntrustedActivityEmbedding} flag, the
+ embedding request will fail.
+ <p>The digest should be computed over the DER encoding of the trusted certificate using the
+ SHA-256 digest algorithm.
+ <p>If only a single signer is declared this can also be a string resource, or the digest
+ can be declared inline as the value for this attribute.
+ <p>If the attribute is declared both on the application and the activity level, the value
+ on the activity level takes precedence. -->
+ <attr name="knownActivityEmbeddingCerts" format="reference|string" />
+
+ <!-- Indicate that the activity can be embedded by untrusted hosts. In this case the
+ interactions and visibility of the embedded activity may be limited.
+ <p>The default value of this attribute is <code>false</code>. -->
+ <attr name="allowUntrustedActivityEmbedding" format="boolean" />
+
<!-- Specifies whether this {@link android.app.Activity} should be shown on
top of the lock screen whenever the lockscreen is up and this activity has another
activity behind it with the {@link android.R.attr#showWhenLocked} attribute set. That
@@ -2011,6 +2029,7 @@
when the application's user data is cleared. The default value is false.
-->
<attr name="resetEnabledSettingsOnAppDataCleared" format="boolean" />
+ <attr name="knownActivityEmbeddingCerts" />
</declare-styleable>
<!-- An attribution is a logical part of an app and is identified by a tag.
@@ -3033,6 +3052,8 @@
<!-- Indicates whether the activity can be displayed on a remote device which may or
may not be running Android. -->
<attr name="canDisplayOnRemoteDevices" format="boolean"/>
+ <attr name="allowUntrustedActivityEmbedding" />
+ <attr name="knownActivityEmbeddingCerts" />
</declare-styleable>
<!-- The <code>activity-alias</code> tag declares a new
@@ -3073,6 +3094,8 @@
<attr name="exported" />
<attr name="parentActivityName" />
<attr name="attributionTags" />
+ <attr name="allowUntrustedActivityEmbedding" />
+ <attr name="knownActivityEmbeddingCerts" />
</declare-styleable>
<!-- The <code>meta-data</code> tag is used to attach additional
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 6a86b1c..5e6d05a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1307,6 +1307,7 @@
<!-- Control the behavior when the user double-taps the home button.
0 - Nothing
1 - Recent apps view in SystemUI
+ 2 - Picture-in-picture menu
This needs to match the constants in
policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
-->
@@ -4082,6 +4083,16 @@
-->
<string name="config_defaultAmbientContextDetectionService" translatable="false"></string>
+ <!-- Component name that accepts ACTION_SEND intents for requesting ambient context consent. -->
+ <string translatable="false" name="config_defaultAmbientContextConsentComponent"></string>
+
+ <!-- Intent extra key for the caller's package name while requesting ambient context consent.
+ -->
+ <string translatable="false" name="config_ambientContextPackageNameExtraKey"></string>
+
+ <!-- Intent extra key for the event code int array while requesting ambient context consent. -->
+ <string translatable="false" name="config_ambientContextEventArrayExtraKey"></string>
+
<!-- The component name for the system-wide captions service.
This service must be trusted, as it controls part of the UI of the volume bar.
Example: "com.android.captions/.SystemCaptionsService"
@@ -4266,6 +4277,9 @@
<!-- URI for in call notification sound -->
<string translatable="false" name="config_inCallNotificationSound">/product/media/audio/ui/InCallNotification.ogg</string>
+ <!-- URI for camera shutter sound -->
+ <string translatable="false" name="config_cameraShutterSound">/product/media/audio/ui/camera_click.ogg</string>
+
<!-- URI for default ringtone sound file to be used for silent ringer vibration -->
<string translatable="false" name="config_defaultRingtoneVibrationSound"></string>
@@ -5687,4 +5701,92 @@
-->
<string-array name="config_dockExtconStateMapping">
</string-array>
+
+ <!-- Whether or not the monitoring on the apps' background battery drain is enabled -->
+ <bool name="config_bg_current_drain_monitor_enabled">true</bool>
+
+ <!-- The threshold of the background current drain (in percentage) to the restricted
+ standby bucket.
+ -->
+ <array name="config_bg_current_drain_threshold_to_restricted_bucket">
+ <item>2.0</item> <!-- regular device -->
+ <item>4.0</item> <!-- low ram device -->
+ </array>
+
+ <!-- The threshold of the background current drain (in percentage) to the background
+ restricted level.
+ -->
+ <array name="config_bg_current_drain_threshold_to_bg_restricted">
+ <item>4.0</item> <!-- regular device -->
+ <item>8.0</item> <!-- low ram device -->
+ </array>
+
+ <!-- The background current drain monitoring window size. -->
+ <integer name="config_bg_current_drain_window">86400</integer>
+
+ <!-- The types of battery drain we're checking on each app; if the sum of the battery drain
+ exceeds the threshold, it'll be moved to restricted standby bucket. The value must be
+ one of or combination of the definitions in AppBatteryPolicy.
+ -->
+ <integer name="config_bg_current_drain_types_to_restricted_bucket">4</integer>
+
+ <!-- The types of battery drain we're checking on each app; if the sum of the battery drain
+ exceeds the threshold, it'll be moved to background restricted level. The value must be
+ one of or combination of the definitions in AppBatteryPolicy.
+ -->
+ <integer name="config_bg_current_drain_types_to_bg_restricted">12</integer>
+
+ <!-- The power usage components we're monitoring. Must one of the definition in BatteryConsumer.
+ -->
+ <integer name="config_bg_current_drain_power_components">-1</integer>
+
+ <!-- Whether or not enable the different threshold based on the durations of
+ certain event type.
+ -->
+ <bool name="config_bg_current_drain_event_duration_based_threshold_enabled">false</bool>
+
+ <!-- The threshold of the background current drain (in percentage) to the restricted
+ standby bucket for legitimate case with higher background current drain.
+ -->
+ <array name="config_bg_current_drain_high_threshold_to_restricted_bucket">
+ <item>30.0</item> <!-- regular device -->
+ <item>60.0</item> <!-- low ram device -->
+ </array>
+
+ <!-- The threshold of the background current drain (in percentage) to the background
+ restricted level for legitimate case with higher background current drain.
+ -->
+ <array name="config_bg_current_drain_high_threshold_to_bg_restricted">
+ <item>20.0</item> <!-- regular device -->
+ <item>40.0</item> <!-- low ram device -->
+ </array>
+
+ <!-- The threshold of minimal time of hosting a foreground service with type "mediaPlayback"
+ or a media session, over the given window, so it'd subject towards the higher background
+ current drain threshold.
+ -->
+ <integer name="config_bg_current_drain_media_playback_min_duration">1800</integer>
+
+ <!-- The threshold of minimal time of hosting a foreground service with type "location"
+ over the given window, so it'd subject towards the higher background
+ current drain threshold.
+ -->
+ <integer name="config_bg_current_drain_location_min_duration">1800</integer>
+
+ <!-- The behavior for an app with a FGS and its notification is still showing, when the system
+ detects it's abusive and should be put into bg restricted level. True - we'll
+ show the prompt to user, False - we'll not show it.
+ -->
+ <bool name="config_bg_prompt_fgs_with_noti_to_bg_restricted">false</bool>
+
+ <!-- The types of state where we'll exempt its battery usage during that state.
+ The state here must be one or a combination of STATE_TYPE_* in BaseAppStateTracker.
+ -->
+ <integer name="config_bg_current_drain_exempted_types">9</integer>
+
+ <!-- The behavior when an app has the permission ACCESS_BACKGROUND_LOCATION granted,
+ whether or not the system will use a higher threshold towards its background battery usage
+ because of it.
+ -->
+ <bool name="config_bg_current_drain_high_threshold_by_bg_location">false</bool>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index cc63fd6..7bf34a1 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3276,6 +3276,9 @@
<public name="toExtendBottom" />
<public name="tileService" />
<public name="windowSplashScreenBehavior" />
+ <public name="allowUntrustedActivityEmbedding" />
+ <public name="knownActivityEmbeddingCerts" />
+ <public name="intro" />
</staging-public-group>
<staging-public-group type="id" first-id="0x01de0000">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 3e821f2..e41aa45 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4242,7 +4242,7 @@
match and total number of matches found in the current page. [CHAR LIMIT=NONE] -->
<string name="matches_found">{ count, plural,
=1 {# match}
- other {# of {total}}}
+ other {# of {total}}
}
</string>
@@ -6280,4 +6280,8 @@
</string>
<!-- Action label of notification for user to check background apps. [CHAR LIMIT=NONE] -->
<string name="notification_action_check_bg_apps">Check active apps</string>
+
+ <!-- Strings for VirtualDeviceManager -->
+ <!-- Error message indicating the camera cannot be accessed when running on a virtual device. [CHAR LIMIT=NONE] -->
+ <string name="vdm_camera_access_denied">Cannot access camera from this device</string>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a79eec2..ff1c70a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3699,6 +3699,9 @@
<java-symbol type="string" name="config_defaultSystemCaptionsService" />
<java-symbol type="string" name="config_defaultSystemCaptionsManagerService" />
<java-symbol type="string" name="config_defaultAmbientContextDetectionService" />
+ <java-symbol type="string" name="config_defaultAmbientContextConsentComponent" />
+ <java-symbol type="string" name="config_ambientContextPackageNameExtraKey" />
+ <java-symbol type="string" name="config_ambientContextEventArrayExtraKey" />
<java-symbol type="string" name="config_retailDemoPackage" />
<java-symbol type="string" name="config_retailDemoPackageSignature" />
@@ -3749,6 +3752,7 @@
<java-symbol type="bool" name="config_handleVolumeAliasesUsingVolumeGroups" />
<java-symbol type="dimen" name="config_inCallNotificationVolume" />
<java-symbol type="string" name="config_inCallNotificationSound" />
+ <java-symbol type="string" name="config_cameraShutterSound" />
<java-symbol type="integer" name="config_autoGroupAtCount" />
<java-symbol type="bool" name="config_dozeAlwaysOnDisplayAvailable" />
<java-symbol type="bool" name="config_dozeAlwaysOnEnabled" />
@@ -4729,5 +4733,24 @@
<java-symbol type="bool" name="config_lowPowerStandbyEnabledByDefault" />
<java-symbol type="integer" name="config_lowPowerStandbyNonInteractiveTimeout" />
+ <!-- For VirtualDeviceManager -->
+ <java-symbol type="string" name="vdm_camera_access_denied" />
+
<java-symbol type="color" name="camera_privacy_light"/>
+
+ <java-symbol type="bool" name="config_bg_current_drain_monitor_enabled" />
+ <java-symbol type="array" name="config_bg_current_drain_threshold_to_restricted_bucket" />
+ <java-symbol type="array" name="config_bg_current_drain_threshold_to_bg_restricted" />
+ <java-symbol type="integer" name="config_bg_current_drain_window" />
+ <java-symbol type="integer" name="config_bg_current_drain_types_to_restricted_bucket" />
+ <java-symbol type="integer" name="config_bg_current_drain_types_to_bg_restricted" />
+ <java-symbol type="integer" name="config_bg_current_drain_power_components" />
+ <java-symbol type="bool" name="config_bg_current_drain_event_duration_based_threshold_enabled" />
+ <java-symbol type="array" name="config_bg_current_drain_high_threshold_to_restricted_bucket" />
+ <java-symbol type="array" name="config_bg_current_drain_high_threshold_to_bg_restricted" />
+ <java-symbol type="integer" name="config_bg_current_drain_media_playback_min_duration" />
+ <java-symbol type="integer" name="config_bg_current_drain_location_min_duration" />
+ <java-symbol type="bool" name="config_bg_prompt_fgs_with_noti_to_bg_restricted" />
+ <java-symbol type="integer" name="config_bg_current_drain_exempted_types" />
+ <java-symbol type="bool" name="config_bg_current_drain_high_threshold_by_bg_location" />
</resources>
diff --git a/core/tests/coretests/res/values/strings.xml b/core/tests/coretests/res/values/strings.xml
index 21613a8..e51eab6 100644
--- a/core/tests/coretests/res/values/strings.xml
+++ b/core/tests/coretests/res/values/strings.xml
@@ -143,6 +143,9 @@
<!-- ResourcesLocaleResolutionTest -->
<string name="dummy_string">dummy string</string>
+ <!-- Intro of the accessibility shortcut [CHAR LIMIT=NONE] -->
+ <string name="accessibility_shortcut_intro">Accessibility shortcut intro</string>
+
<!-- Description of the accessibility shortcut [CHAR LIMIT=NONE] -->
<string name="accessibility_shortcut_description">Accessibility shortcut description</string>
diff --git a/core/tests/coretests/res/xml/accessibility_shortcut_test_activity.xml b/core/tests/coretests/res/xml/accessibility_shortcut_test_activity.xml
index 5fc536a..52fe65d 100644
--- a/core/tests/coretests/res/xml/accessibility_shortcut_test_activity.xml
+++ b/core/tests/coretests/res/xml/accessibility_shortcut_test_activity.xml
@@ -23,4 +23,4 @@
android:htmlDescription="@string/accessibility_shortcut_html_description"
android:settingsActivity="com.example.shortcut.target.SettingsActivity"
android:tileService="com.example.shortcut.target.TileService"
-/>
\ No newline at end of file
+ android:intro="@string/accessibility_shortcut_intro" />
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/accessibilityservice/AccessibilityShortcutInfoTest.java b/core/tests/coretests/src/android/accessibilityservice/AccessibilityShortcutInfoTest.java
index 76fb520..f605a00 100644
--- a/core/tests/coretests/src/android/accessibilityservice/AccessibilityShortcutInfoTest.java
+++ b/core/tests/coretests/src/android/accessibilityservice/AccessibilityShortcutInfoTest.java
@@ -89,6 +89,16 @@
}
@Test
+ public void testIntro() {
+ final String intro = mTargetContext.getResources()
+ .getString(R.string.accessibility_shortcut_intro);
+
+ assertNotNull("Can't find intro string", intro);
+ assertThat("Intro is not correct",
+ mShortcutInfo.loadIntro(mPackageManager), is(intro));
+ }
+
+ @Test
public void testAnimatedImageRes() {
assertThat("Animated image resource id is not correct",
mShortcutInfo.getAnimatedImageRes(), is(R.drawable.bitmap_drawable));
diff --git a/core/tests/coretests/src/android/app/activity/RegisterComponentCallbacksTest.java b/core/tests/coretests/src/android/app/activity/RegisterComponentCallbacksTest.java
new file mode 100644
index 0000000..c1b6666
--- /dev/null
+++ b/core/tests/coretests/src/android/app/activity/RegisterComponentCallbacksTest.java
@@ -0,0 +1,124 @@
+/*
+ * 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.app.activity;
+
+import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
+import static android.content.Context.OVERRIDABLE_COMPONENT_CALLBACKS;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
+
+import android.app.Activity;
+import android.app.WindowConfiguration;
+import android.app.activity.ActivityThreadTest.TestActivity;
+import android.compat.testing.PlatformCompatChangeRule;
+import android.content.ComponentCallbacks;
+import android.content.TestComponentCallbacks2;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.core.app.ActivityScenario;
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+
+/**
+ * Test for verifying {@link Activity#registerComponentCallbacks(ComponentCallbacks)} behavior.
+ * Build/Install/Run:
+ * atest FrameworksCoreTests:android.app.activity.RegisterComponentCallbacksTest
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class RegisterComponentCallbacksTest {
+ @Rule
+ public ActivityScenarioRule rule = new ActivityScenarioRule<>(TestActivity.class);
+ @Rule
+ public TestRule compatChangeRule = new PlatformCompatChangeRule();
+
+ @Test
+ public void testRegisterComponentCallbacks() {
+ final ActivityScenario scenario = rule.getScenario();
+ final TestComponentCallbacks2 callbacks = new TestComponentCallbacks2();
+ final Configuration config = new Configuration();
+ config.fontScale = 1.2f;
+ config.windowConfiguration.setWindowingMode(
+ WindowConfiguration.WINDOWING_MODE_FREEFORM);
+ config.windowConfiguration.setBounds(new Rect(0, 0, 100, 100));
+ final int trimMemoryLevel = TRIM_MEMORY_RUNNING_LOW;
+
+ scenario.onActivity(activity -> {
+ // It should be no-op to unregister a ComponentCallbacks without registration.
+ activity.unregisterComponentCallbacks(callbacks);
+
+ activity.registerComponentCallbacks(callbacks);
+ // Verify #onConfigurationChanged
+ activity.onConfigurationChanged(config);
+ assertThat(callbacks.mConfiguration).isEqualTo(config);
+ // Verify #onTrimMemory
+ activity.onTrimMemory(trimMemoryLevel);
+ assertThat(callbacks.mLevel).isEqualTo(trimMemoryLevel);
+ // verify #onLowMemory
+ activity.onLowMemory();
+ assertThat(callbacks.mLowMemoryCalled).isTrue();
+
+ activity.unregisterComponentCallbacks(callbacks);
+ });
+ }
+
+ @DisableCompatChanges(OVERRIDABLE_COMPONENT_CALLBACKS)
+ @Test
+ public void testRegisterComponentCallbacksBeforeT() {
+ final ActivityScenario scenario = rule.getScenario();
+ final TestComponentCallbacks2 callbacks = new TestComponentCallbacks2();
+ final Configuration config = new Configuration();
+ config.fontScale = 1.2f;
+ config.windowConfiguration.setWindowingMode(
+ WindowConfiguration.WINDOWING_MODE_FREEFORM);
+ config.windowConfiguration.setBounds(new Rect(0, 0, 100, 100));
+ final int trimMemoryLevel = TRIM_MEMORY_RUNNING_LOW;
+
+ scenario.onActivity(activity -> {
+ // It should be no-op to unregister a ComponentCallbacks without registration.
+ activity.unregisterComponentCallbacks(callbacks);
+
+ activity.registerComponentCallbacks(callbacks);
+ // Verify #onConfigurationChanged
+ activity.onConfigurationChanged(config);
+ assertWithMessage("The ComponentCallbacks must be added to #getApplicationContext "
+ + "before T.").that(callbacks.mConfiguration).isNull();
+ // Verify #onTrimMemory
+ activity.onTrimMemory(trimMemoryLevel);
+ assertWithMessage("The ComponentCallbacks must be added to #getApplicationContext "
+ + "before T.").that(callbacks.mLevel).isEqualTo(0);
+ // verify #onLowMemory
+ activity.onLowMemory();
+ assertWithMessage("The ComponentCallbacks must be added to #getApplicationContext "
+ + "before T.").that(callbacks.mLowMemoryCalled).isFalse();
+
+ activity.unregisterComponentCallbacks(callbacks);
+ });
+ }
+}
diff --git a/core/tests/coretests/src/android/app/timedetector/TelephonyTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/TelephonyTimeSuggestionTest.java
index 4b64dfc..cc75579 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 @@
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 @@
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 @@
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/companion/virtual/audio/VirtualAudioSessionTest.java b/core/tests/coretests/src/android/companion/virtual/audio/VirtualAudioSessionTest.java
new file mode 100644
index 0000000..d66cb71
--- /dev/null
+++ b/core/tests/coretests/src/android/companion/virtual/audio/VirtualAudioSessionTest.java
@@ -0,0 +1,182 @@
+/*
+ * 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.companion.virtual.audio;
+
+import static android.media.AudioFormat.CHANNEL_IN_MONO;
+import static android.media.AudioFormat.CHANNEL_OUT_MONO;
+import static android.media.AudioFormat.ENCODING_PCM_16BIT;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.verify;
+import static org.testng.Assert.assertThrows;
+
+import android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChangeCallback;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.media.AudioFormat;
+import android.media.AudioPlaybackConfiguration;
+import android.media.AudioRecordingConfiguration;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class VirtualAudioSessionTest {
+
+ @Rule
+ public final MockitoRule mockito = MockitoJUnit.rule();
+ @Mock
+ private AudioConfigurationChangeCallback mCallback;
+ private static final int APP_UID = 100;
+ private static final int APP_UID2 = 200;
+ private static final AudioFormat AUDIO_CAPTURE_FORMAT =
+ new AudioFormat.Builder()
+ .setSampleRate(48000)
+ .setEncoding(ENCODING_PCM_16BIT)
+ .setChannelMask(CHANNEL_IN_MONO)
+ .build();
+ private static final AudioFormat AUDIO_INJECT_FORMAT =
+ new AudioFormat.Builder()
+ .setSampleRate(48000)
+ .setEncoding(ENCODING_PCM_16BIT)
+ .setChannelMask(CHANNEL_OUT_MONO)
+ .build();
+ private Context mContext;
+ private VirtualAudioSession mVirtualAudioSession;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = Mockito.spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
+ mVirtualAudioSession = new VirtualAudioSession(
+ mContext, mCallback, /* executor= */ null);
+ }
+
+ @Test
+ public void startAudioCapture_isSuccessful() {
+ AudioCapture audioCapture = mVirtualAudioSession.startAudioCapture(AUDIO_CAPTURE_FORMAT);
+
+ assertThat(audioCapture).isNotNull();
+ assertThat(mVirtualAudioSession.getAudioCapture()).isEqualTo(audioCapture);
+ }
+
+ @Test
+ public void startAudioCapture_audioCaptureAlreadyStarted_throws() {
+ mVirtualAudioSession.startAudioCapture(AUDIO_CAPTURE_FORMAT);
+
+ assertThrows(IllegalStateException.class,
+ () -> mVirtualAudioSession.startAudioCapture(AUDIO_CAPTURE_FORMAT));
+ }
+
+ @Test
+ public void startAudioInjection_isSuccessful() {
+ AudioInjection audioInjection = mVirtualAudioSession.startAudioInjection(
+ AUDIO_INJECT_FORMAT);
+
+ assertThat(audioInjection).isNotNull();
+ assertThat(mVirtualAudioSession.getAudioInjection()).isEqualTo(audioInjection);
+ }
+
+ @Test
+ public void startAudioInjection_audioInjectionAlreadyStarted_throws() {
+ mVirtualAudioSession.startAudioInjection(AUDIO_INJECT_FORMAT);
+
+ assertThrows(IllegalStateException.class,
+ () -> mVirtualAudioSession.startAudioInjection(AUDIO_INJECT_FORMAT));
+ }
+
+ @Test
+ public void onAppsNeedingAudioRoutingChanged_neverStartAudioCaptureOrInjection_throws() {
+ int[] uids = new int[]{APP_UID};
+
+ assertThrows(IllegalStateException.class,
+ () -> mVirtualAudioSession.onAppsNeedingAudioRoutingChanged(uids));
+ }
+
+ @Test
+ public void onAppsNeedingAudioRoutingChanged_cachesReroutedApps() {
+ mVirtualAudioSession.startAudioCapture(AUDIO_CAPTURE_FORMAT);
+ mVirtualAudioSession.startAudioInjection(AUDIO_INJECT_FORMAT);
+ int[] appUids = new int[]{APP_UID};
+
+ mVirtualAudioSession.onAppsNeedingAudioRoutingChanged(appUids);
+
+ assertThat(Arrays.equals(mVirtualAudioSession.getReroutedAppUids().toArray(),
+ appUids)).isTrue();
+ }
+
+ @Test
+ public void onAppsNeedingAudioRoutingChanged_receiveManyTimes_reroutedAppsSizeIsCorrect() {
+ mVirtualAudioSession.startAudioCapture(AUDIO_CAPTURE_FORMAT);
+ mVirtualAudioSession.startAudioInjection(AUDIO_INJECT_FORMAT);
+ int[] appUids = new int[]{APP_UID, APP_UID2};
+
+ mVirtualAudioSession.onAppsNeedingAudioRoutingChanged(new int[]{1234});
+ mVirtualAudioSession.onAppsNeedingAudioRoutingChanged(new int[]{5678});
+ mVirtualAudioSession.onAppsNeedingAudioRoutingChanged(appUids);
+
+ assertThat(Arrays.equals(mVirtualAudioSession.getReroutedAppUids().toArray(),
+ appUids)).isTrue();
+ assertThat(mVirtualAudioSession.getReroutedAppUids().size()).isEqualTo(2);
+ }
+
+ @Test
+ public void close_releasesCaptureAndInjection() {
+ mVirtualAudioSession.startAudioCapture(AUDIO_CAPTURE_FORMAT);
+ mVirtualAudioSession.startAudioInjection(AUDIO_INJECT_FORMAT);
+
+ mVirtualAudioSession.close();
+
+ assertThat(mVirtualAudioSession.getAudioCapture()).isNull();
+ assertThat(mVirtualAudioSession.getAudioInjection()).isNull();
+ }
+
+ @Test
+ public void onPlaybackConfigChanged_sendsCallback() {
+ List<AudioPlaybackConfiguration> configs = new ArrayList<>();
+
+ mVirtualAudioSession.onPlaybackConfigChanged(configs);
+
+ verify(mCallback).onPlaybackConfigChanged(configs);
+ }
+
+ @Test
+ public void onRecordingConfigChanged_sendCallback() {
+ List<AudioRecordingConfiguration> configs = new ArrayList<>();
+
+ mVirtualAudioSession.onRecordingConfigChanged(configs);
+
+ verify(mCallback).onRecordingConfigChanged(configs);
+ }
+}
diff --git a/core/tests/coretests/src/android/content/ContextWrapperTest.java b/core/tests/coretests/src/android/content/ContextWrapperTest.java
index ecaf1f4..4957702 100644
--- a/core/tests/coretests/src/android/content/ContextWrapperTest.java
+++ b/core/tests/coretests/src/android/content/ContextWrapperTest.java
@@ -16,7 +16,7 @@
package android.content;
-import static android.content.ContextWrapper.COMPONENT_CALLBACK_ON_WRAPPER;
+import static android.content.Context.OVERRIDABLE_COMPONENT_CALLBACKS;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
@@ -61,7 +61,7 @@
* register {@link ComponentCallbacks} to {@link ContextWrapper#getApplicationContext} before
* {@link ContextWrapper#attachBaseContext(Context)}.
*/
- @DisableCompatChanges(COMPONENT_CALLBACK_ON_WRAPPER)
+ @DisableCompatChanges(OVERRIDABLE_COMPONENT_CALLBACKS)
@Test
public void testRegisterComponentCallbacksWithoutBaseContextBeforeT() {
final ContextWrapper wrapper = new TestContextWrapper(null /* base */);
diff --git a/core/tests/coretests/src/android/content/OWNERS b/core/tests/coretests/src/android/content/OWNERS
index 0b94589..a69c6ff 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/content/TestComponentCallbacks2.java b/core/tests/coretests/src/android/content/TestComponentCallbacks2.java
index 6ae7fc4..5c8787a 100644
--- a/core/tests/coretests/src/android/content/TestComponentCallbacks2.java
+++ b/core/tests/coretests/src/android/content/TestComponentCallbacks2.java
@@ -20,10 +20,10 @@
import androidx.annotation.NonNull;
-class TestComponentCallbacks2 implements ComponentCallbacks2 {
- android.content.res.Configuration mConfiguration;
- boolean mLowMemoryCalled;
- int mLevel;
+public class TestComponentCallbacks2 implements ComponentCallbacks2 {
+ public Configuration mConfiguration = null;
+ public boolean mLowMemoryCalled = false;
+ public int mLevel = 0;
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
diff --git a/core/tests/coretests/src/android/content/integrity/AtomicFormulaTest.java b/core/tests/coretests/src/android/content/integrity/AtomicFormulaTest.java
index 7af96c3..36072c3 100644
--- a/core/tests/coretests/src/android/content/integrity/AtomicFormulaTest.java
+++ b/core/tests/coretests/src/android/content/integrity/AtomicFormulaTest.java
@@ -104,6 +104,17 @@
}
@Test
+ public void testValidAtomicFormula_stringValue_appCertificateLineageIsNotAutoHashed() {
+ String appCert = "cert";
+ StringAtomicFormula stringAtomicFormula =
+ new StringAtomicFormula(AtomicFormula.APP_CERTIFICATE_LINEAGE, appCert);
+
+ assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.APP_CERTIFICATE_LINEAGE);
+ assertThat(stringAtomicFormula.getValue()).matches(appCert);
+ assertThat(stringAtomicFormula.getIsHashedValue()).isTrue();
+ }
+
+ @Test
public void testValidAtomicFormula_stringValue_installerCertificateIsNotAutoHashed() {
String installerCert = "cert";
StringAtomicFormula stringAtomicFormula =
@@ -285,6 +296,34 @@
}
@Test
+ public void testFormulaMatches_string_multipleAppCertificateLineage_true() {
+ StringAtomicFormula stringAtomicFormula =
+ new StringAtomicFormula(
+ AtomicFormula.APP_CERTIFICATE_LINEAGE, "cert", /* isHashedValue= */ true);
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder()
+ .setPackageName("com.test.app")
+ .setAppCertificateLineage(Arrays.asList("test-cert", "cert"))
+ .build();
+
+ assertThat(stringAtomicFormula.matches(appInstallMetadata)).isTrue();
+ }
+
+ @Test
+ public void testFormulaMatches_string_multipleAppCertificateLineage_false() {
+ StringAtomicFormula stringAtomicFormula =
+ new StringAtomicFormula(
+ AtomicFormula.APP_CERTIFICATE_LINEAGE, "cert", /* isHashedValue= */ true);
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder()
+ .setPackageName("com.test.app")
+ .setAppCertificateLineage(Arrays.asList("test-cert", "another-cert"))
+ .build();
+
+ assertThat(stringAtomicFormula.matches(appInstallMetadata)).isFalse();
+ }
+
+ @Test
public void testFormulaMatches_string_multipleInstallerCertificates_true() {
StringAtomicFormula stringAtomicFormula =
new StringAtomicFormula(
@@ -324,6 +363,15 @@
}
@Test
+ public void testIsAppCertificateLineageFormula_string_true() {
+ StringAtomicFormula stringAtomicFormula =
+ new StringAtomicFormula(
+ AtomicFormula.APP_CERTIFICATE_LINEAGE, "cert", /* isHashedValue= */false);
+
+ assertThat(stringAtomicFormula.isAppCertificateLineageFormula()).isTrue();
+ }
+
+ @Test
public void testIsAppCertificateFormula_string_false() {
StringAtomicFormula stringAtomicFormula =
new StringAtomicFormula(
@@ -334,6 +382,16 @@
}
@Test
+ public void testIsAppCertificateLineageFormula_string_false() {
+ StringAtomicFormula stringAtomicFormula =
+ new StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME, "com.test.app", /* isHashedValue= */
+ false);
+
+ assertThat(stringAtomicFormula.isAppCertificateLineageFormula()).isFalse();
+ }
+
+ @Test
public void testIsInstallerFormula_string_false() {
StringAtomicFormula stringAtomicFormula =
new StringAtomicFormula(
@@ -442,6 +500,15 @@
}
@Test
+ public void testIsAppCertificateLineageFormula_long_false() {
+ LongAtomicFormula longAtomicFormula =
+ new AtomicFormula.LongAtomicFormula(
+ AtomicFormula.VERSION_CODE, AtomicFormula.GTE, 1);
+
+ assertThat(longAtomicFormula.isAppCertificateLineageFormula()).isFalse();
+ }
+
+ @Test
public void testIsInstallerFormula_long_false() {
LongAtomicFormula longAtomicFormula =
new LongAtomicFormula(
@@ -479,6 +546,14 @@
}
@Test
+ public void testIsAppCertificateLineageFormula_bool_false() {
+ BooleanAtomicFormula boolFormula =
+ new BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true);
+
+ assertThat(boolFormula.isAppCertificateLineageFormula()).isFalse();
+ }
+
+ @Test
public void testIsInstallerFormula_bool_false() {
BooleanAtomicFormula boolFormula =
new BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true);
@@ -491,6 +566,7 @@
return new AppInstallMetadata.Builder()
.setPackageName("abc")
.setAppCertificates(Collections.singletonList("abc"))
+ .setAppCertificateLineage(Collections.singletonList("abc"))
.setInstallerCertificates(Collections.singletonList("abc"))
.setInstallerName("abc")
.setVersionCode(-1)
diff --git a/core/tests/coretests/src/android/content/integrity/CompoundFormulaTest.java b/core/tests/coretests/src/android/content/integrity/CompoundFormulaTest.java
index 593e70e..a202efb 100644
--- a/core/tests/coretests/src/android/content/integrity/CompoundFormulaTest.java
+++ b/core/tests/coretests/src/android/content/integrity/CompoundFormulaTest.java
@@ -249,6 +249,28 @@
}
@Test
+ public void testIsAppCertificateLineageFormula_false() {
+ CompoundFormula compoundFormula =
+ new CompoundFormula(
+ CompoundFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
+
+ assertThat(compoundFormula.isAppCertificateLineageFormula()).isFalse();
+ }
+
+ @Test
+ public void testIsAppCertificateLineageFormula_true() {
+ AtomicFormula appCertFormula =
+ new AtomicFormula.StringAtomicFormula(AtomicFormula.APP_CERTIFICATE_LINEAGE,
+ "app.cert", /* isHashed= */false);
+ CompoundFormula compoundFormula =
+ new CompoundFormula(
+ CompoundFormula.AND,
+ Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2, appCertFormula));
+
+ assertThat(compoundFormula.isAppCertificateLineageFormula()).isTrue();
+ }
+
+ @Test
public void testIsInstallerFormula_false() {
CompoundFormula compoundFormula =
new CompoundFormula(
@@ -288,6 +310,7 @@
return new AppInstallMetadata.Builder()
.setPackageName("abc")
.setAppCertificates(Collections.singletonList("abc"))
+ .setAppCertificateLineage(Collections.singletonList("abc"))
.setInstallerCertificates(Collections.singletonList("abc"))
.setInstallerName("abc")
.setVersionCode(-1)
diff --git a/core/tests/coretests/src/android/content/integrity/InstallerAllowedByManifestFormulaTest.java b/core/tests/coretests/src/android/content/integrity/InstallerAllowedByManifestFormulaTest.java
index 70712e4..54acb1e 100644
--- a/core/tests/coretests/src/android/content/integrity/InstallerAllowedByManifestFormulaTest.java
+++ b/core/tests/coretests/src/android/content/integrity/InstallerAllowedByManifestFormulaTest.java
@@ -32,8 +32,8 @@
@RunWith(JUnit4.class)
public class InstallerAllowedByManifestFormulaTest {
- private static final InstallerAllowedByManifestFormula
- FORMULA = new InstallerAllowedByManifestFormula();
+ private static final InstallerAllowedByManifestFormula FORMULA =
+ new InstallerAllowedByManifestFormula();
@Test
public void testFormulaMatches_installerAndCertBothInManifest() {
@@ -115,6 +115,7 @@
return new AppInstallMetadata.Builder()
.setPackageName("abc")
.setAppCertificates(Collections.emptyList())
+ .setAppCertificateLineage(Collections.emptyList())
.setInstallerCertificates(Collections.emptyList())
.setInstallerName("abc")
.setVersionCode(-1)
diff --git a/core/tests/coretests/src/android/content/integrity/IntegrityFormulaTest.java b/core/tests/coretests/src/android/content/integrity/IntegrityFormulaTest.java
index 7e4c138..9058a71 100644
--- a/core/tests/coretests/src/android/content/integrity/IntegrityFormulaTest.java
+++ b/core/tests/coretests/src/android/content/integrity/IntegrityFormulaTest.java
@@ -54,6 +54,20 @@
}
@Test
+ public void createEqualsFormula_appCertificateLineage() {
+ String appCertificate = "com.test.app";
+ IntegrityFormula formula =
+ IntegrityFormula.Application.certificateLineageContains(appCertificate);
+
+ AtomicFormula.StringAtomicFormula stringAtomicFormula =
+ (AtomicFormula.StringAtomicFormula) formula;
+
+ assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.APP_CERTIFICATE_LINEAGE);
+ assertThat(stringAtomicFormula.getValue()).matches(appCertificate);
+ assertThat(stringAtomicFormula.getIsHashedValue()).isTrue();
+ }
+
+ @Test
public void createEqualsFormula_installerName() {
String installerName = "com.test.app";
IntegrityFormula formula = IntegrityFormula.Installer.packageNameEquals(installerName);
@@ -138,8 +152,10 @@
IntegrityFormula formula1 = IntegrityFormula.Application.packageNameEquals(packageName);
IntegrityFormula formula2 =
IntegrityFormula.Application.certificatesContain(certificateName);
+ IntegrityFormula formula3 =
+ IntegrityFormula.Application.certificateLineageContains(certificateName);
- IntegrityFormula compoundFormula = IntegrityFormula.all(formula1, formula2);
+ IntegrityFormula compoundFormula = IntegrityFormula.all(formula1, formula2, formula3);
assertThat(compoundFormula.getTag()).isEqualTo(COMPOUND_FORMULA_TAG);
}
@@ -151,8 +167,10 @@
IntegrityFormula formula1 = IntegrityFormula.Application.packageNameEquals(packageName);
IntegrityFormula formula2 =
IntegrityFormula.Application.certificatesContain(certificateName);
+ IntegrityFormula formula3 =
+ IntegrityFormula.Application.certificateLineageContains(certificateName);
- IntegrityFormula compoundFormula = IntegrityFormula.any(formula1, formula2);
+ IntegrityFormula compoundFormula = IntegrityFormula.any(formula1, formula2, formula3);
assertThat(compoundFormula.getTag()).isEqualTo(COMPOUND_FORMULA_TAG);
}
diff --git a/core/tests/coretests/src/android/util/RotationUtilsTest.java b/core/tests/coretests/src/android/util/RotationUtilsTest.java
index 5dbe03e..826eb30 100644
--- a/core/tests/coretests/src/android/util/RotationUtilsTest.java
+++ b/core/tests/coretests/src/android/util/RotationUtilsTest.java
@@ -17,12 +17,14 @@
package android.util;
import static android.util.RotationUtils.rotateBounds;
+import static android.util.RotationUtils.rotatePoint;
import static android.view.Surface.ROTATION_180;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
import static org.junit.Assert.assertEquals;
+import android.graphics.Point;
import android.graphics.Rect;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -58,4 +60,23 @@
rotateBounds(testResult, testParent, ROTATION_270);
assertEquals(new Rect(520, 40, 580, 120), testResult);
}
+
+ @Test
+ public void testRotatePoint() {
+ int parentW = 1000;
+ int parentH = 600;
+ Point testPt = new Point(60, 40);
+
+ Point testResult = new Point(testPt);
+ rotatePoint(testResult, ROTATION_90, parentW, parentH);
+ assertEquals(new Point(40, 940), testResult);
+
+ testResult.set(testPt.x, testPt.y);
+ rotatePoint(testResult, ROTATION_180, parentW, parentH);
+ assertEquals(new Point(940, 560), testResult);
+
+ testResult.set(testPt.x, testPt.y);
+ rotatePoint(testResult, ROTATION_270, parentW, parentH);
+ assertEquals(new Point(560, 60), testResult);
+ }
}
diff --git a/core/tests/coretests/src/android/view/stylus/HandwritableViewInfoTest.java b/core/tests/coretests/src/android/view/stylus/HandwritableViewInfoTest.java
new file mode 100644
index 0000000..4bea54b
--- /dev/null
+++ b/core/tests/coretests/src/android/view/stylus/HandwritableViewInfoTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.view.stylus;
+
+import static android.view.stylus.HandwritingTestUtil.createView;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+import android.view.HandwritingInitiator;
+import android.view.View;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class HandwritableViewInfoTest {
+
+ @Test
+ public void constructorTest() {
+ final Rect rect = new Rect(1, 2, 3, 4);
+ final View view = createView(rect);
+ final HandwritingInitiator.HandwritableViewInfo handwritableViewInfo =
+ new HandwritingInitiator.HandwritableViewInfo(view);
+
+ assertThat(handwritableViewInfo.getView()).isEqualTo(view);
+ // It's labeled dirty by default.
+ assertTrue(handwritableViewInfo.mIsDirty);
+ }
+
+ @Test
+ public void update() {
+ final Rect rect = new Rect(1, 2, 3, 4);
+ final View view = createView(rect);
+ final HandwritingInitiator.HandwritableViewInfo handwritableViewInfo =
+ new HandwritingInitiator.HandwritableViewInfo(view);
+
+ assertThat(handwritableViewInfo.getView()).isEqualTo(view);
+
+ final boolean isViewInfoValid = handwritableViewInfo.update();
+
+ assertTrue(isViewInfoValid);
+ assertThat(handwritableViewInfo.getHandwritingArea()).isEqualTo(rect);
+ assertFalse(handwritableViewInfo.mIsDirty);
+ }
+
+ @Test
+ public void update_viewDisableAutoHandwriting() {
+ final Rect rect = new Rect(1, 2, 3, 4);
+ final View view = HandwritingTestUtil.createView(rect, false /* autoHandwritingEnabled */);
+ final HandwritingInitiator.HandwritableViewInfo handwritableViewInfo =
+ new HandwritingInitiator.HandwritableViewInfo(view);
+
+ assertThat(handwritableViewInfo.getView()).isEqualTo(view);
+
+ final boolean isViewInfoValid = handwritableViewInfo.update();
+
+ // Return false because the view disabled autoHandwriting.
+ assertFalse(isViewInfoValid);
+ // The view disabled the autoHandwriting, and it won't update the handwriting area.
+ assertThat(handwritableViewInfo.getHandwritingArea()).isNull();
+ }
+
+}
diff --git a/core/tests/coretests/src/android/view/stylus/HandwritingAreaTrackerTest.java b/core/tests/coretests/src/android/view/stylus/HandwritingAreaTrackerTest.java
new file mode 100644
index 0000000..db4707a
--- /dev/null
+++ b/core/tests/coretests/src/android/view/stylus/HandwritingAreaTrackerTest.java
@@ -0,0 +1,149 @@
+/*
+ * 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.view.stylus;
+
+import static android.view.stylus.HandwritingTestUtil.createView;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+import android.view.HandwritingInitiator;
+import android.view.View;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+
+/**
+ * Tests for {@link HandwritingInitiator.HandwritingAreaTracker}
+ *
+ * Build/Install/Run:
+ * atest FrameworksCoreTests:android.view.stylus.HandwritingAreaTrackerTest
+ */
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class HandwritingAreaTrackerTest {
+ HandwritingInitiator.HandwritingAreaTracker mHandwritingAreaTracker;
+ Context mContext;
+
+ @Before
+ public void setup() {
+ final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mContext = mInstrumentation.getTargetContext();
+ mHandwritingAreaTracker = new HandwritingInitiator.HandwritingAreaTracker();
+ }
+
+ @Test
+ public void updateHandwritingAreaForView_singleView() {
+ Rect rect = new Rect(0, 0, 100, 100);
+ View view = createView(rect);
+ mHandwritingAreaTracker.updateHandwritingAreaForView(view);
+
+ List<HandwritingInitiator.HandwritableViewInfo> viewInfos =
+ mHandwritingAreaTracker.computeViewInfos();
+
+ assertThat(viewInfos.size()).isEqualTo(1);
+ assertThat(viewInfos.get(0).getHandwritingArea()).isEqualTo(rect);
+ assertThat(viewInfos.get(0).getView()).isEqualTo(view);
+ }
+
+ @Test
+ public void updateHandwritingAreaForView_multipleViews() {
+ Rect rect1 = new Rect(0, 0, 100, 100);
+ Rect rect2 = new Rect(100, 100, 200, 200);
+
+ View view1 = createView(rect1);
+ View view2 = createView(rect2);
+ mHandwritingAreaTracker.updateHandwritingAreaForView(view1);
+ mHandwritingAreaTracker.updateHandwritingAreaForView(view2);
+
+ List<HandwritingInitiator.HandwritableViewInfo> viewInfos =
+ mHandwritingAreaTracker.computeViewInfos();
+
+ assertThat(viewInfos.size()).isEqualTo(2);
+ assertThat(viewInfos.get(0).getView()).isEqualTo(view1);
+ assertThat(viewInfos.get(0).getHandwritingArea()).isEqualTo(rect1);
+
+ assertThat(viewInfos.get(1).getView()).isEqualTo(view2);
+ assertThat(viewInfos.get(1).getHandwritingArea()).isEqualTo(rect2);
+ }
+
+ @Test
+ public void updateHandwritingAreaForView_afterDisableAutoHandwriting() {
+ Rect rect1 = new Rect(0, 0, 100, 100);
+ Rect rect2 = new Rect(100, 100, 200, 200);
+
+ View view1 = createView(rect1);
+ View view2 = createView(rect2);
+ mHandwritingAreaTracker.updateHandwritingAreaForView(view1);
+ mHandwritingAreaTracker.updateHandwritingAreaForView(view2);
+
+ // There should be 2 views tracked.
+ assertThat(mHandwritingAreaTracker.computeViewInfos().size()).isEqualTo(2);
+
+ // Disable autoHandwriting for view1 and update handwriting area.
+ view1.setAutoHandwritingEnabled(false);
+ mHandwritingAreaTracker.updateHandwritingAreaForView(view1);
+
+ List<HandwritingInitiator.HandwritableViewInfo> viewInfos =
+ mHandwritingAreaTracker.computeViewInfos();
+ // The view1 has disabled the autoHandwriting, it's not tracked anymore.
+ assertThat(viewInfos.size()).isEqualTo(1);
+
+ // view2 is still tracked.
+ assertThat(viewInfos.get(0).getView()).isEqualTo(view2);
+ assertThat(viewInfos.get(0).getHandwritingArea()).isEqualTo(rect2);
+ }
+
+ @Test
+ public void updateHandwritingAreaForView_removesInactiveView() {
+ Rect rect1 = new Rect(0, 0, 100, 100);
+ Rect rect2 = new Rect(100, 100, 200, 200);
+
+ View view1 = createView(rect1);
+ View view2 = createView(rect2);
+ mHandwritingAreaTracker.updateHandwritingAreaForView(view1);
+ mHandwritingAreaTracker.updateHandwritingAreaForView(view2);
+
+ // There should be 2 viewInfos tracked.
+ assertThat(mHandwritingAreaTracker.computeViewInfos().size()).isEqualTo(2);
+
+ // Disable autoHandwriting for view1, but update handwriting area for view2.
+ view1.setAutoHandwritingEnabled(false);
+ mHandwritingAreaTracker.updateHandwritingAreaForView(view2);
+
+ List<HandwritingInitiator.HandwritableViewInfo> viewInfos =
+ mHandwritingAreaTracker.computeViewInfos();
+ // The view1 has disabled the autoHandwriting, it's not tracked anymore.
+ assertThat(viewInfos.size()).isEqualTo(1);
+
+ // view2 is still tracked.
+ assertThat(viewInfos.get(0).getView()).isEqualTo(view2);
+ assertThat(viewInfos.get(0).getHandwritingArea()).isEqualTo(rect2);
+ }
+}
diff --git a/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java b/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
index e11fe17..1ae9649 100644
--- a/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
+++ b/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
@@ -19,6 +19,7 @@
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_UP;
+import static android.view.stylus.HandwritingTestUtil.createView;
import static com.google.common.truth.Truth.assertThat;
@@ -38,7 +39,6 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
-import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -78,7 +78,8 @@
mHandwritingInitiator =
spy(new HandwritingInitiator(viewConfiguration, inputMethodManager));
- mTestView = createMockView(sHwArea, true);
+ mTestView = createView(sHwArea, true);
+ mHandwritingInitiator.updateHandwritingAreasForView(mTestView);
}
@Test
@@ -195,8 +196,25 @@
}
@Test
+ public void onTouchEvent_focusView_stylusMoveOnce_withinHWArea() {
+ final int x1 = (sHwArea.left + sHwArea.right) / 2;
+ final int y1 = (sHwArea.top + sHwArea.bottom) / 2;
+ MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
+ mHandwritingInitiator.onTouchEvent(stylusEvent1);
+
+ final int x2 = x1 + TOUCH_SLOP * 2;
+ final int y2 = y1;
+
+ MotionEvent stylusEvent2 = createStylusEvent(ACTION_MOVE, x2, y2, 0);
+ mHandwritingInitiator.onTouchEvent(stylusEvent2);
+
+ // HandwritingInitiator will request focus for the registered view.
+ verify(mTestView, times(1)).requestFocus();
+ }
+
+ @Test
public void autoHandwriting_whenDisabled_wontStartHW() {
- View mockView = createMockView(sHwArea, false);
+ View mockView = createView(sHwArea, false);
mHandwritingInitiator.onInputConnectionCreated(mockView);
final int x1 = (sHwArea.left + sHwArea.right) / 2;
final int y1 = (sHwArea.top + sHwArea.bottom) / 2;
@@ -273,25 +291,4 @@
1 /* yPrecision */, 0 /* deviceId */, 0 /* edgeFlags */,
InputDevice.SOURCE_TOUCHSCREEN, 0 /* flags */);
}
-
- private View createMockView(Rect viewBound, boolean autoHandwritingEnabled) {
- // mock a parent so that HandwritingInitiator can get
- ViewGroup parent = new ViewGroup(mContext) {
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- // We don't layout this view.
- }
- @Override
- public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
- r.set(viewBound);
- return true;
- }
- };
-
- View mockView = mock(View.class);
- when(mockView.isAttachedToWindow()).thenReturn(true);
- when(mockView.isAutoHandwritingEnabled()).thenReturn(autoHandwritingEnabled);
- parent.addView(mockView);
- return mockView;
- }
}
diff --git a/core/tests/coretests/src/android/view/stylus/HandwritingTestUtil.java b/core/tests/coretests/src/android/view/stylus/HandwritingTestUtil.java
new file mode 100644
index 0000000..6daf880
--- /dev/null
+++ b/core/tests/coretests/src/android/view/stylus/HandwritingTestUtil.java
@@ -0,0 +1,59 @@
+/*
+ * 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.view.stylus;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.graphics.Rect;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+public class HandwritingTestUtil {
+ public static View createView(Rect handwritingArea) {
+ return createView(handwritingArea, true);
+ }
+
+ public static View createView(Rect handwritingArea, boolean autoHandwritingEnabled) {
+ final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ final Context context = instrumentation.getTargetContext();
+ // mock a parent so that HandwritingInitiator can get
+ final ViewGroup parent = new ViewGroup(context) {
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ // We don't layout this view.
+ }
+ @Override
+ public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
+ r.set(handwritingArea);
+ return true;
+ }
+ };
+
+ View view = spy(new View(context));
+ when(view.isAttachedToWindow()).thenReturn(true);
+ when(view.isAggregatedVisible()).thenReturn(true);
+ when(view.getHandwritingArea()).thenReturn(handwritingArea);
+ view.setAutoHandwritingEnabled(autoHandwritingEnabled);
+ parent.addView(view);
+ return view;
+ }
+}
diff --git a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
index a1a1e20..1f2bcfb 100644
--- a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
+++ b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
@@ -83,8 +83,10 @@
mDispatcher.registerOnBackInvokedCallback(
mCallback2, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
- verify(mWindowSession, times(2))
- .setOnBackInvokedCallback(Mockito.eq(mWindow), captor.capture());
+ verify(mWindowSession, times(2)).setOnBackInvokedCallback(
+ Mockito.eq(mWindow),
+ captor.capture(),
+ Mockito.eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT));
captor.getAllValues().get(0).onBackStarted();
waitForIdle();
verify(mCallback1).onBackStarted();
@@ -106,8 +108,9 @@
mDispatcher.registerOnBackInvokedCallback(
mCallback2, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
- verify(mWindowSession)
- .setOnBackInvokedCallback(Mockito.eq(mWindow), captor.capture());
+ verify(mWindowSession).setOnBackInvokedCallback(
+ Mockito.eq(mWindow), captor.capture(),
+ Mockito.eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY));
verifyNoMoreInteractions(mWindowSession);
captor.getValue().onBackStarted();
waitForIdle();
@@ -126,7 +129,10 @@
verifyZeroInteractions(mWindowSession);
mDispatcher.unregisterOnBackInvokedCallback(mCallback2);
- verify(mWindowSession).setOnBackInvokedCallback(Mockito.eq(mWindow), isNull());
+ verify(mWindowSession).setOnBackInvokedCallback(
+ Mockito.eq(mWindow),
+ isNull(),
+ Mockito.eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT));
}
@@ -145,8 +151,10 @@
reset(mWindowSession);
mDispatcher.registerOnBackInvokedCallback(
mCallback2, OnBackInvokedDispatcher.PRIORITY_OVERLAY);
- verify(mWindowSession)
- .setOnBackInvokedCallback(Mockito.eq(mWindow), captor.capture());
+ verify(mWindowSession).setOnBackInvokedCallback(
+ Mockito.eq(mWindow),
+ captor.capture(),
+ Mockito.eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY));
captor.getValue().onBackStarted();
waitForIdle();
verify(mCallback2).onBackStarted();
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java
deleted file mode 100644
index 260b65a..0000000
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * Copyright (C) 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 com.android.internal.os;
-
-import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.BatteryStats;
-import android.os.Process;
-import android.text.format.DateUtils;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import junit.framework.TestCase;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class BatteryStatsHelperTest extends TestCase {
- private static final long TIME_FOREGROUND_ACTIVITY_ZERO = 0;
- private static final long TIME_FOREGROUND_ACTIVITY = 100 * DateUtils.MINUTE_IN_MILLIS * 1000;
- private static final long TIME_STATE_FOREGROUND_MS = 10 * DateUtils.MINUTE_IN_MILLIS;
- private static final long TIME_STATE_FOREGROUND_US = TIME_STATE_FOREGROUND_MS * 1000;
-
- private static final int UID = 123456;
- private static final double BATTERY_SCREEN_USAGE = 300;
- private static final double BATTERY_SYSTEM_USAGE = 600;
- private static final double BATTERY_WIFI_USAGE = 200;
- private static final double BATTERY_IDLE_USAGE = 600;
- private static final double BATTERY_BLUETOOTH_USAGE = 300;
- private static final double BATTERY_OVERACCOUNTED_USAGE = 500;
- private static final double BATTERY_UNACCOUNTED_USAGE = 700;
- private static final double BATTERY_APP_USAGE = 100;
- private static final double TOTAL_BATTERY_USAGE = 1000;
- private static final double PRECISION = 0.001;
-
- @Mock
- private BatteryStats.Uid mUid;
- @Mock
- private BatterySipper mWifiBatterySipper;
- @Mock
- private BatterySipper mBluetoothBatterySipper;
- @Mock
- private BatterySipper mIdleBatterySipper;
- @Mock
- private BatterySipper mNormalBatterySipper;
- @Mock
- private BatterySipper mScreenBatterySipper;
- @Mock
- private BatterySipper mOvercountedBatterySipper;
- @Mock
- private BatterySipper mUnaccountedBatterySipper;
- @Mock
- private BatterySipper mSystemBatterySipper;
- @Mock
- private BatterySipper mCellBatterySipper;
- @Mock
- private PackageManager mPackageManager;
-
- private BatteryStatsHelper mBatteryStatsHelper;
- private Context mContext;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
- mNormalBatterySipper.totalPowerMah = TOTAL_BATTERY_USAGE;
- when(mNormalBatterySipper.getUid()).thenReturn(UID);
- mNormalBatterySipper.uidObj = mUid;
-
-
- mScreenBatterySipper.drainType = BatterySipper.DrainType.SCREEN;
- mScreenBatterySipper.totalPowerMah = BATTERY_SCREEN_USAGE;
-
- mSystemBatterySipper.drainType = BatterySipper.DrainType.APP;
- mSystemBatterySipper.totalPowerMah = BATTERY_SYSTEM_USAGE;
- mSystemBatterySipper.uidObj = mUid;
- when(mSystemBatterySipper.getUid()).thenReturn(Process.SYSTEM_UID);
-
- mOvercountedBatterySipper.drainType = BatterySipper.DrainType.OVERCOUNTED;
- mOvercountedBatterySipper.totalPowerMah = BATTERY_OVERACCOUNTED_USAGE;
-
- mUnaccountedBatterySipper.drainType = BatterySipper.DrainType.UNACCOUNTED;
- mUnaccountedBatterySipper.totalPowerMah = BATTERY_UNACCOUNTED_USAGE;
-
- mWifiBatterySipper.drainType = BatterySipper.DrainType.WIFI;
- mWifiBatterySipper.totalPowerMah = BATTERY_WIFI_USAGE;
-
- mBluetoothBatterySipper.drainType = BatterySipper.DrainType.BLUETOOTH;
- mBluetoothBatterySipper.totalPowerMah = BATTERY_BLUETOOTH_USAGE;
-
- mIdleBatterySipper.drainType = BatterySipper.DrainType.IDLE;
- mIdleBatterySipper.totalPowerMah = BATTERY_IDLE_USAGE;
-
- mContext = InstrumentationRegistry.getContext();
- mBatteryStatsHelper = spy(new BatteryStatsHelper(mContext));
- mBatteryStatsHelper.setPackageManager(mPackageManager);
- }
-
- @Test
- public void testShouldHideSipper_TypeUnAccounted_ReturnTrue() {
- mNormalBatterySipper.drainType = BatterySipper.DrainType.UNACCOUNTED;
- assertThat(mBatteryStatsHelper.shouldHideSipper(mNormalBatterySipper)).isTrue();
- }
-
- @Test
- public void testShouldHideSipper_TypeOverAccounted_ReturnTrue() {
- mNormalBatterySipper.drainType = BatterySipper.DrainType.OVERCOUNTED;
- assertThat(mBatteryStatsHelper.shouldHideSipper(mNormalBatterySipper)).isTrue();
- }
-
- @Test
- public void testShouldHideSipper_TypeIdle_ReturnTrue() {
- mNormalBatterySipper.drainType = BatterySipper.DrainType.IDLE;
- assertThat(mBatteryStatsHelper.shouldHideSipper(mNormalBatterySipper)).isTrue();
- }
-
- @Test
- public void testShouldHideSipper_TypeCell_ReturnTrue() {
- mNormalBatterySipper.drainType = BatterySipper.DrainType.CELL;
- assertThat(mBatteryStatsHelper.shouldHideSipper(mNormalBatterySipper)).isTrue();
- }
-
- @Test
- public void testShouldHideSipper_TypeScreen_ReturnTrue() {
- mNormalBatterySipper.drainType = BatterySipper.DrainType.SCREEN;
- assertThat(mBatteryStatsHelper.shouldHideSipper(mNormalBatterySipper)).isTrue();
- }
-
- @Test
- public void testShouldHideSipper_TypeSystem_ReturnTrue() {
- mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
- when(mNormalBatterySipper.getUid()).thenReturn(Process.ROOT_UID);
- assertThat(mBatteryStatsHelper.shouldHideSipper(mNormalBatterySipper)).isTrue();
- }
-
- @Test
- public void testShouldHideSipper_UidNormal_ReturnFalse() {
- mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
- assertThat(mBatteryStatsHelper.shouldHideSipper(mNormalBatterySipper)).isFalse();
- }
-
- @Test
- public void testRemoveHiddenBatterySippers_ContainsHiddenSippers_RemoveAndReturnValue() {
- final List<BatterySipper> sippers = new ArrayList<>();
- sippers.add(mNormalBatterySipper);
- sippers.add(mScreenBatterySipper);
- sippers.add(mSystemBatterySipper);
- sippers.add(mOvercountedBatterySipper);
- sippers.add(mUnaccountedBatterySipper);
- sippers.add(mWifiBatterySipper);
- sippers.add(mBluetoothBatterySipper);
- sippers.add(mIdleBatterySipper);
- doReturn(true).when(mBatteryStatsHelper).isTypeSystem(mSystemBatterySipper);
-
- final double totalUsage = mBatteryStatsHelper.removeHiddenBatterySippers(sippers);
-
- assertThat(mNormalBatterySipper.shouldHide).isFalse();
- assertThat(mScreenBatterySipper.shouldHide).isTrue();
- assertThat(mSystemBatterySipper.shouldHide).isTrue();
- assertThat(mOvercountedBatterySipper.shouldHide).isTrue();
- assertThat(mUnaccountedBatterySipper.shouldHide).isTrue();
- assertThat(totalUsage).isWithin(PRECISION).of(BATTERY_SYSTEM_USAGE);
- }
-
- @Test
- public void testSmearScreenBatterySipper() {
- final ScreenPowerCalculator spc = spy(ScreenPowerCalculator.class);
- final BatterySipper sipperNull = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY_ZERO,
- BATTERY_APP_USAGE, 0 /* uid */, true /* isUidNull */, spc);
- final BatterySipper sipperBg = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY_ZERO,
- BATTERY_APP_USAGE, 1 /* uid */, false /* isUidNull */, spc);
- final BatterySipper sipperFg = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY,
- BATTERY_APP_USAGE, 2 /* uid */, false /* isUidNull */, spc);
-
- final List<BatterySipper> sippers = new ArrayList<>();
- sippers.add(sipperNull);
- sippers.add(sipperBg);
- sippers.add(sipperFg);
-
- spc.smearScreenBatterySipper(sippers, mScreenBatterySipper, 0);
-
- assertThat(sipperNull.screenPowerMah).isWithin(PRECISION).of(0);
- assertThat(sipperBg.screenPowerMah).isWithin(PRECISION).of(0);
- assertThat(sipperFg.screenPowerMah).isWithin(PRECISION).of(BATTERY_SCREEN_USAGE);
- }
-
- @Test
- public void testIsTypeSystem_systemPackage_returnTrue() {
- final String[] systemPackages = {"com.android.system"};
- mBatteryStatsHelper.setSystemPackageArray(systemPackages);
- doReturn(UID).when(mNormalBatterySipper).getUid();
- doReturn(systemPackages).when(mPackageManager).getPackagesForUid(UID);
-
- assertThat(mBatteryStatsHelper.isTypeSystem(mNormalBatterySipper)).isTrue();
- }
-
- @Test
- public void testIsTypeService_servicePackage_returnTrue() {
- final String[] servicePackages = {"com.android.service"};
- mBatteryStatsHelper.setServicePackageArray(servicePackages);
- doReturn(UID).when(mNormalBatterySipper).getUid();
- doReturn(servicePackages).when(mPackageManager).getPackagesForUid(UID);
-
- assertThat(mBatteryStatsHelper.isTypeService(mNormalBatterySipper)).isTrue();
- }
-
- @Test
- public void testGetProcessForegroundTimeMs_largerActivityTime_returnMinTime() {
- final ScreenPowerCalculator spc = spy(ScreenPowerCalculator.class);
- doReturn(TIME_STATE_FOREGROUND_US + 500).when(spc)
- .getForegroundActivityTotalTimeUs(eq(mUid), anyLong());
- doReturn(TIME_STATE_FOREGROUND_US).when(mUid).getProcessStateTime(eq(PROCESS_STATE_TOP),
- anyLong(), anyInt());
-
- final long time = spc.getProcessForegroundTimeMs(mUid, 1000);
-
- assertThat(time).isEqualTo(TIME_STATE_FOREGROUND_MS);
- }
-
- private BatterySipper createTestSmearBatterySipper(long activityTime, double totalPowerMah,
- int uidCode, boolean isUidNull, ScreenPowerCalculator spc) {
- final BatterySipper sipper = mock(BatterySipper.class);
- sipper.drainType = BatterySipper.DrainType.APP;
- sipper.totalPowerMah = totalPowerMah;
- doReturn(uidCode).when(sipper).getUid();
- if (!isUidNull) {
- final BatteryStats.Uid uid = mock(BatteryStats.Uid.class, RETURNS_DEEP_STUBS);
- doReturn(activityTime).when(spc).getProcessForegroundTimeMs(eq(uid), anyLong());
- doReturn(uidCode).when(uid).getUid();
- sipper.uidObj = uid;
- }
-
- return sipper;
- }
-
-}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
index be8045d..d9b98a5 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
@@ -41,6 +41,7 @@
import android.bluetooth.UidTraffic;
import android.os.BatteryStats;
import android.os.BluetoothBatteryStats;
+import android.os.Parcel;
import android.os.WakeLockStats;
import android.os.WorkSource;
import android.util.SparseArray;
@@ -583,11 +584,42 @@
mBatteryStatsImpl.noteBluetoothScanStoppedFromSourceLocked(ws, true, 9000, 9000);
mBatteryStatsImpl.noteBluetoothScanResultsFromSourceLocked(ws, 42, 9000, 9000);
- BluetoothActivityEnergyInfo info = new BluetoothActivityEnergyInfo(1000,
- BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE, 9000, 8000, 12000, 0);
- info.setUidTraffic(ImmutableList.of(
- new UidTraffic(10042, 3000, 4000),
- new UidTraffic(10043, 5000, 8000)));
+
+
+ final Parcel uidTrafficParcel1 = Parcel.obtain();
+ final Parcel uidTrafficParcel2 = Parcel.obtain();
+
+ uidTrafficParcel1.writeInt(10042);
+ uidTrafficParcel1.writeLong(3000);
+ uidTrafficParcel1.writeLong(4000);
+ uidTrafficParcel1.setDataPosition(0);
+ uidTrafficParcel2.writeInt(10043);
+ uidTrafficParcel2.writeLong(5000);
+ uidTrafficParcel2.writeLong(8000);
+ uidTrafficParcel2.setDataPosition(0);
+
+ List<UidTraffic> uidTrafficList = ImmutableList.of(
+ UidTraffic.CREATOR.createFromParcel(uidTrafficParcel1),
+ UidTraffic.CREATOR.createFromParcel(uidTrafficParcel2));
+
+ final Parcel btActivityEnergyInfoParcel = Parcel.obtain();
+ btActivityEnergyInfoParcel.writeLong(1000);
+ btActivityEnergyInfoParcel.writeInt(
+ BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE);
+ btActivityEnergyInfoParcel.writeLong(9000);
+ btActivityEnergyInfoParcel.writeLong(8000);
+ btActivityEnergyInfoParcel.writeLong(12000);
+ btActivityEnergyInfoParcel.writeLong(0);
+ btActivityEnergyInfoParcel.writeTypedList(uidTrafficList);
+ btActivityEnergyInfoParcel.setDataPosition(0);
+
+ BluetoothActivityEnergyInfo info = BluetoothActivityEnergyInfo.CREATOR
+ .createFromParcel(btActivityEnergyInfoParcel);
+
+ uidTrafficParcel1.recycle();
+ uidTrafficParcel2.recycle();
+ btActivityEnergyInfoParcel.recycle();
+
mBatteryStatsImpl.updateBluetoothStateLocked(info, -1, 1000, 1000);
BluetoothBatteryStats stats =
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
index 92c2d43..ace39fb 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -30,7 +30,6 @@
BatteryStatsCounterTest.class,
BatteryStatsDualTimerTest.class,
BatteryStatsDurationTimerTest.class,
- BatteryStatsHelperTest.class,
BatteryStatsHistoryIteratorTest.class,
BatteryStatsHistoryTest.class,
BatteryStatsImplTest.class,
@@ -69,7 +68,6 @@
LongSamplingCounterTest.class,
LongSamplingCounterArrayTest.class,
MobileRadioPowerCalculatorTest.class,
- PowerCalculatorTest.class,
PowerProfileTest.class,
ScreenPowerCalculatorTest.class,
SensorPowerCalculatorTest.class,
diff --git a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
index ed035e5..448f666 100644
--- a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
@@ -24,6 +24,7 @@
import android.os.BatteryConsumer;
import android.os.BatteryStats;
import android.os.BatteryUsageStatsQuery;
+import android.os.Parcel;
import android.os.Process;
import android.os.UidBatteryConsumer;
import android.os.WorkSource;
@@ -37,6 +38,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.List;
+
@RunWith(AndroidJUnit4.class)
@SmallTest
@SuppressWarnings("GuardedBy")
@@ -90,11 +93,13 @@
uid.setProcessStateForTest(
BatteryStats.Uid.PROCESS_STATE_FOREGROUND, 1000);
- BluetoothActivityEnergyInfo info1 = new BluetoothActivityEnergyInfo(2000,
- BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE, 1000, 2000, 3000, 4000);
- info1.setUidTraffic(ImmutableList.of(
- new UidTraffic(Process.BLUETOOTH_UID, 1000, 2000),
- new UidTraffic(APP_UID, 3000, 4000)));
+
+ List<UidTraffic> trafficList1 = ImmutableList.of(
+ createUidTraffic(Process.BLUETOOTH_UID, 1000, 2000),
+ createUidTraffic(APP_UID, 3000, 4000));
+ BluetoothActivityEnergyInfo info1 = createBtEnergyInfo(2000,
+ BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE, 1000, 2000, 3000, 4000,
+ trafficList1);
batteryStats.updateBluetoothStateLocked(info1,
0/*1_000_000*/, 2000, 2000);
@@ -102,11 +107,14 @@
uid.setProcessStateForTest(
BatteryStats.Uid.PROCESS_STATE_BACKGROUND, 3000);
- BluetoothActivityEnergyInfo info2 = new BluetoothActivityEnergyInfo(4000,
- BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE, 5000, 6000, 7000, 8000);
- info2.setUidTraffic(ImmutableList.of(
- new UidTraffic(Process.BLUETOOTH_UID, 5000, 6000),
- new UidTraffic(APP_UID, 7000, 8000)));
+
+ List<UidTraffic> trafficList2 = ImmutableList.of(
+ createUidTraffic(Process.BLUETOOTH_UID, 5000, 6000),
+ createUidTraffic(APP_UID, 7000, 8000));
+ BluetoothActivityEnergyInfo info2 = createBtEnergyInfo(4000,
+ BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE, 5000, 6000, 7000, 8000,
+ trafficList2);
+
batteryStats.updateBluetoothStateLocked(info2,
0 /*5_000_000 */, 4000, 4000);
@@ -202,11 +210,14 @@
uid.setProcessStateForTest(
BatteryStats.Uid.PROCESS_STATE_FOREGROUND, 1000);
- BluetoothActivityEnergyInfo info1 = new BluetoothActivityEnergyInfo(2000,
- BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE, 1000, 2000, 3000, 4000);
- info1.setUidTraffic(ImmutableList.of(
- new UidTraffic(Process.BLUETOOTH_UID, 1000, 2000),
- new UidTraffic(APP_UID, 3000, 4000)));
+
+ List<UidTraffic> trafficList1 = ImmutableList.of(
+ createUidTraffic(Process.BLUETOOTH_UID, 1000, 2000),
+ createUidTraffic(APP_UID, 3000, 4000));
+ BluetoothActivityEnergyInfo info1 = createBtEnergyInfo(2000,
+ BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE, 1000, 2000, 3000, 4000,
+ trafficList1);
+
batteryStats.updateBluetoothStateLocked(info1,
1_000_000, 2000, 2000);
@@ -214,11 +225,13 @@
uid.setProcessStateForTest(
BatteryStats.Uid.PROCESS_STATE_BACKGROUND, 3000);
- BluetoothActivityEnergyInfo info2 = new BluetoothActivityEnergyInfo(4000,
- BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE, 5000, 6000, 7000, 8000);
- info2.setUidTraffic(ImmutableList.of(
- new UidTraffic(Process.BLUETOOTH_UID, 5000, 6000),
- new UidTraffic(APP_UID, 7000, 8000)));
+ List<UidTraffic> trafficList2 = ImmutableList.of(
+ createUidTraffic(Process.BLUETOOTH_UID, 5000, 6000),
+ createUidTraffic(APP_UID, 7000, 8000));
+ BluetoothActivityEnergyInfo info2 = createBtEnergyInfo(4000,
+ BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE, 5000, 6000, 7000, 8000,
+ trafficList2);
+
batteryStats.updateBluetoothStateLocked(info2,
5_000_000, 4000, 4000);
@@ -280,12 +293,15 @@
}
private void setupBluetoothEnergyInfo(long reportedEnergyUc, long consumedEnergyUc) {
- final BluetoothActivityEnergyInfo info = new BluetoothActivityEnergyInfo(1000,
+ List<UidTraffic> trafficList = ImmutableList.of(
+ createUidTraffic(Process.BLUETOOTH_UID, 1000, 2000),
+ createUidTraffic(APP_UID, 3000, 4000));
+
+
+ final BluetoothActivityEnergyInfo info = createBtEnergyInfo(1000,
BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE, 7000, 5000, 0,
- reportedEnergyUc);
- info.setUidTraffic(ImmutableList.of(
- new UidTraffic(Process.BLUETOOTH_UID, 1000, 2000),
- new UidTraffic(APP_UID, 3000, 4000)));
+ reportedEnergyUc, trafficList);
+
mStatsRule.getBatteryStats().updateBluetoothStateLocked(info,
consumedEnergyUc, 1000, 1000);
}
@@ -304,4 +320,34 @@
BatteryConsumer.POWER_COMPONENT_BLUETOOTH);
assertThat(usageDurationMillis).isEqualTo(durationMs);
}
+
+ private UidTraffic createUidTraffic(int uid, long traffic1, long traffic2) {
+ final Parcel uidTrafficParcel = Parcel.obtain();
+ uidTrafficParcel.writeInt(uid);
+ uidTrafficParcel.writeLong(traffic1);
+ uidTrafficParcel.writeLong(traffic2);
+ uidTrafficParcel.setDataPosition(0);
+
+ UidTraffic traffic = UidTraffic.CREATOR.createFromParcel(uidTrafficParcel);
+ uidTrafficParcel.recycle();
+ return traffic;
+ }
+
+ private BluetoothActivityEnergyInfo createBtEnergyInfo(long timestamp, int stackState,
+ long txTime, long rxTime, long idleTime, long energyUsed, List<UidTraffic> traffic) {
+ final Parcel btActivityEnergyInfoParcel = Parcel.obtain();
+ btActivityEnergyInfoParcel.writeLong(timestamp);
+ btActivityEnergyInfoParcel.writeInt(stackState);
+ btActivityEnergyInfoParcel.writeLong(txTime);
+ btActivityEnergyInfoParcel.writeLong(rxTime);
+ btActivityEnergyInfoParcel.writeLong(idleTime);
+ btActivityEnergyInfoParcel.writeLong(energyUsed);
+ btActivityEnergyInfoParcel.writeTypedList(traffic);
+ btActivityEnergyInfoParcel.setDataPosition(0);
+
+ BluetoothActivityEnergyInfo info = BluetoothActivityEnergyInfo.CREATOR
+ .createFromParcel(btActivityEnergyInfoParcel);
+ btActivityEnergyInfoParcel.recycle();
+ return info;
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/os/PowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/PowerCalculatorTest.java
deleted file mode 100644
index 4bd5724..0000000
--- a/core/tests/coretests/src/com/android/internal/os/PowerCalculatorTest.java
+++ /dev/null
@@ -1,71 +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 com.android.internal.os;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import android.os.BatteryStats;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import junit.framework.TestCase;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class PowerCalculatorTest extends TestCase {
- private static final long US_IN_HR = 1000L * 1000L * 60L * 60L;
-
- @Mock
- private PowerProfile mPowerProfile;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- }
-
- /** Test {@link MediaPowerCalculator#calculateApp} */
- @Test
- public void testMediaPowerCalculator() {
- when(mPowerProfile.getAveragePower(PowerProfile.POWER_AUDIO)).thenReturn(12.0);
- when(mPowerProfile.getAveragePower(PowerProfile.POWER_VIDEO)).thenReturn(25.0);
-
- BatteryStats.Uid u = mock(BatteryStats.Uid.class);
- BatteryStats.Timer audioTimer = mock(BatteryStats.Timer.class);
- when(u.getAudioTurnedOnTimer()).thenReturn(audioTimer);
- when(audioTimer.getTotalTimeLocked(2L * US_IN_HR, 0)).thenReturn(2L * US_IN_HR);
- BatteryStats.Timer videoTimer = mock(BatteryStats.Timer.class);
- when(u.getVideoTurnedOnTimer()).thenReturn(videoTimer);
- when(videoTimer.getTotalTimeLocked(2L * US_IN_HR, 0)).thenReturn(1L * US_IN_HR);
-
- MediaPowerCalculator mediaPowerCalculator = new MediaPowerCalculator(mPowerProfile);
- BatterySipper app = new BatterySipper(BatterySipper.DrainType.APP, u, 0);
-
- mediaPowerCalculator.calculate(List.of(app), null, 2L * US_IN_HR, 2L * US_IN_HR, 0, null);
- assertEquals(49.0, app.sumPower());
- }
-}
diff --git a/core/tests/coretests/src/com/android/internal/util/DumpableContainerImplTest.java b/core/tests/coretests/src/com/android/internal/util/DumpableContainerImplTest.java
index 4c58dfa..589e4f9 100644
--- a/core/tests/coretests/src/com/android/internal/util/DumpableContainerImplTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/DumpableContainerImplTest.java
@@ -27,6 +27,7 @@
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.util.concurrent.atomic.AtomicReference;
public final class DumpableContainerImplTest {
@@ -41,7 +42,7 @@
@Test
public void testAddDumpable_dumpableWithoutName() {
- Dumpable noNamer = new Dumpable() {
+ Dumpable namelessDumpable = new Dumpable() {
@Override
public String getDumpableName() {
@@ -54,7 +55,7 @@
}
};
- assertThrows(NullPointerException.class, () -> mImpl.addDumpable(noNamer));
+ assertThrows(NullPointerException.class, () -> mImpl.addDumpable(namelessDumpable));
}
@Test
@@ -178,11 +179,76 @@
+ "......6 Args: 4,8,15,16,23,42,\n");
}
+ @Test
+ public void testRemoveDumpable_null() {
+ assertThrows(NullPointerException.class, () -> mImpl.removeDumpable(null));
+ }
+
+ @Test
+ public void testARemoveDumpable_dumpableWithoutName() {
+ // Need a non-null name initially otherwise it won't be added
+ AtomicReference<String> name = new AtomicReference<>("A Dumpable Has No Name");
+ Dumpable dumpable = new Dumpable() {
+
+ @Override
+ public String getDumpableName() {
+ return name.get();
+ }
+
+ @Override
+ public void dump(PrintWriter writer, String[] args) {
+ throw new UnsupportedOperationException("D'OH!");
+ }
+
+ };
+ assertWithMessage("addDumpable(with name)").that(mImpl.addDumpable(dumpable)).isTrue();
+
+ name.set(null);
+ assertWithMessage("removeDumpable(nameless)").that(mImpl.removeDumpable(dumpable))
+ .isFalse();
+ }
+
+ @Test
+ public void testRemoveDumpable_empty() {
+ CustomDumpable dumpable = new CustomDumpable("The name is Bond", "James Bond!");
+
+ assertWithMessage("removeDumpable()").that(mImpl.removeDumpable(dumpable)).isFalse();
+ }
+
+ @Test
+ public void testRemoveDumpable_sameNameButDifferentDumpable() {
+ CustomDumpable real = new CustomDumpable("Slim Shade", "Please stand up!");
+ CustomDumpable fake = new CustomDumpable("Slim Shade", "Please stand up!");
+
+ mImpl.addDumpable(real);
+
+ assertWithMessage("removeDumpable(fake)").that(mImpl.removeDumpable(fake)).isFalse();
+ assertWithMessage("removeDumpable(real)").that(mImpl.removeDumpable(real)).isTrue();
+ }
+
+ @Test
+ public void testRemoveDumpable_existing() {
+ CustomDumpable dumpable = new CustomDumpable("Homer", "D'ohmp!");
+
+ mImpl.addDumpable(dumpable);
+ mImpl.listDumpables("...", mWriter);
+ assertWithMessage("listDumpables()").that(getOutput()).isEqualTo("...1 dumpables: Homer\n");
+
+ assertWithMessage("removeDumpable()").that(mImpl.removeDumpable(dumpable)).isTrue();
+ resetOutput();
+ mImpl.listDumpables("...", mWriter);
+ assertWithMessage("listDumpables(...)").that(getOutput()).isEqualTo("...No dumpables\n");
+ }
+
private String getOutput() {
mSw.flush();
return mSw.toString();
}
+ private void resetOutput() {
+ mSw.getBuffer().setLength(0);
+ }
+
private static final class CustomDumpable implements Dumpable {
public final String name;
public final String content;
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 2d5f833..ac5daf0 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -508,6 +508,8 @@
<permission name="android.permission.MANAGE_APP_HIBERNATION"/>
<!-- Permission required for CTS test - ResourceObserverNativeTest -->
<permission name="android.permission.REGISTER_MEDIA_RESOURCE_OBSERVER" />
+ <!-- Permission required for CTS test - MediaCodecResourceTest -->
+ <permission name="android.permission.MEDIA_RESOURCE_OVERRIDE_PID" />
<!-- Permission required for CTS test - CtsAlarmManagerTestCases -->
<permission name="android.permission.SCHEDULE_PRIORITIZED_ALARM" />
<!-- Permission required for CTS test - SystemMediaRouter2Test -->
@@ -547,17 +549,6 @@
<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/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index f2a875c7..4aa0f07 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -1567,6 +1567,12 @@
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/RootWindowContainer.java"
},
+ "-432881038": {
+ "message": "startBackNavigation task=%s, topRunningActivity=%s, applicationBackCallback=%s, systemBackCallback=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_BACK_PREVIEW",
+ "at": "com\/android\/server\/wm\/BackNavigationController.java"
+ },
"-415865166": {
"message": "findFocusedWindow: Found new focus @ %s",
"level": "VERBOSE",
@@ -3691,12 +3697,6 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
- "1898905572": {
- "message": "startBackNavigation task=%s, topRunningActivity=%s, topWindow=%s backCallback=%s",
- "level": "DEBUG",
- "group": "WM_DEBUG_BACK_PREVIEW",
- "at": "com\/android\/server\/wm\/BackNavigationController.java"
- },
"1903353011": {
"message": "notifyAppStopped: %s",
"level": "VERBOSE",
diff --git a/graphics/java/android/graphics/BLASTBufferQueue.java b/graphics/java/android/graphics/BLASTBufferQueue.java
index a9e730d..2678c79d 100644
--- a/graphics/java/android/graphics/BLASTBufferQueue.java
+++ b/graphics/java/android/graphics/BLASTBufferQueue.java
@@ -39,6 +39,8 @@
private static native long nativeGetLastAcquiredFrameNum(long ptr);
private static native void nativeApplyPendingTransactions(long ptr, long frameNumber);
private static native boolean nativeIsSameSurfaceControl(long ptr, long surfaceControlPtr);
+ private static native SurfaceControl.Transaction nativeGatherPendingTransactions(long ptr,
+ long frameNumber);
/** Create a new connection with the surface flinger. */
public BLASTBufferQueue(String name, SurfaceControl sc, int width, int height,
@@ -159,4 +161,17 @@
public boolean isSameSurfaceControl(SurfaceControl sc) {
return nativeIsSameSurfaceControl(mNativeObject, sc.mNativeObject);
}
+
+ /**
+ * Get any transactions that were passed to {@link #mergeWithNextTransaction} with the
+ * specified frameNumber. This is intended to ensure transactions don't get stuck as pending
+ * if the specified frameNumber is never drawn.
+ *
+ * @param frameNumber The frameNumber used to determine which transactions to apply.
+ * @return a Transaction that contains the merge of all the transactions that were sent to
+ * mergeWithNextTransaction
+ */
+ public SurfaceControl.Transaction gatherPendingTransactions(long frameNumber) {
+ return nativeGatherPendingTransactions(mNativeObject, frameNumber);
+ }
}
diff --git a/graphics/java/android/graphics/PixelFormat.java b/graphics/java/android/graphics/PixelFormat.java
index dde757b..3ec5b9c 100644
--- a/graphics/java/android/graphics/PixelFormat.java
+++ b/graphics/java/android/graphics/PixelFormat.java
@@ -29,7 +29,7 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({RGBA_8888, RGBX_8888, RGBA_F16, RGBA_1010102, RGB_888, RGB_565})
+ @IntDef({RGBA_8888, RGBX_8888, RGBA_F16, RGBA_1010102, RGB_888, RGB_565, R_8})
public @interface Format { }
// NOTE: these constants must match the values from graphics/common/x.x/types.hal
@@ -93,6 +93,9 @@
/** @hide */
public static final int HSV_888 = 0x37;
+ /** @hide */
+ public static final int R_8 = 0x38;
+
/**
* @deprecated use {@link android.graphics.ImageFormat#JPEG
* ImageFormat.JPEG} instead.
@@ -142,6 +145,10 @@
info.bitsPerPixel = 64;
info.bytesPerPixel = 8;
break;
+ case R_8:
+ info.bitsPerPixel = 8;
+ info.bytesPerPixel = 1;
+ break;
default:
throw new IllegalArgumentException("unknown pixel format " + format);
}
@@ -235,6 +242,8 @@
return "HSV_888";
case JPEG:
return "JPEG";
+ case R_8:
+ return "R_8";
default:
return Integer.toString(format);
}
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index ee41148..ee0d647 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -290,7 +290,7 @@
* 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/keystore/OWNERS b/keystore/OWNERS
index a63ca46..7ab9d76 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/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 8f368c2..d35ecbd 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -924,6 +924,7 @@
* Checks if an activity is embedded and its presentation is customized by a
* {@link android.window.TaskFragmentOrganizer} to only occupy a portion of Task bounds.
*/
+ @Override
public boolean isActivityEmbedded(@NonNull Activity activity) {
return mPresenter.isActivityEmbedded(activity.getActivityToken());
}
diff --git a/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml b/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml
index fc6ea9a..5beaa87 100644
--- a/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml
+++ b/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml
@@ -22,6 +22,8 @@
<!-- The background of the top-level layout acts as the background dim. -->
+ <!-- Setting the alpha of the dialog container to 0, since it shouldn't be visible until the
+ enter animation starts. -->
<LinearLayout
android:id="@+id/letterbox_education_dialog_container"
android:layout_width="wrap_content"
@@ -30,7 +32,8 @@
android:gravity="center_horizontal"
android:orientation="vertical"
android:background="@drawable/letterbox_education_dialog_background"
- android:padding="24dp">
+ android:padding="24dp"
+ android:alpha="0">
<ImageView
android:id="@+id/letterbox_education_icon"
diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml
index e45e409..88382d7 100644
--- a/libs/WindowManager/Shell/res/values-af/strings.xml
+++ b/libs/WindowManager/Shell/res/values-af/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kamerakwessies?\nTik om aan te pas"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nie opgelos nie?\nTik om terug te stel"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Geen kamerakwessies nie? Tik om toe te maak."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Kry die meeste uit <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Draai jou skerm na portret"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Draai jou skerm na landskap"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Sleep nog \'n program in om verdeelde skerm te gebruik"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Dubbeltik om te herposisioneer"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Het dit"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml
index 3a1f619..20d081f 100644
--- a/libs/WindowManager/Shell/res/values-am/strings.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"የካሜራ ችግሮች አሉ?\nዳግም ለማበጀት መታ ያድርጉ"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"አልተስተካከለም?\nለማህደር መታ ያድርጉ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ምንም የካሜራ ችግሮች የሉም? ለማሰናበት መታ ያድርጉ።"</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"ከ<xliff:g id="APP_NAME">%s</xliff:g> ማግኘት የሚችሉትን ያግኙ"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"የቁመት አቀማመጥ ለማድረግ ማያ ገጽዎን ያሽከርክሩት"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"የአግድም አቀማመጥ ለማድረግ ማያ ገጽዎን ያሽከርክሩት"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"የተከፈለ ማያ ገጽ ለመጠቀም ሌላ መተግበሪያ ይጎትቱ"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"ቦታ ለመቀየር ሁለቴ መታ ያድርጉ"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ገባኝ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml
index 1b890f5..b41e642 100644
--- a/libs/WindowManager/Shell/res/values-ar/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ar/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"هل هناك مشاكل في الكاميرا؟\nانقر لإعادة الضبط."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ألم يتم حل المشكلة؟\nانقر للعودة"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"أليس هناك مشاكل في الكاميرا؟ انقر للإغلاق."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"الاستفادة إلى أقصى حدّ من <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"تدوير الشاشة للوضع العمودي"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"تدوير الشاشة إلى الوضع الأفقي"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"اسحب تطبيقًا آخر لاستخدام وضع تقسيم الشاشة"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"انقر مرتين لتغيير الموضع"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"حسنًا"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml
index a700fbf..663691f 100644
--- a/libs/WindowManager/Shell/res/values-as/strings.xml
+++ b/libs/WindowManager/Shell/res/values-as/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"কেমেৰাৰ কোনো সমস্যা হৈছে নেকি?\nপুনৰ খাপ খোৱাবলৈ টিপক"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"এইটো সমাধান কৰা নাই নেকি?\nপূৰ্বাৱস্থালৈ নিবলৈ টিপক"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"কেমেৰাৰ কোনো সমস্যা নাই নেকি? অগ্ৰাহ্য কৰিবলৈ টিপক।"</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"<xliff:g id="APP_NAME">%s</xliff:g>পাৰ্যমানে ব্যৱহাৰ কৰক"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"প’ৰ্ট্ৰেইট কৰিবলৈ স্ক্ৰীনখন ঘূৰাওক"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"লেণ্ডস্কেইপ কৰিবলৈ স্ক্ৰীনখন ঘূৰাওক"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰিবলৈ অন্য এটা এপ্ ইয়ালৈ টানি আনি এৰক"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"স্থান সলনি কৰিবলৈ দুবাৰ টিপক"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"বুজি পালোঁ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml
index 0dba934..646aba8 100644
--- a/libs/WindowManager/Shell/res/values-az/strings.xml
+++ b/libs/WindowManager/Shell/res/values-az/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kamera problemi var?\nBərpa etmək üçün toxunun"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Düzəltməmisiniz?\nGeri qaytarmaq üçün toxunun"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kamera problemi yoxdur? Qapatmaq üçün toxunun."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"<xliff:g id="APP_NAME">%s</xliff:g> tətbiqindən maksimum faydalanın"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Ekranı fırladaraq portret rejiminə keçin"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Ekranı fırladaraq albom rejiminə keçin"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Bölünmüş ekrandan istifadə etmək üçün başqa tətbiqə sürüşdürün"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Yerini dəyişdirmək üçün iki dəfə toxunun"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Anladım"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
index afe411b..2ebdf92 100644
--- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Imate problema sa kamerom?\nDodirnite da biste ponovo uklopili"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problem nije rešen?\nDodirnite da biste vratili"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nemate problema sa kamerom? Dodirnite da biste odbacili."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Iskoristite aplikaciju <xliff:g id="APP_NAME">%s</xliff:g> na najbolji način"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Rotirajte ekran u uspravni položaj"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Rotirajte ekran u vodoravni položaj"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Prevucite drugu aplikaciju da biste koristili podeljeni ekran"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Dvaput dodirnite radi premeštanja"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Važi"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml
index ef692c2..157e168 100644
--- a/libs/WindowManager/Shell/res/values-be/strings.xml
+++ b/libs/WindowManager/Shell/res/values-be/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Праблемы з камерай?\nНацісніце, каб пераабсталяваць"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Не ўдалося выправіць?\nНацісніце, каб аднавіць"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ніякіх праблем з камерай? Націсніце, каб адхіліць."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Выкарыстоўвайце ўсе магчымасці праграмы \"<xliff:g id="APP_NAME">%s</xliff:g>\""</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Павярніце экран у кніжную арыентацыю"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Павярніце экран у альбомную арыентацыю"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Перацягніце іншую праграму, каб выкарыстоўваць падзелены экран"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Двойчы націсніце, каб перасунуць"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Зразумела"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml
index 4ca46b5..4ed8672 100644
--- a/libs/WindowManager/Shell/res/values-bg/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bg/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Имате проблеми с камерата?\nДокоснете за ремонтиране"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Проблемът не се отстрани?\nДокоснете за връщане в предишното състояние"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Нямате проблеми с камерата? Докоснете, за да отхвърлите."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Използване на <xliff:g id="APP_NAME">%s</xliff:g> в пълна степен"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Завъртете екрана си вертикално"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Завъртете екрана си хоризонтално"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Преместете друго приложение с плъзгане, за да използвате режима за разделен екран"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Докоснете два пъти за промяна на позицията"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Разбрах"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml
index fa62bba..7579fac 100644
--- a/libs/WindowManager/Shell/res/values-bn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bn/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ক্যামেরা সংক্রান্ত সমস্যা?\nরিফিট করতে ট্যাপ করুন"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"এখনও সমাধান হয়নি?\nরিভার্ট করার জন্য ট্যাপ করুন"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ক্যামেরা সংক্রান্ত সমস্যা নেই? বাতিল করতে ট্যাপ করুন।"</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"<xliff:g id="APP_NAME">%s</xliff:g>-এর সবচেয়ে বেশি সুবিধা নিন"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"আপনার স্ক্রিন ঘুরিয়ে পোর্ট্রেট করুন"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"আপনার স্ক্রিন ঘুরিয়ে ল্যান্ডস্কেপ করুন"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"স্প্লিট স্ক্রিন ফিচার ব্যবহার করতে অন্য অ্যাপে টেনে আনুন"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"জায়গা পরিবর্তন করতে ডবল ট্যাপ করুন"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"বুঝেছি"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml
index 043a309..7b08d03 100644
--- a/libs/WindowManager/Shell/res/values-bs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bs/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemi s kamerom?\nDodirnite da ponovo namjestite"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nije popravljeno?\nDodirnite da vratite"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nema problema s kamerom? Dodirnite da odbacite."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Iskoristite sve prednosti aplikacije <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Zarotirajte ekran u uspravni položaj"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Zarotirajte ekran u vodoravni položaj"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Prevucite još jednu aplikaciju da koristite podijeljeni ekran"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Dodirnite dvaput da premjestite"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Razumijem"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml
index 3ee8a23..44429cc 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Tens problemes amb la càmera?\nToca per resoldre\'ls"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"El problema no s\'ha resolt?\nToca per desfer els canvis"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No tens cap problema amb la càmera? Toca per ignorar."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Treu el màxim profit de l\'aplicació <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Gira la pantalla per posar-la en vertical"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Gira la pantalla per posar-la en horitzontal"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Arrossega una altra aplicació per utilitzar la pantalla dividida"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Fes doble toc per canviar la posició"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entesos"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml
index 00e5827..d6e7136 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problémy s fotoaparátem?\nKlepnutím vyřešíte"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nepomohlo to?\nKlepnutím se vrátíte"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Žádné problémy s fotoaparátem? Klepnutím zavřete."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Využijte <xliff:g id="APP_NAME">%s</xliff:g> na maximum"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Otočením obrazovky přejdete do zobrazení na výšku"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Otočením obrazovky přejdete do zobrazení na šířku"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Přetáhnutím druhé aplikace použijete rozdělenou obrazovku"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Dvojitým klepnutím změníte umístění"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml
index bdcb6d8..e7b8e73 100644
--- a/libs/WindowManager/Shell/res/values-da/strings.xml
+++ b/libs/WindowManager/Shell/res/values-da/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Har du problemer med dit kamera?\nTryk for at gendanne det oprindelige format"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Løste det ikke problemet?\nTryk for at fortryde"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Har du ingen problemer med dit kamera? Tryk for at afvise."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Få mest muligt ud af <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Roter din skærm til stående format"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Roter din skærm til liggende format"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Træk en anden app hertil for at bruge opdelt skærm"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Tryk to gange for at flytte"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml
index 472e941..57af696c 100644
--- a/libs/WindowManager/Shell/res/values-de/strings.xml
+++ b/libs/WindowManager/Shell/res/values-de/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Probleme mit der Kamera?\nZum Anpassen tippen."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Das Problem ist nicht behoben?\nZum Rückgängigmachen tippen."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Keine Probleme mit der Kamera? Zum Schließen tippen."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"<xliff:g id="APP_NAME">%s</xliff:g> optimal nutzen"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Display ins Hochformat drehen"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Display ins Querformat drehen"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Weitere App hierher ziehen, um den Bildschirm zu teilen"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Doppeltippen, um Position anzupassen"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Ok"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml
index 53edf1e..873b329 100644
--- a/libs/WindowManager/Shell/res/values-el/strings.xml
+++ b/libs/WindowManager/Shell/res/values-el/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Προβλήματα με την κάμερα;\nΠατήστε για επιδιόρθωση."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Δεν διορθώθηκε;\nΠατήστε για επαναφορά."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Δεν αντιμετωπίζετε προβλήματα με την κάμερα; Πατήστε για παράβλεψη."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Αξιοποιήστε όλες τις δυνατότητες του <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Περιστροφή της οθόνης σε προσανατολισμό πορτρέτου"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Περιστροφή της οθόνης σε οριζόντιο προσανατολισμό"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Σύρετε σε μια άλλη εφαρμογή για να χρησιμοποιήσετε τον διαχωρισμό οθόνης"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Διπλό πάτημα για επανατοποθέτηση"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Το κατάλαβα"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
index eb806a7..da4933b 100644
--- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Camera issues?\nTap to refit"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Get the most out of <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Rotate your screen to portrait"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Rotate your screen to landscape"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Drag in another app to use split screen"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Double tap to reposition"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
index eb806a7..da4933b 100644
--- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Camera issues?\nTap to refit"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Get the most out of <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Rotate your screen to portrait"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Rotate your screen to landscape"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Drag in another app to use split screen"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Double tap to reposition"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
index eb806a7..da4933b 100644
--- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Camera issues?\nTap to refit"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Get the most out of <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Rotate your screen to portrait"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Rotate your screen to landscape"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Drag in another app to use split screen"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Double tap to reposition"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
index eb806a7..da4933b 100644
--- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Camera issues?\nTap to refit"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Get the most out of <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Rotate your screen to portrait"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Rotate your screen to landscape"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Drag in another app to use split screen"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Double tap to reposition"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
index 62123eb..5c3d0f6 100644
--- a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
@@ -76,10 +76,9 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Camera issues?\nTap to refit"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Get the most out of <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Rotate your screen to portrait"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Rotate your screen to landscape"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Drag in another app to use split screen"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Double tap to reposition"</string>
+ <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Some apps work best in portrait"</string>
+ <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Try one of these options to make the most of your space"</string>
+ <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rotate your device to go full screen"</string>
+ <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Double-tap next to an app to reposition it"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
index 6db0975..154c7ab 100644
--- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"¿Tienes problemas con la cámara?\nPresiona para reajustarla"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"¿No se resolvió?\nPresiona para revertir los cambios"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"¿No tienes problemas con la cámara? Presionar para descartar."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Aprovecha <xliff:g id="APP_NAME">%s</xliff:g> al máximo"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Rota la pantalla al modo vertical"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Rota la pantalla al modo horizontal"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Arrastra otra app para usar la pantalla dividida"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Presiona dos veces para cambiar la posición"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendido"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml
index 4356dc8..e2fa3a0 100644
--- a/libs/WindowManager/Shell/res/values-es/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"¿Problemas con la cámara?\nToca para reajustar"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"¿No se ha solucionado?\nToca para revertir"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"¿No hay problemas con la cámara? Toca para cerrar."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Saca el máximo partido de <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Gira la pantalla para ponerla en el modo de vista vertical"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Gira la pantalla para ponerla en el modo de vista horizontal"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Arrastra otra aplicación para usar la pantalla dividida"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Toca dos veces para cambiar de posición"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendido"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml
index 3dba8cc..da33f4d 100644
--- a/libs/WindowManager/Shell/res/values-et/strings.xml
+++ b/libs/WindowManager/Shell/res/values-et/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kas teil on kaameraprobleeme?\nPuudutage ümberpaigutamiseks."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Kas probleemi ei lahendatud?\nPuudutage ennistamiseks."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kas kaameraprobleeme pole? Puudutage loobumiseks."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Kasutage <xliff:g id="APP_NAME">%s</xliff:g> võimalusi"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Pöörake ekraan vertikaalpaigutusse"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Pöörake ekraan horisontaalpaigutusse"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Lohistage muusse rakendusse, et jagatud ekraanikuva kasutada"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Topeltpuudutage ümberpaigutamiseks"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Selge"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml
index ab70b3a..e0dd3ca2 100644
--- a/libs/WindowManager/Shell/res/values-eu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-eu/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Arazoak dauzkazu kamerarekin?\nBerriro doitzeko, sakatu hau."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Ez al da konpondu?\nLeheneratzeko, sakatu hau."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ez daukazu arazorik kamerarekin? Baztertzeko, sakatu hau."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Atera ahalik eta etekin handiena <xliff:g id="APP_NAME">%s</xliff:g> aplikazioari"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Edukia bertikalki ikusteko, biratu pantaila"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Edukia horizontalki ikusteko, biratu pantaila"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Pantaila zatituta ikusteko, arrastatu beste aplikazio bat"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Aplikazioaren posizioa aldatzeko, saka ezazu birritan"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Ados"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml
index bef49d3..6fcb5ee 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"دوربین مشکل دارد؟\nبرای تنظیم مجدد اندازه ضربه بزنید"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"مشکل برطرف نشد؟\nبرای برگرداندن ضربه بزنید"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"دوربین مشکلی ندارد؟ برای بستن ضربه بزنید."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"بیشترین بهره را از <xliff:g id="APP_NAME">%s</xliff:g> ببرید"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"صفحهنمایش را در جهت عمودی بچرخانید"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"صفحهنمایش را در جهت افقی بچرخانید"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"برای استفاده از صفحهٔ دونیمه، در برنامهای دیگر بکشید"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"برای تغییر مکان، دوضربه بزنید"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"متوجهام"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml
index c5b9ece..fc51ad4 100644
--- a/libs/WindowManager/Shell/res/values-fi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fi/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Onko kameran kanssa ongelmia?\nKorjaa napauttamalla"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Eikö ongelma ratkennut?\nKumoa napauttamalla"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ei ongelmia kameran kanssa? Hylkää napauttamalla."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"<xliff:g id="APP_NAME">%s</xliff:g> niin kuin se on tarkoitettu"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Vaihda pystysuuntaan kääntämällä näyttöä"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Vaihda vaakasuuntaan kääntämällä näyttöä"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Käytä jaettua näyttöä vetämällä tähän toinen sovellus"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Sijoita uudelleen kaksoisnapauttamalla"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
index 5689b59..43fad3a 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problèmes d\'appareil photo?\nTouchez pour réajuster"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problème non résolu?\nTouchez pour rétablir"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Aucun problème d\'appareil photo? Touchez pour ignorer."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Profitez de toutes les possibilités de <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Faites pivoter votre écran pour passer en mode portrait"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Faites pivoter votre écran pour passer en mode paysage"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Faites glisser une autre application pour utiliser l\'écran partagé"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Touchez deux fois pour repositionner"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml
index 670a242..8b8cc09 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problèmes d\'appareil photo ?\nAppuyez pour réajuster"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problème non résolu ?\nAppuyez pour rétablir"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Aucun problème d\'appareil photo ? Appuyez pour ignorer."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Tirez le meilleur parti de <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Faites pivoter votre écran en mode Portrait"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Faites pivoter votre écran en mode Paysage"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Faites glisser une autre application pour utiliser l\'écran partagé"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Appuyez deux fois pour repositionner"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml
index 0559838..9bc9d93 100644
--- a/libs/WindowManager/Shell/res/values-gl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gl/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Tes problemas coa cámara?\nToca para reaxustala"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Non se solucionaron os problemas?\nToca para reverter o seu tratamento"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Non hai problemas coa cámara? Tocar para ignorar."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Sácalle o máximo partido a <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Xira a pantalla para poñela en modo vertical"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Xira a pantalla para poñela en modo horizontal"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Arrastra outra aplicación para usar a pantalla dividida"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Toca dúas veces para cambiar a posición"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendido"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml
index ec3093a..032b591 100644
--- a/libs/WindowManager/Shell/res/values-gu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gu/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"કૅમેરામાં સમસ્યાઓ છે?\nફરીથી ફિટ કરવા માટે ટૅપ કરો"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"સુધારો નથી થયો?\nપહેલાંના પર પાછું ફેરવવા માટે ટૅપ કરો"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"કૅમેરામાં કોઈ સમસ્યા નથી? છોડી દેવા માટે ટૅપ કરો."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"<xliff:g id="APP_NAME">%s</xliff:g>નો સૌથી વધુ લાભ મેળવો"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"પોર્ટ્રેટ સ્થિતિ માટે તમારી સ્ક્રીનને ફેરવો"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"લૅન્ડસ્કેપ સ્થિતિ માટે તમારી સ્ક્રીનને ફેરવો"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"સ્ક્રીન વિભાજનનો ઉપયોગ કરવા કોઈ અન્ય ઍપમાં ખેંચો"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"સ્થાનમાં ફેરફાર કરવા માટે બે વાર ટૅપ કરો"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"સમજાઈ ગયું"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml
index d1776d8..72fd65c 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"क्या कैमरे से जुड़ी कोई समस्या है?\nफिर से फ़िट करने के लिए टैप करें"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"क्या समस्या ठीक नहीं हुई?\nपहले जैसा करने के लिए टैप करें"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"क्या कैमरे से जुड़ी कोई समस्या नहीं है? खारिज करने के लिए टैप करें."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"<xliff:g id="APP_NAME">%s</xliff:g> का ज़्यादा से ज़्यादा फ़ायदा पाएं"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"अपनी स्क्रीन को घुमाकर, पोर्ट्रेट मोड में लाएं"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"अपनी स्क्रीन को घुमाकर, लैंडस्केप मोड में लाएं"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"स्प्लिट स्क्रीन का इस्तेमाल करने के लिए, दूसरे ऐप्लिकेशन को खींचें और छोड़ें"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"ऐप्लिकेशन की जगह बदलने के लिए, दो बार टैप करें"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ठीक है"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml
index 0986090..5315558 100644
--- a/libs/WindowManager/Shell/res/values-hr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hr/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemi s fotoaparatom?\nDodirnite za popravak"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problem nije riješen?\nDodirnite za vraćanje"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nemate problema s fotoaparatom? Dodirnite za odbacivanje."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Iskoristite sve prednosti aplikacije <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Zakrenite zaslon u okomiti položaj"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Zakrenite zaslon u vodoravni položaj"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Povucite drugu aplikaciju da biste upotrebljavali podijeljeni zaslon"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Dvaput dodirnite za premještanje"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Shvaćam"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml
index f4027fb..01671c9 100644
--- a/libs/WindowManager/Shell/res/values-hu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hu/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kamerával kapcsolatos problémába ütközött?\nKoppintson a megoldáshoz."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nem sikerült a hiba kijavítása?\nKoppintson a visszaállításhoz."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nincsenek problémái kamerával? Koppintson az elvetéshez."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Használja ki a(z) <xliff:g id="APP_NAME">%s</xliff:g> minden előnyét"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Képernyő elforgatása álló módba"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Képernyő elforgatása fekvő módba"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Húzzon ide egy másik alkalmazást az osztott képernyő használatához"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Koppintson duplán az áthelyezéshez"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Értem"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml
index c934695..459cd0a 100644
--- a/libs/WindowManager/Shell/res/values-hy/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hy/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Տեսախցիկի հետ կապված խնդիրնե՞ր կան։\nՀպեք՝ վերակարգավորելու համար։"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Չհաջողվե՞ց շտկել։\nՀպեք՝ փոփոխությունները չեղարկելու համար։"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Տեսախցիկի հետ կապված խնդիրներ չկա՞ն։ Փակելու համար հպեք։"</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Օգտվեք <xliff:g id="APP_NAME">%s</xliff:g>-ի բոլոր հնարավորություններից"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Պտտեք էկրանը ուղղաձիգ դիրքի"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Պտտեք էկրանը հորիզոնական դիրքի"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Քաշեք մյուս հավելվածի մեջ՝ էկրանի տրոհումն օգտագործելու համար"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Կրկնակի հպեք՝ դիրքը փոխելու համար"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Եղավ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml
index 5976fe1..e5b7421 100644
--- a/libs/WindowManager/Shell/res/values-in/strings.xml
+++ b/libs/WindowManager/Shell/res/values-in/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Masalah kamera?\nKetuk untuk memperbaiki"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Tidak dapat diperbaiki?\nKetuk untuk mengembalikan"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Tidak ada masalah kamera? Ketuk untuk menutup."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Optimalkan penggunaan <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Putar layar ke mode potret"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Putar layar ke mode lanskap"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Tarik aplikasi lain untuk menggunakan layar terpisah"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Ketuk dua kali untuk mengubah posisi"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Oke"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml
index ee9940a..1bfec2b 100644
--- a/libs/WindowManager/Shell/res/values-is/strings.xml
+++ b/libs/WindowManager/Shell/res/values-is/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Myndavélavesen?\nÝttu til að breyta stærð"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Ennþá vesen?\nÝttu til að afturkalla"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ekkert myndavélavesen? Ýttu til að hunsa."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Nýttu <xliff:g id="APP_NAME">%s</xliff:g> sem best"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Snúðu skjánum í skammsnið"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Snúðu skjánum í langsnið"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Dragðu annað forrit inn til að nota skjáskiptingu"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Ýttu tvisvar til að breyta staðsetningu"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Ég skil"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml
index f12289e..ebdf44b 100644
--- a/libs/WindowManager/Shell/res/values-it/strings.xml
+++ b/libs/WindowManager/Shell/res/values-it/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemi con la fotocamera?\nTocca per risolverli"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Il problema non si è risolto?\nTocca per ripristinare"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nessun problema con la fotocamera? Tocca per ignorare."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Usa al meglio l\'app <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Ruota lo schermo in verticale"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Ruota lo schermo in orizzontale"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Trascina in un\'altra app per usare lo schermo diviso"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Tocca due volte per riposizionare"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml
index eb63a21..3a0f72b 100644
--- a/libs/WindowManager/Shell/res/values-iw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-iw/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"בעיות במצלמה?\nאפשר להקיש כדי לבצע התאמה מחדש"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"הבעיה לא נפתרה?\nאפשר להקיש כדי לחזור לגרסה הקודמת"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"אין בעיות במצלמה? אפשר להקיש כדי לסגור."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"להפיק את המרב מ-<xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"מסובבים את המסך כדי להציג לאורך"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"מסובבים את המסך כדי להציג לרוחב"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"גוררים אפליקציה אחרת כדי להשתמש במסך מפוצל"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"מקישים הקשה כפולה כדי למקם מחדש"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"הבנתי"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml
index c6399e3..7b3ad24 100644
--- a/libs/WindowManager/Shell/res/values-ja/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ja/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"カメラに関する問題の場合は、\nタップすると修正できます"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"修正されなかった場合は、\nタップすると元に戻ります"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"カメラに関する問題でない場合は、タップすると閉じます。"</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"<xliff:g id="APP_NAME">%s</xliff:g> の活用法"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"縦向きにするには画面を回転します"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"横向きにするには画面を回転します"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"分割画面を使用するにはもう 1 つのアプリをドラッグします"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"位置を変更するにはダブルタップします"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml
index 4155236..07ee0f9 100644
--- a/libs/WindowManager/Shell/res/values-ka/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ka/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"კამერად პრობლემები აქვს?\nშეეხეთ გამოსასწორებლად"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"არ გამოსწორდა?\nშეეხეთ წინა ვერსიის დასაბრუნებლად"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"კამერას პრობლემები არ აქვს? შეეხეთ უარყოფისთვის."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"მაქსიმალურად გამოიყენეთ <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"პორტრეტის რეჟიმზე გადასასვლელად შეატრიალეთ თქვენი ეკრანი"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"ლანდშაფტის რეჟიმზე გადასასვლელად შეატრიალეთ თქვენი ეკრანი"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"ეკრანის გასაყოფად ჩავლებით გადაიტანეთ სხვა აპში"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"პოზიციის შესაცვლელად ორჯერ შეეხეთ"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"გასაგებია"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml
index f93dab5..bdaa03e 100644
--- a/libs/WindowManager/Shell/res/values-kk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kk/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Камерада қателер шықты ма?\nЖөндеу үшін түртіңіз."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Жөнделмеді ме?\nҚайтару үшін түртіңіз."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Камерада қателер шықпады ма? Жабу үшін түртіңіз."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"<xliff:g id="APP_NAME">%s</xliff:g> мүмкіндіктерін барынша пайдаланыңыз"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Көлденеңінен ашу үшін экранды бұрыңыз."</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Тігінен ашу үшін экранды бұрыңыз."</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Экранды бөлу үшін басқа қолданбаға өтіңіз."</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Қалпын өзгерту үшін екі рет түртіңіз."</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Түсінікті"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml
index 3fedb24..2654765 100644
--- a/libs/WindowManager/Shell/res/values-km/strings.xml
+++ b/libs/WindowManager/Shell/res/values-km/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"មានបញ្ហាពាក់ព័ន្ធនឹងកាមេរ៉ាឬ?\nចុចដើម្បីដោះស្រាយ"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"មិនបានដោះស្រាយបញ្ហានេះទេឬ?\nចុចដើម្បីត្រឡប់"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"មិនមានបញ្ហាពាក់ព័ន្ធនឹងកាមេរ៉ាទេឬ? ចុចដើម្បីច្រានចោល។"</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"ទទួលបានអត្ថប្រយោជន៍ច្រើនបំផុតពី <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"បង្វិលអេក្រង់របស់អ្នកទៅទិសដៅបញ្ឈរ"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"បង្វិលអេក្រង់របស់អ្នកទៅទិសដៅផ្ដេក"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"អូសនៅក្នុងកម្មវិធីផ្សេងទៀត ដើម្បីប្រើមុខងារបំបែកអេក្រង់"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"ចុចពីរដង ដើម្បីប្ដូរទីតាំង"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"យល់ហើយ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml
index 49203e5..6edbf13 100644
--- a/libs/WindowManager/Shell/res/values-kn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kn/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ಕ್ಯಾಮರಾ ಸಮಸ್ಯೆಗಳಿವೆಯೇ?\nಮರುಹೊಂದಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ಅದನ್ನು ಸರಿಪಡಿಸಲಿಲ್ಲವೇ?\nಹಿಂತಿರುಗಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ಕ್ಯಾಮರಾ ಸಮಸ್ಯೆಗಳಿಲ್ಲವೇ? ವಜಾಗೊಳಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"<xliff:g id="APP_NAME">%s</xliff:g> ನಿಂದ ಹೆಚ್ಚಿನ ಪ್ರಯೋಜನವನ್ನು ಪಡೆದುಕೊಳ್ಳಿ"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಪೋರ್ಟ್ರೇಟ್ಗೆ ತಿರುಗಿಸಿ"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಲ್ಯಾಂಡ್ಸ್ಕೇಪ್ಗೆ ತಿರುಗಿಸಿ"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಬಳಸಲು ಬೇರೊಂದು ಆ್ಯಪ್ ಅನ್ನು ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"ಸರಿಹೊಂದಿಸಲು ಡಬಲ್ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ಸರಿ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml
index 6164ed9..1f8d0b0 100644
--- a/libs/WindowManager/Shell/res/values-ko/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ko/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"카메라 문제가 있나요?\n해결하려면 탭하세요."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"해결되지 않았나요?\n되돌리려면 탭하세요."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"카메라에 문제가 없나요? 닫으려면 탭하세요."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"<xliff:g id="APP_NAME">%s</xliff:g> 최대한 활용하기"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"세로 모드로 화면을 회전합니다."</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"가로 모드로 화면을 회전합니다."</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"화면 분할을 사용하려면 다른 앱에 드래그합니다."</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"두 번 탭하여 위치를 조정합니다."</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"확인"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
index 29091fb..81eb2d7 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Камерада маселелер келип чыктыбы?\nОңдоо үчүн таптаңыз"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Оңдолгон жокпу?\nАртка кайтаруу үчүн таптаңыз"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Камерада маселе жокпу? Этибарга албоо үчүн таптаңыз."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"<xliff:g id="APP_NAME">%s</xliff:g> колдонмосунун бардык мүмкүнчүлүктөрүн колдонуңуз"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Экранды тигинен буруңуз"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Экранды туурасынан буруңуз"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Экранды бөлүү үчүн башка колдонмого сүйрөңүз"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Ракурсту өзгөртүү үчүн эки жолу басыңыз"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Түшүндүм"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml
index 20b15ee..3252130 100644
--- a/libs/WindowManager/Shell/res/values-lo/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lo/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ມີບັນຫາກ້ອງຖ່າຍຮູບບໍ?\nແຕະເພື່ອປັບໃໝ່"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ບໍ່ໄດ້ແກ້ໄຂມັນບໍ?\nແຕະເພື່ອແປງກັບຄືນ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ບໍ່ມີບັນຫາກ້ອງຖ່າຍຮູບບໍ? ແຕະເພື່ອປິດໄວ້."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"ໃຊ້ປະໂຫຍດສູງສຸດຈາກ <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"ໝຸນໜ້າຈໍຂອງທ່ານເປັນລວງຕັ້ງ"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"ໝຸນໜ້າຈໍຂອງທ່ານເປັນລວງນອນ"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"ລາກແອັບອື່ນເຂົ້າມາເພື່ອໃຊ້ການແບ່ງໜ້າຈໍ"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"ແຕະສອງເທື່ອເພື່ອປ່ຽນຕຳແໜ່ງ"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ເຂົ້າໃຈແລ້ວ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml
index 80f2815..70654c7 100644
--- a/libs/WindowManager/Shell/res/values-lt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lt/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Iškilo problemų dėl kameros?\nPalieskite, kad pritaikytumėte iš naujo"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nepavyko pataisyti?\nPalieskite, kad grąžintumėte"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nėra jokių problemų dėl kameros? Palieskite, kad atsisakytumėte."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Išnaudokite visas „<xliff:g id="APP_NAME">%s</xliff:g>“ galimybes"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Pasukite ekraną stačiai"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Pasukite ekraną gulsčiai"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Vilkite kitoje programoje, kad galėtumėte naudoti išskaidyto ekrano režimą"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Keiskite vietą dukart paliesdami"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Supratau"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml
index a66b29e..74d1b3f 100644
--- a/libs/WindowManager/Shell/res/values-lv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lv/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Vai ir problēmas ar kameru?\nPieskarieties, lai tās novērstu."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Vai problēma netika novērsta?\nPieskarieties, lai atjaunotu."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Vai nav problēmu ar kameru? Pieskarieties, lai nerādītu."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Izmantojiet visas lietotnes <xliff:g id="APP_NAME">%s</xliff:g> sniegtās iespējas"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Pagrieziet ekrānu, lai iestatītu portreta režīmu"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Pagrieziet ekrānu, lai iestatītu ainavas režīmu"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Velciet uz citu lietotni, lai izmantotu dalītu ekrānu"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Veiciet dubultskārienu, lai mainītu pozīciju"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Labi"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml
index 9502a89..be6ed4d 100644
--- a/libs/WindowManager/Shell/res/values-mk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mk/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Проблеми со камерата?\nДопрете за да се совпадне повторно"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Не се поправи?\nДопрете за враќање"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Нема проблеми со камерата? Допрете за отфрлање."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Извлечете го максимумот од <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Ротирајте го екранот во портрет"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Ротирајте го екранот во пејзаж"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Повлечете друга апликација за да користите поделен екран"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Допрете двапати за да преместите"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Сфатив"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml
index 7f2c977..14a341b 100644
--- a/libs/WindowManager/Shell/res/values-ml/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ml/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ക്യാമറ പ്രശ്നങ്ങളുണ്ടോ?\nശരിയാക്കാൻ ടാപ്പ് ചെയ്യുക"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"അത് പരിഹരിച്ചില്ലേ?\nപുനഃസ്ഥാപിക്കാൻ ടാപ്പ് ചെയ്യുക"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ക്യാമറാ പ്രശ്നങ്ങളൊന്നുമില്ലേ? നിരസിക്കാൻ ടാപ്പ് ചെയ്യുക."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"<xliff:g id="APP_NAME">%s</xliff:g> പരമാവധി പ്രയോജനപ്പെടുത്തുക"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"പോർട്രെയ്റ്റിന് നിങ്ങളുടെ സ്ക്രീൻ റൊട്ടേറ്റ് ചെയ്യുക"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"ലാൻഡ്സ്കേപ്പിന് നിങ്ങളുടെ സ്ക്രീൻ റൊട്ടേറ്റ് ചെയ്യുക"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"സ്ക്രീൻ വിഭജന മോഡ് ഉപയോഗിക്കാൻ മറ്റൊരു ആപ്പിൽ വലിച്ചിടുക"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"സ്ഥാനം മാറ്റാൻ ഡബിൾ ടാപ്പ് ചെയ്യുക"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"മനസ്സിലായി"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml
index ce4f4e1..b59f282 100644
--- a/libs/WindowManager/Shell/res/values-mn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mn/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Камерын асуудал гарсан уу?\nДахин тааруулахын тулд товшино уу"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Үүнийг засаагүй юу?\nБуцаахын тулд товшино уу"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Камерын асуудал байхгүй юу? Хаахын тулд товшино уу."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"<xliff:g id="APP_NAME">%s</xliff:g>-г бүрэн ашиглаарай"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Дэлгэцээ босоо байрлал руу эргүүлнэ үү"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Дэлгэцээ хөндлөн байрлал руу эргүүлнэ үү"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Дэлгэц хуваахыг ашиглахын тулд өөр аппыг чирнэ үү"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Дахин байрлуулахын тулд хоёр товшино уу"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Ойлголоо"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml
index 2a7ecbe..3d2d6a3 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"कॅमेराशी संबंधित काही समस्या आहेत का?\nपुन्हा फिट करण्यासाठी टॅप करा"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"निराकरण झाले नाही?\nरिव्हर्ट करण्यासाठी कृपया टॅप करा"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"कॅमेराशी संबंधित कोणत्याही समस्या नाहीत का? डिसमिस करण्यासाठी टॅप करा."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"<xliff:g id="APP_NAME">%s</xliff:g> चा पुरेपूर वापर करा"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"तुमची स्क्रीन पोर्ट्रेटवर फिरवा"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"तुमची स्क्रीन लॅंडस्केपवर फिरवा"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"स्प्लिट स्क्रीन वापरण्यासाठी दुसऱ्या ॲपमध्ये ड्रॅग करा"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"जागा बदलण्यासाठी दोनदा टॅप करा"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"समजले"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml
index c1ec74f..4e9a7e9 100644
--- a/libs/WindowManager/Shell/res/values-ms/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ms/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Isu kamera?\nKetik untuk memuatkan semula"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Isu tidak dibetulkan?\nKetik untuk kembali"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Tiada isu kamera? Ketik untuk mengetepikan."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Manfaatkan <xliff:g id="APP_NAME">%s</xliff:g> sepenuhnya"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Putar skrin anda kepada potret"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Putar skrin anda kepada landskap"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Seret ke dalam apl lain untuk menggunakan skrin pisah"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Ketik dua kali untuk menempatkan semula"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml
index fc1868f..449e502 100644
--- a/libs/WindowManager/Shell/res/values-my/strings.xml
+++ b/libs/WindowManager/Shell/res/values-my/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ကင်မရာပြဿနာလား။\nပြင်ဆင်ရန် တို့ပါ"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ကောင်းမသွားဘူးလား။\nပြန်ပြောင်းရန် တို့ပါ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ကင်မရာပြဿနာ မရှိဘူးလား။ ပယ်ရန် တို့ပါ။"</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"<xliff:g id="APP_NAME">%s</xliff:g> ကို အကောင်းဆုံးအသုံးချခြင်း"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"သင့်စခရင်ကို ဒေါင်လိုက်လှည့်နိုင်သည်"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"သင့်စခရင်ကို အလျားလိုက်လှည့်နိုင်သည်"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"မျက်နှာပြင် ခွဲ၍ပြသခြင်းသုံးရန် အက်ပ်နောက်တစ်ခုကို ဖိဆွဲနိုင်သည်"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"နေရာပြန်ချရန် နှစ်ချက်တို့နိုင်သည်"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ရပြီ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml
index 3eda48a..2172cc5 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Har du kameraproblemer?\nTrykk for å tilpasse"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Ble ikke problemet løst?\nTrykk for å gå tilbake"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Har du ingen kameraproblemer? Trykk for å lukke."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Få mest mulig ut av <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Roter skjermen til stående format"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Roter skjermen til liggende format"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Dra inn en annen app for å bruke delt skjerm"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Dobbelttrykk for å flytte"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Greit"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml
index 25db78e..ff01dcd 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"क्यामेरासम्बन्धी समस्या देखियो?\nसमस्या हल गर्न ट्याप गर्नुहोस्"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"समस्या हल भएन?\nपहिलेको जस्तै बनाउन ट्याप गर्नुहोस्"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"क्यामेरासम्बन्धी कुनै पनि समस्या छैन? खारेज गर्न ट्याप गर्नुहोस्।"</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"<xliff:g id="APP_NAME">%s</xliff:g> बाट बढीभन्दा बढी फाइदा लिनुहोस्"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"आफ्नो स्क्रिन पोर्ट्रेट मोडमा रोटेट गर्नुहोस्"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"आफ्नो स्क्रिन ल्यान्डस्केप मोडमा रोटेट गर्नुहोस्"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"तपाईं स्प्लिट स्क्रिन मोड प्रयोग गर्न चाहनुहुन्छ भने अर्को एप ड्रयाग एन्ड ड्रप गर्नुहोस्"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"एप यताउता सार्न डबल ट्याप गर्नुहोस्"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"बुझेँ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml
index 8f74258..428cb3f 100644
--- a/libs/WindowManager/Shell/res/values-nl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nl/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Cameraproblemen?\nTik om opnieuw passend te maken."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Is dit geen oplossing?\nTik om terug te zetten."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Geen cameraproblemen? Tik om te sluiten."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Haal het maximale uit <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Draai je scherm naar de staande stand"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Draai je scherm naar de liggende stand"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Sleep een andere app hier naartoe om het scherm te splitsen"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Dubbeltik om te herpositioneren"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml
index a709297..f9668a1 100644
--- a/libs/WindowManager/Shell/res/values-or/strings.xml
+++ b/libs/WindowManager/Shell/res/values-or/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"କ୍ୟାମେରାରେ ସମସ୍ୟା ଅଛି?\nପୁଣି ଫିଟ କରିବାକୁ ଟାପ କରନ୍ତୁ"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ଏହାର ସମାଧାନ ହୋଇନାହିଁ?\nଫେରିଯିବା ପାଇଁ ଟାପ କରନ୍ତୁ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"କ୍ୟାମେରାରେ କିଛି ସମସ୍ୟା ନାହିଁ? ଖାରଜ କରିବାକୁ ଟାପ କରନ୍ତୁ।"</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"<xliff:g id="APP_NAME">%s</xliff:g>ରୁ ସବୁଠାରୁ ଅଧିକ ସୁବିଧା ପାଆନ୍ତୁ"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"ପୋଟ୍ରେଟ ସ୍ଥିତି ପାଇଁ ଆପଣଙ୍କ ସ୍କ୍ରିନକୁ ରୋଟେଟ କରନ୍ତୁ"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"ଲ୍ୟାଣ୍ଡସ୍କେପ ସ୍ଥିତି ପାଇଁ ଆପଣଙ୍କ ସ୍କ୍ରିନକୁ ରୋଟେଟ କରନ୍ତୁ"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ବ୍ୟବହାର କରିବା ପାଇଁ ଅନ୍ୟ ଏକ ଆପକୁ ଡ୍ରାଗ କରନ୍ତୁ"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"ରିପୋଜିସନ ପାଇଁ ଦୁଇଥର ଟାପ କରନ୍ତୁ"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ବୁଝିଗଲି"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml
index 8c15678..7132597 100644
--- a/libs/WindowManager/Shell/res/values-pa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pa/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ਕੀ ਕੈਮਰੇ ਸੰਬੰਧੀ ਸਮੱਸਿਆਵਾਂ ਹਨ?\nਮੁੜ-ਫਿੱਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ਕੀ ਇਹ ਠੀਕ ਨਹੀਂ ਹੋਈ?\nਵਾਪਸ ਉਹੀ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ਕੀ ਕੈਮਰੇ ਸੰਬੰਧੀ ਕੋਈ ਸਮੱਸਿਆ ਨਹੀਂ ਹੈ? ਖਾਰਜ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"<xliff:g id="APP_NAME">%s</xliff:g> ਦਾ ਵੱਧ ਤੋਂ ਵੱਧ ਲਾਹਾ ਲਓ"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"ਪੋਰਟਰੇਟ ਕਰਨ ਲਈ ਆਪਣੀ ਸਕ੍ਰੀਨ ਨੂੰ ਘੁਮਾਓ"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"ਲੈਂਡਸਕੇਪ ਕਰਨ ਲਈ ਆਪਣੀ ਸਕ੍ਰੀਨ ਨੂੰ ਘੁਮਾਓ"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ ਕਿਸੇ ਹੋਰ ਐਪ ਵਿੱਚ ਘਸੀਟੋ"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"ਜਗ੍ਹਾ ਬਦਲਣ ਲਈ ਡਬਲ ਟੈਪ ਕਰੋ"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ਸਮਝ ਲਿਆ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml
index 8097995..f7f97ef 100644
--- a/libs/WindowManager/Shell/res/values-pl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pl/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemy z aparatem?\nKliknij, aby dopasować"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Naprawa się nie udała?\nKliknij, aby cofnąć"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Brak problemów z aparatem? Kliknij, aby zamknąć"</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Wykorzystaj wszystkie możliwości aplikacji <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Obróć ekran do orientacji pionowej"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Obróć ekran do orientacji poziomej"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Przeciągnij drugą aplikację, aby podzielić ekran"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Kliknij dwukrotnie, aby zmienić położenie"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
index 644e80e..a3d2ab0 100644
--- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemas com a câmera?\nToque para ajustar o enquadramento"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"O problema não foi corrigido?\nToque para reverter"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Não tem problemas com a câmera? Toque para dispensar."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Aproveite o app <xliff:g id="APP_NAME">%s</xliff:g> ao máximo"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Gire a tela para o modo retrato"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Gire a tela para o modo paisagem"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Arraste outro app para usar a tela dividida"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Toque duas vezes para reposicionar"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendi"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
index fac38a5..86872c8 100644
--- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemas com a câmara?\nToque aqui para reajustar"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Não foi corrigido?\nToque para reverter"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nenhum problema com a câmara? Toque para ignorar."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Tire o máximo partido da app <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Rode o ecrã para vertical"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Rode o ecrã para horizontal"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Arraste para utilizar o ecrã dividido"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Toque duas vezes para reposicionar"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml
index 644e80e..a3d2ab0 100644
--- a/libs/WindowManager/Shell/res/values-pt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemas com a câmera?\nToque para ajustar o enquadramento"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"O problema não foi corrigido?\nToque para reverter"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Não tem problemas com a câmera? Toque para dispensar."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Aproveite o app <xliff:g id="APP_NAME">%s</xliff:g> ao máximo"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Gire a tela para o modo retrato"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Gire a tela para o modo paisagem"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Arraste outro app para usar a tela dividida"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Toque duas vezes para reposicionar"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendi"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml
index e7d96cb..5448e45 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Aveți probleme cu camera foto?\nAtingeți pentru a reîncadra"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nu ați remediat problema?\nAtingeți pentru a reveni"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nu aveți probleme cu camera foto? Atingeți pentru a închide."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Beneficiați de toate avantajele <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Rotiți ecranul în orientarea portret"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Rotiți ecranul în orientarea peisaj"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Trageți în altă aplicație pentru a folosi ecranul împărțit"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Atingeți de două ori pentru a repoziționa"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml
index 046497d..64e74a2 100644
--- a/libs/WindowManager/Shell/res/values-ru/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ru/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Проблемы с камерой?\nНажмите, чтобы исправить."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Не помогло?\nНажмите, чтобы отменить изменения."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Нет проблем с камерой? Нажмите, чтобы закрыть."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Используйте все возможности приложения \"<xliff:g id="APP_NAME">%s</xliff:g>\""</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Поверните экран в вертикальное положение."</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Поверните экран в горизонтальное положение."</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Перетащите сюда другое приложение, чтобы использовать разделение экрана."</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Нажмите дважды, чтобы переместить окно."</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ОК"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml
index 0c604ff..3cdaa72 100644
--- a/libs/WindowManager/Shell/res/values-si/strings.xml
+++ b/libs/WindowManager/Shell/res/values-si/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"කැමරා ගැටලුද?\nයළි සවි කිරීමට තට්ටු කරන්න"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"එය විසඳුවේ නැතිද?\nප්රතිවර්තනය කිරීමට තට්ටු කරන්න"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"කැමරා ගැටලු නොමැතිද? ඉවත දැමීමට තට්ටු කරන්න"</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"<xliff:g id="APP_NAME">%s</xliff:g> වෙතින් උපරිම ප්රයෝජන ගන්න"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"ඔබගේ තිරය ප්රතිමූර්තියට කරකවන්න"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"ඔබගේ තිරය භූදර්ශනයට කරකවන්න"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"බෙදුම් තිරය භාවිත කිරීමට තවත් යෙදුමක් මෙතැනට අදින්න"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"නැවත ස්ථානගත කිරීමට දෙවරක් තට්ටු කරන්න"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"තේරුණා"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml
index f651080..daa2021 100644
--- a/libs/WindowManager/Shell/res/values-sk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sk/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problémy s kamerou?\nKlepnutím znova upravte."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nevyriešilo sa to?\nKlepnutím sa vráťte."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nemáte problémy s kamerou? Klepnutím zatvoríte."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Využívajte aplikáciu <xliff:g id="APP_NAME">%s</xliff:g> naplno"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Otočenie obrazovky na výšku"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Otočenie obrazovky na šírku"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Ak chcete použiť rozdelenú obrazovku, presuňte do inej aplikácie"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Dvojitým klepnutím premiestníte"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Dobre"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml
index 104b9a5..b4c7b95 100644
--- a/libs/WindowManager/Shell/res/values-sl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sl/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Težave s fotoaparatom?\nDotaknite se za vnovično prilagoditev"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"To ni odpravilo težave?\nDotaknite se za povrnitev"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nimate težav s fotoaparatom? Dotaknite se za opustitev."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Izkoristite aplikacijo <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Zasuk zaslona v pokončni položaj"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Zasuk zaslona v ležeči položaj"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Za razdeljeni zaslon povlecite sem še eno aplikacijo."</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Dvakrat se dotaknite za prestavljanje."</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"V redu"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml
index d0d485a..5051351 100644
--- a/libs/WindowManager/Shell/res/values-sq/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sq/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Ka probleme me kamerën?\nTrokit për ta ripërshtatur"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nuk u rregullua?\nTrokit për ta rikthyer"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nuk ka probleme me kamerën? Trokit për ta shpërfillur."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Përfito sa më shumë nga <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Rrotulloje ekranin vertikalisht"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Rrotulloje ekranin horizontalisht"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Zvarrite në një aplikacion tjetër për të përdorur ekranin e ndarë"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Trokit dy herë për ta risistemuar"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"E kuptova"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml
index 3b44181..96bb48a 100644
--- a/libs/WindowManager/Shell/res/values-sr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sr/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Имате проблема са камером?\nДодирните да бисте поново уклопили"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Проблем није решен?\nДодирните да бисте вратили"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Немате проблема са камером? Додирните да бисте одбацили."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Искористите апликацију <xliff:g id="APP_NAME">%s</xliff:g> на најбољи начин"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Ротирајте екран у усправни положај"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Ротирајте екран у водоравни положај"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Превуците другу апликацију да бисте користили подељени екран"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Двапут додирните ради премештања"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Важи"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml
index b066c9f..9fa5c19 100644
--- a/libs/WindowManager/Shell/res/values-sv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sv/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problem med kameran?\nTryck för att anpassa på nytt"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Löstes inte problemet?\nTryck för att återställa"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Inga problem med kameran? Tryck för att ignorera."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Få ut mesta möjliga av <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Rotera skärmen till stående läge"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Rotera skärmen till liggande läge"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Dra en annan app hit för att dela upp skärmen"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Tryck snabbt två gånger för att flytta"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml
index ea9d885..8c026f9 100644
--- a/libs/WindowManager/Shell/res/values-sw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sw/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Je, kuna hitilafu za kamera?\nGusa ili urekebishe"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Umeshindwa kurekebisha?\nGusa ili urejeshe nakala ya awali"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Je, hakuna hitilafu za kamera? Gusa ili uondoe."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Nufaika zaidi na <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Zungusha skrini iwe wima"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Zungusha skrini yako iwe mlalo"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Buruta ndani programu nyingine ili utumie skrini iliyogawanyika"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Gusa mara mbili ili uweke kwenye nafasi yake"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Nimeelewa"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml
index 30b9813..cb3d138 100644
--- a/libs/WindowManager/Shell/res/values-ta/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ta/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"கேமரா தொடர்பான சிக்கல்களா?\nமீண்டும் பொருத்த தட்டவும்"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"சிக்கல்கள் சரிசெய்யப்படவில்லையா?\nமாற்றியமைக்க தட்டவும்"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"கேமரா தொடர்பான சிக்கல்கள் எதுவும் இல்லையா? நிராகரிக்க தட்டவும்."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"<xliff:g id="APP_NAME">%s</xliff:g> ஆப்ஸில் அதிகப் பலன்களைப் பெறுங்கள்"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"திரையைப் போர்ட்ரெய்ட் பயன்முறைக்குச் சுழற்றலாம்"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"திரையை லேண்ட்ஸ்கேப் பயன்முறைக்குச் சுழற்றலாம்"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"திரைப் பிரிப்பைப் பயன்படுத்த மற்றொரு ஆப்ஸை இழுக்கலாம்"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"இடம் மாற்ற இருமுறை தட்டலாம்"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"சரி"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml
index fc4ab39..7589e70 100644
--- a/libs/WindowManager/Shell/res/values-te/strings.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"కెమెరా సమస్యలు ఉన్నాయా?\nరీఫిట్ చేయడానికి ట్యాప్ చేయండి"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"దాని సమస్యను పరిష్కరించలేదా?\nపూర్వస్థితికి మార్చడానికి ట్యాప్ చేయండి"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"కెమెరా సమస్యలు లేవా? తీసివేయడానికి ట్యాప్ చేయండి."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"<xliff:g id="APP_NAME">%s</xliff:g> నుండి మరిన్ని పొందండి"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"మీ స్క్రీన్ను పోర్ట్రెయిట్కు తిప్పండి"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"మీ స్క్రీన్ను ల్యాండ్స్కేప్కు తిప్పండి"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"స్ప్లిట్ స్క్రీన్ను ఉపయోగించడానికి మరొక యాప్లోకి లాగండి"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"స్థానాన్ని మార్చడానికి రెండుసార్లు నొక్కండి"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"అర్థమైంది"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml
index be0d61b..d8a33ff 100644
--- a/libs/WindowManager/Shell/res/values-th/strings.xml
+++ b/libs/WindowManager/Shell/res/values-th/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"หากพบปัญหากับกล้อง\nแตะเพื่อแก้ไข"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"หากไม่ได้แก้ไข\nแตะเพื่อเปลี่ยนกลับ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"หากไม่พบปัญหากับกล้อง แตะเพื่อปิด"</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"ใช้ประโยชน์สูงสุดจาก <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"หมุนหน้าจอเป็นแนวตั้ง"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"หมุนหน้าจอเป็นแนวนอน"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"ลากไปไว้ในแอปอื่นเพื่อใช้การแบ่งหน้าจอ"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"แตะสองครั้งเพื่อเปลี่ยนตำแหน่ง"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"รับทราบ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml
index cb8bb1d..35a58b3 100644
--- a/libs/WindowManager/Shell/res/values-tl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tl/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"May mga isyu sa camera?\nI-tap para i-refit"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Hindi ito naayos?\nI-tap para i-revert"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Walang isyu sa camera? I-tap para i-dismiss."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Sulitin ang <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"I-rotate sa portrait ang iyong screen"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"I-rotate sa landscape ang iyong screen"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Mag-drag ng ibang app para gamitin ang split screen"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"I-double tap para baguhin ang puwesto"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml
index 7f78fe9..8a9fb75 100644
--- a/libs/WindowManager/Shell/res/values-tr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tr/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kameranızda sorun mu var?\nDüzeltmek için dokunun"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Bu işlem sorunu düzeltmedi mi?\nİşlemi geri almak için dokunun"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kameranızda sorun yok mu? Kapatmak için dokunun."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"<xliff:g id="APP_NAME">%s</xliff:g> uygulamasından en iyi şekilde yararlanma"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Dikey görüntüleme için ekranınızı döndürün"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Yatay görüntüleme için ekranınızı döndürün"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Bölünmüş ekran kullanmak için başka bir uygulamayı sürükleyin"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Yeniden konumlandırmak için iki kez dokunun"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Anladım"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml
index 08fc023..aac9031 100644
--- a/libs/WindowManager/Shell/res/values-uk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uk/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Проблеми з камерою?\nНатисніть, щоб пристосувати"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Проблему не вирішено?\nНатисніть, щоб скасувати зміни"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Немає проблем із камерою? Торкніться, щоб закрити."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Використовуйте всі можливості додатка <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Змініть орієнтацію екрана на портретну"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Змініть орієнтацію екрана на альбомну"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Щоб перейти в режим розділення екрана, перетягніть інший додаток"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Двічі торкніться, щоб перемістити"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ОK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml
index cea12e5..e3bab32 100644
--- a/libs/WindowManager/Shell/res/values-ur/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ur/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"کیمرے کے مسائل؟\nدوبارہ فٹ کرنے کیلئے تھپتھپائیں"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"یہ حل نہیں ہوا؟\nلوٹانے کیلئے تھپتھپائیں"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"کوئی کیمرے کا مسئلہ نہیں ہے؟ برخاست کرنے کیلئے تھپتھپائیں۔"</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"<xliff:g id="APP_NAME">%s</xliff:g> سے بھر پور فائدہ حاصل کریں"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"اپنی سکرین کو پورٹریٹ میں گھمائيں"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"اپنی اسکرین کو لینڈ اسکیپ میں گھمائیں"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"اسپلٹ اسکرین استعمال کرنے کے ليے دوسری ایپ میں گھسیٹیں"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"پوزیشن تبدیل کرنے کے ليے دو بار تھپتھپائیں"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"سمجھ آ گئی"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml
index 980e46e..54ec89a 100644
--- a/libs/WindowManager/Shell/res/values-uz/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uz/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kamera nosozmi?\nQayta moslash uchun bosing"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Tuzatilmadimi?\nQaytarish uchun bosing"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kamera muammosizmi? Yopish uchun bosing."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"<xliff:g id="APP_NAME">%s</xliff:g> ilovasidan unumli foydalaning"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Boʻyiga koʻrishuchun ekranni buring"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Eniga koʻrish uchun ekranni buring"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Ekranni boʻlish xususiyatidan foydalanish uchun boshqa ilovani bu yerga torting"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Joyini oʻzgartirish uchun ikki marta bosing"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml
index 2f33799..b683702 100644
--- a/libs/WindowManager/Shell/res/values-vi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-vi/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Có vấn đề với máy ảnh?\nHãy nhấn để sửa lỗi"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Bạn chưa khắc phục vấn đề?\nHãy nhấn để hủy bỏ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Không có vấn đề với máy ảnh? Hãy nhấn để đóng."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Khai thác tối đa <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Xoay màn hình sang chế độ dọc"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Xoay màn hình sang chế độ ngang"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Kéo vào một ứng dụng khác để dùng chế độ chia đôi màn hình"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Nhấn đúp để thay đổi vị trí"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
index 48465c3..811d860 100644
--- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"相机有问题?\n点按即可整修"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"没有解决此问题?\n点按即可恢复"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"相机没有问题?点按即可忽略。"</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"充分利用 <xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"将屏幕旋转成纵向模式"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"将屏幕旋转成横向模式"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"拖入另一个应用,即可使用分屏模式"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"点按两次即可调整位置"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"知道了"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
index 18f7fa2..2a01714 100644
--- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"相機有問題?\n輕按即可修正"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"未能修正問題?\n輕按即可還原"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"相機冇問題?㩒一下就可以即可閂咗佢。"</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"充分善用「<xliff:g id="APP_NAME">%s</xliff:g>」"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"將螢幕旋轉為直向"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"將螢幕旋轉為橫向"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"拖入另一個應用程式即可使用分割螢幕"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"輕按兩下即可調整位置"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"知道了"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
index 7bc48ae..292a439 100644
--- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"相機有問題嗎?\n輕觸即可修正"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"未修正問題嗎?\n輕觸即可還原"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"相機沒問題嗎?輕觸即可關閉。"</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"充分發揮「<xliff:g id="APP_NAME">%s</xliff:g>」的各項功能"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"將螢幕轉成直向"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"將螢幕轉成橫向"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"拖進另一個應用程式即可使用分割畫面"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"輕觸兩下即可調整位置"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"我知道了"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml
index 5da9fa1..389eb08 100644
--- a/libs/WindowManager/Shell/res/values-zu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zu/strings.xml
@@ -76,10 +76,13 @@
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Izinkinga zekhamera?\nThepha ukuze uyilinganise kabusha"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Akuyilungisanga?\nThepha ukuze ubuyele"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Azikho izinkinga zekhamera? Thepha ukuze ucashise."</string>
- <string name="letterbox_education_dialog_title" msgid="3924745395335329810">"Thola okuningi ku-<xliff:g id="APP_NAME">%s</xliff:g>"</string>
- <string name="letterbox_education_screen_rotation_portrait_text" msgid="9005616635100891260">"Zungezisa isikrini sakho sime ngobude"</string>
- <string name="letterbox_education_screen_rotation_landscape_text" msgid="7619609293250631225">"Zungezisa isikrini sakho sibe sime ngokuvundla"</string>
- <string name="letterbox_education_split_screen_text" msgid="3906978051324735033">"Hudula kwenye i-app ukuze usebenzise isikrini esihlukanisiwe"</string>
- <string name="letterbox_education_reposition_text" msgid="8597800472592539168">"Thepha kabili ukuze ubeke kabusha"</string>
+ <!-- no translation found for letterbox_education_dialog_title (6688664582871779215) -->
+ <skip />
+ <!-- no translation found for letterbox_education_dialog_subtext (4853542518367719562) -->
+ <skip />
+ <!-- no translation found for letterbox_education_screen_rotation_text (5085786687366339027) -->
+ <skip />
+ <!-- no translation found for letterbox_education_reposition_text (1068293354123934727) -->
+ <skip />
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Ngiyezwa"</string>
</resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
index 9a6df23..7cf3597 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
@@ -17,6 +17,7 @@
package com.android.wm.shell.back;
import android.view.MotionEvent;
+import android.window.BackEvent;
import com.android.wm.shell.common.annotations.ExternalThread;
@@ -29,7 +30,7 @@
/**
* Called when a {@link MotionEvent} is generated by a back gesture.
*/
- void onBackMotion(MotionEvent event);
+ void onBackMotion(MotionEvent event, @BackEvent.SwipeEdge int swipeEdge);
/**
* Sets whether the back gesture is past the trigger threshold or not.
@@ -42,4 +43,11 @@
default IBackAnimation createExternalInterface() {
return null;
}
+
+ /**
+ * Sets the threshold values that defining edge swipe behavior.
+ * @param triggerThreshold the min threshold to trigger back.
+ * @param progressThreshold the max threshold to keep progressing back animation.
+ */
+ void setSwipeThresholds(float triggerThreshold, float progressThreshold);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index a5140c3..8d5fdfb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -35,7 +35,9 @@
import android.os.SystemProperties;
import android.util.Log;
import android.view.MotionEvent;
+import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
+import android.window.BackEvent;
import android.window.BackNavigationInfo;
import android.window.IOnBackInvokedCallback;
@@ -53,6 +55,10 @@
private static final String BACK_PREDICTABILITY_PROP = "persist.debug.back_predictability";
public static final boolean IS_ENABLED = SystemProperties
.getInt(BACK_PREDICTABILITY_PROP, 0) > 0;
+ private static final String BACK_PREDICTABILITY_PROGRESS_THRESHOLD_PROP =
+ "persist.debug.back_predictability_progress_threshold";
+ private static final int PROGRESS_THRESHOLD = SystemProperties
+ .getInt(BACK_PREDICTABILITY_PROGRESS_THRESHOLD_PROP, -1);
private static final String TAG = "BackAnimationController";
/**
@@ -79,6 +85,8 @@
private final Context mContext;
@Nullable
private IOnBackInvokedCallback mBackToLauncherCallback;
+ private float mTriggerThreshold;
+ private float mProgressThreshold;
public BackAnimationController(
@ShellMainThread ShellExecutor shellExecutor,
@@ -127,14 +135,20 @@
}
@Override
- public void onBackMotion(MotionEvent event) {
- mShellExecutor.execute(() -> onMotionEvent(event));
+ public void onBackMotion(MotionEvent event, @BackEvent.SwipeEdge int swipeEdge) {
+ mShellExecutor.execute(() -> onMotionEvent(event, swipeEdge));
}
@Override
public void setTriggerBack(boolean triggerBack) {
mShellExecutor.execute(() -> BackAnimationController.this.setTriggerBack(triggerBack));
}
+
+ @Override
+ public void setSwipeThresholds(float triggerThreshold, float progressThreshold) {
+ mShellExecutor.execute(() -> BackAnimationController.this.setSwipeThresholds(
+ triggerThreshold, progressThreshold));
+ }
}
private static class IBackAnimationImpl extends IBackAnimation.Stub {
@@ -167,7 +181,8 @@
}
}
- private void setBackToLauncherCallback(IOnBackInvokedCallback callback) {
+ @VisibleForTesting
+ void setBackToLauncherCallback(IOnBackInvokedCallback callback) {
mBackToLauncherCallback = callback;
}
@@ -176,6 +191,14 @@
}
private void onBackToLauncherAnimationFinished() {
+ if (mBackNavigationInfo != null) {
+ IOnBackInvokedCallback callback = mBackNavigationInfo.getOnBackInvokedCallback();
+ if (mTriggerBack) {
+ dispatchOnBackInvoked(callback);
+ } else {
+ dispatchOnBackCancelled(callback);
+ }
+ }
finishAnimation();
}
@@ -183,12 +206,12 @@
* Called when a new motion event needs to be transferred to this
* {@link BackAnimationController}
*/
- public void onMotionEvent(MotionEvent event) {
+ public void onMotionEvent(MotionEvent event, @BackEvent.SwipeEdge int swipeEdge) {
int action = event.getActionMasked();
if (action == MotionEvent.ACTION_DOWN) {
initAnimation(event);
} else if (action == MotionEvent.ACTION_MOVE) {
- onMove(event);
+ onMove(event, swipeEdge);
} else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
onGestureFinished();
}
@@ -217,19 +240,27 @@
}
private void onBackNavigationInfoReceived(@Nullable BackNavigationInfo backNavigationInfo) {
- if (backNavigationInfo == null
- || backNavigationInfo.getDepartingWindowContainer() == null) {
+ ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Received backNavigationInfo:%s", backNavigationInfo);
+ if (backNavigationInfo == null) {
Log.e(TAG, "Received BackNavigationInfo is null.");
finishAnimation();
return;
}
-
- HardwareBuffer hardwareBuffer = backNavigationInfo.getScreenshotHardwareBuffer();
- if (hardwareBuffer != null) {
- displayTargetScreenshot(hardwareBuffer,
- backNavigationInfo.getTaskWindowConfiguration());
+ int backType = backNavigationInfo.getType();
+ IOnBackInvokedCallback targetCallback = null;
+ if (backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY) {
+ HardwareBuffer hardwareBuffer = backNavigationInfo.getScreenshotHardwareBuffer();
+ if (hardwareBuffer != null) {
+ displayTargetScreenshot(hardwareBuffer,
+ backNavigationInfo.getTaskWindowConfiguration());
+ }
+ mTransaction.apply();
+ } else if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME) {
+ targetCallback = mBackToLauncherCallback;
+ } else if (backType == BackNavigationInfo.TYPE_CALLBACK) {
+ targetCallback = mBackNavigationInfo.getOnBackInvokedCallback();
}
- mTransaction.apply();
+ dispatchOnBackStarted(targetCallback);
}
/**
@@ -264,30 +295,110 @@
mTransaction.setVisibility(screenshotSurface, true);
}
- private void onMove(MotionEvent event) {
+ private void onMove(MotionEvent event, @BackEvent.SwipeEdge int swipeEdge) {
if (!mBackGestureStarted || mBackNavigationInfo == null) {
return;
}
int deltaX = Math.round(event.getX() - mInitTouchLocation.x);
int deltaY = Math.round(event.getY() - mInitTouchLocation.y);
ProtoLog.v(WM_SHELL_BACK_PREVIEW, "Runner move: %d %d", deltaX, deltaY);
- SurfaceControl topWindowLeash = mBackNavigationInfo.getDepartingWindowContainer();
- mTransaction.setPosition(topWindowLeash, deltaX, deltaY);
- mTouchEventDelta.set(deltaX, deltaY);
- mTransaction.apply();
+ float progressThreshold = PROGRESS_THRESHOLD >= 0 ? PROGRESS_THRESHOLD : mProgressThreshold;
+ float progress = Math.min(Math.max(Math.abs(deltaX) / progressThreshold, 0), 1);
+ int backType = mBackNavigationInfo.getType();
+ RemoteAnimationTarget animationTarget = mBackNavigationInfo.getDepartingAnimationTarget();
+
+ BackEvent backEvent = new BackEvent(0, 0, progress, swipeEdge, animationTarget);
+ IOnBackInvokedCallback targetCallback = null;
+ if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME) {
+ targetCallback = mBackToLauncherCallback;
+ } else if (backType == BackNavigationInfo.TYPE_CROSS_TASK
+ || backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY) {
+ if (animationTarget != null) {
+ mTransaction.setPosition(animationTarget.leash, deltaX, deltaY);
+ mTouchEventDelta.set(deltaX, deltaY);
+ mTransaction.apply();
+ }
+ } else if (backType == BackNavigationInfo.TYPE_CALLBACK) {
+ targetCallback = mBackNavigationInfo.getOnBackInvokedCallback();
+ }
+ dispatchOnBackProgressed(targetCallback, backEvent);
}
private void onGestureFinished() {
ProtoLog.d(WM_SHELL_BACK_PREVIEW, "onGestureFinished() mTriggerBack == %s", mTriggerBack);
- if (mBackGestureStarted) {
+ if (!mBackGestureStarted || mBackNavigationInfo == null) {
+ return;
+ }
+ int backType = mBackNavigationInfo.getType();
+ boolean shouldDispatchToLauncher = backType == BackNavigationInfo.TYPE_RETURN_TO_HOME
+ && mBackToLauncherCallback != null;
+ IOnBackInvokedCallback targetCallback = shouldDispatchToLauncher
+ ? mBackToLauncherCallback
+ : mBackNavigationInfo.getOnBackInvokedCallback();
+ if (mTriggerBack) {
+ dispatchOnBackInvoked(targetCallback);
+ } else {
+ dispatchOnBackCancelled(targetCallback);
+ }
+ if (backType == BackNavigationInfo.TYPE_CALLBACK) {
+ finishAnimation();
+ } else if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME
+ && !shouldDispatchToLauncher) {
+ // Launcher callback missing. Simply finish animation.
+ finishAnimation();
+ } else if (backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY
+ || backType == BackNavigationInfo.TYPE_CROSS_TASK) {
if (mTriggerBack) {
prepareTransition();
} else {
resetPositionAnimated();
}
}
- mBackGestureStarted = false;
- mTriggerBack = false;
+ }
+
+ private static void dispatchOnBackStarted(IOnBackInvokedCallback callback) {
+ if (callback == null) {
+ return;
+ }
+ try {
+ callback.onBackStarted();
+ } catch (RemoteException e) {
+ Log.e(TAG, "dispatchOnBackStarted error: ", e);
+ }
+ }
+
+ private static void dispatchOnBackInvoked(IOnBackInvokedCallback callback) {
+ if (callback == null) {
+ return;
+ }
+ try {
+ callback.onBackInvoked();
+ } catch (RemoteException e) {
+ Log.e(TAG, "dispatchOnBackInvoked error: ", e);
+ }
+ }
+
+ private static void dispatchOnBackCancelled(IOnBackInvokedCallback callback) {
+ if (callback == null) {
+ return;
+ }
+ try {
+ callback.onBackCancelled();
+ } catch (RemoteException e) {
+ Log.e(TAG, "dispatchOnBackCancelled error: ", e);
+ }
+ }
+
+ private static void dispatchOnBackProgressed(
+ IOnBackInvokedCallback callback, BackEvent backEvent) {
+ if (callback == null) {
+ return;
+ }
+ try {
+ callback.onBackProgressed(backEvent);
+ } catch (RemoteException e) {
+ Log.e(TAG, "dispatchOnBackProgressed error: ", e);
+ }
}
/**
@@ -308,9 +419,12 @@
float fraction = animation1.getAnimatedFraction();
int deltaX = Math.round(mTouchEventDelta.x - (mTouchEventDelta.x * fraction));
int deltaY = Math.round(mTouchEventDelta.y - (mTouchEventDelta.y * fraction));
- mTransaction.setPosition(mBackNavigationInfo.getDepartingWindowContainer(),
- deltaX, deltaY);
- mTransaction.apply();
+ RemoteAnimationTarget animationTarget =
+ mBackNavigationInfo.getDepartingAnimationTarget();
+ if (animationTarget != null) {
+ mTransaction.setPosition(animationTarget.leash, deltaX, deltaY);
+ mTransaction.apply();
+ }
});
animation.addListener(new AnimatorListenerAdapter() {
@@ -336,25 +450,34 @@
mTriggerBack = triggerBack;
}
+ private void setSwipeThresholds(float triggerThreshold, float progressThreshold) {
+ mProgressThreshold = progressThreshold;
+ mTriggerThreshold = triggerThreshold;
+ }
+
private void finishAnimation() {
ProtoLog.d(WM_SHELL_BACK_PREVIEW, "BackAnimationController: finishAnimation()");
mBackGestureStarted = false;
mTouchEventDelta.set(0, 0);
mInitTouchLocation.set(0, 0);
BackNavigationInfo backNavigationInfo = mBackNavigationInfo;
+ boolean triggerBack = mTriggerBack;
mBackNavigationInfo = null;
+ mTriggerBack = false;
if (backNavigationInfo == null) {
return;
}
- SurfaceControl topWindowLeash = backNavigationInfo.getDepartingWindowContainer();
- if (topWindowLeash != null && topWindowLeash.isValid()) {
- mTransaction.remove(topWindowLeash);
+ RemoteAnimationTarget animationTarget = backNavigationInfo.getDepartingAnimationTarget();
+ if (animationTarget != null && mTriggerBack) {
+ if (animationTarget.leash != null && animationTarget.leash.isValid()) {
+ mTransaction.remove(animationTarget.leash);
+ }
}
SurfaceControl screenshotSurface = backNavigationInfo.getScreenshotSurface();
if (screenshotSurface != null && screenshotSurface.isValid()) {
mTransaction.remove(screenshotSurface);
}
mTransaction.apply();
- backNavigationInfo.onBackNavigationFinished();
+ backNavigationInfo.onBackNavigationFinished(triggerBack);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java
index c52d87d..79e6242 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java
@@ -367,4 +367,9 @@
void hideBadge() {
mAppIcon.setVisibility(GONE);
}
+
+ @Override
+ public String toString() {
+ return "BadgedImageView{" + mBubble + "}";
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 57cb7a5..6ffcf10 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -24,6 +24,7 @@
import static android.view.View.VISIBLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_CONTROLLER;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.wm.shell.bubbles.BubblePositioner.TASKBAR_POSITION_BOTTOM;
@@ -616,8 +617,9 @@
return mTaskViewTransitions;
}
- /** Contains information to help position things on the screen. */
- BubblePositioner getPositioner() {
+ /** Contains information to help position things on the screen. */
+ @VisibleForTesting
+ public BubblePositioner getPositioner() {
return mBubblePositioner;
}
@@ -659,8 +661,8 @@
ViewGroup.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
PixelFormat.TRANSLUCENT);
mWmLayoutParams.setTrustedOverlay();
@@ -750,7 +752,7 @@
// First clear any existing keys that might be stored.
mSavedBubbleKeysPerUser.remove(userId);
// Add in all active bubbles for the current user.
- for (Bubble bubble: mBubbleData.getBubbles()) {
+ for (Bubble bubble : mBubbleData.getBubbles()) {
mSavedBubbleKeysPerUser.add(userId, bubble.getKey());
}
}
@@ -982,9 +984,9 @@
/**
* Adds or updates a bubble associated with the provided notification entry.
*
- * @param notif the notification associated with this bubble.
+ * @param notif the notification associated with this bubble.
* @param suppressFlyout this bubble suppress flyout or not.
- * @param showInShade this bubble show in shade or not.
+ * @param showInShade this bubble show in shade or not.
*/
@VisibleForTesting
public void updateBubble(BubbleEntry notif, boolean suppressFlyout, boolean showInShade) {
@@ -992,11 +994,17 @@
mSysuiProxy.setNotificationInterruption(notif.getKey());
if (!notif.getRanking().isTextChanged()
&& (notif.getBubbleMetadata() != null
- && !notif.getBubbleMetadata().getAutoExpandBubble())
+ && !notif.getBubbleMetadata().getAutoExpandBubble())
&& mBubbleData.hasOverflowBubbleWithKey(notif.getKey())) {
// Update the bubble but don't promote it out of overflow
Bubble b = mBubbleData.getOverflowBubbleWithKey(notif.getKey());
b.setEntry(notif);
+ } else if (mBubbleData.isSuppressedWithLocusId(notif.getLocusId())) {
+ // Update the bubble but don't promote it out of overflow
+ Bubble b = mBubbleData.getSuppressedBubbleWithKey(notif.getKey());
+ if (b != null) {
+ b.setEntry(notif);
+ }
} else {
Bubble bubble = mBubbleData.getOrCreateBubble(notif, null /* persistedBubble */);
inflateAndAdd(bubble, suppressFlyout, showInShade);
@@ -1170,6 +1178,18 @@
@Override
public void applyUpdate(BubbleData.Update update) {
+ if (DEBUG_BUBBLE_CONTROLLER) {
+ Log.d(TAG, "applyUpdate:" + " bubbleAdded=" + (update.addedBubble != null)
+ + " bubbleRemoved="
+ + (update.removedBubbles != null && update.removedBubbles.size() > 0)
+ + " bubbleUpdated=" + (update.updatedBubble != null)
+ + " orderChanged=" + update.orderChanged
+ + " expandedChanged=" + update.expandedChanged
+ + " selectionChanged=" + update.selectionChanged
+ + " suppressed=" + (update.suppressedBubble != null)
+ + " unsuppressed=" + (update.unsuppressedBubble != null));
+ }
+
ensureStackViewCreated();
// Lazy load overflow bubbles from disk
@@ -1249,6 +1269,14 @@
mStackView.updateBubble(update.updatedBubble);
}
+ if (update.suppressedBubble != null && mStackView != null) {
+ mStackView.setBubbleSuppressed(update.suppressedBubble, true);
+ }
+
+ if (update.unsuppressedBubble != null && mStackView != null) {
+ mStackView.setBubbleSuppressed(update.unsuppressedBubble, false);
+ }
+
// At this point, the correct bubbles are inflated in the stack.
// Make sure the order in bubble data is reflected in bubble row.
if (update.orderChanged && mStackView != null) {
@@ -1263,14 +1291,6 @@
}
}
- if (update.suppressedBubble != null && mStackView != null) {
- mStackView.setBubbleVisibility(update.suppressedBubble, false);
- }
-
- if (update.unsuppressedBubble != null && mStackView != null) {
- mStackView.setBubbleVisibility(update.unsuppressedBubble, true);
- }
-
// Expanding? Apply this last.
if (update.expandedChanged && update.expanded) {
if (mStackView != null) {
@@ -1398,7 +1418,7 @@
* that should filter out any invalid bubbles, but should protect SysUI side just in case.
*
* @param context the context to use.
- * @param entry the entry to bubble.
+ * @param entry the entry to bubble.
*/
static boolean canLaunchInTaskView(Context context, BubbleEntry entry) {
PendingIntent intent = entry.getBubbleMetadata() != null
@@ -1531,7 +1551,7 @@
String groupKey) {
return mSuppressedBubbleKeys.contains(key)
|| (mSuppressedGroupToNotifKeys.containsKey(groupKey)
- && key.equals(mSuppressedGroupToNotifKeys.get(groupKey)));
+ && key.equals(mSuppressedGroupToNotifKeys.get(groupKey)));
}
@Nullable
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index 51b7eaa..9961ad7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -224,7 +224,8 @@
}
public boolean hasAnyBubbleWithKey(String key) {
- return hasBubbleInStackWithKey(key) || hasOverflowBubbleWithKey(key);
+ return hasBubbleInStackWithKey(key) || hasOverflowBubbleWithKey(key)
+ || hasSuppressedBubbleWithKey(key);
}
public boolean hasBubbleInStackWithKey(String key) {
@@ -235,6 +236,20 @@
return getOverflowBubbleWithKey(key) != null;
}
+ /**
+ * Check if there are any bubbles suppressed with the given notification <code>key</code>
+ */
+ public boolean hasSuppressedBubbleWithKey(String key) {
+ return mSuppressedBubbles.values().stream().anyMatch(b -> b.getKey().equals(key));
+ }
+
+ /**
+ * Check if there are any bubbles suppressed with the given <code>LocusId</code>
+ */
+ public boolean isSuppressedWithLocusId(LocusId locusId) {
+ return mSuppressedBubbles.get(locusId) != null;
+ }
+
@Nullable
public BubbleViewProvider getSelectedBubble() {
return mSelectedBubble;
@@ -356,11 +371,11 @@
boolean isSuppressed = mSuppressedBubbles.containsKey(locusId);
if (isSuppressed && (!bubble.isSuppressed() || !bubble.isSuppressable())) {
mSuppressedBubbles.remove(locusId);
- mStateChange.unsuppressedBubble = bubble;
+ doUnsuppress(bubble);
} else if (!isSuppressed && (bubble.isSuppressed()
|| bubble.isSuppressable() && mVisibleLocusIds.contains(locusId))) {
mSuppressedBubbles.put(locusId, bubble);
- mStateChange.suppressedBubble = bubble;
+ doSuppress(bubble);
}
}
dispatchPendingChanges();
@@ -532,16 +547,19 @@
if (mPendingBubbles.containsKey(key)) {
mPendingBubbles.remove(key);
}
+
+ boolean shouldRemoveHiddenBubble = reason == Bubbles.DISMISS_NOTIF_CANCEL
+ || reason == Bubbles.DISMISS_GROUP_CANCELLED
+ || reason == Bubbles.DISMISS_NO_LONGER_BUBBLE
+ || reason == Bubbles.DISMISS_BLOCKED
+ || reason == Bubbles.DISMISS_SHORTCUT_REMOVED
+ || reason == Bubbles.DISMISS_PACKAGE_REMOVED
+ || reason == Bubbles.DISMISS_USER_CHANGED;
+
int indexToRemove = indexForKey(key);
if (indexToRemove == -1) {
if (hasOverflowBubbleWithKey(key)
- && (reason == Bubbles.DISMISS_NOTIF_CANCEL
- || reason == Bubbles.DISMISS_GROUP_CANCELLED
- || reason == Bubbles.DISMISS_NO_LONGER_BUBBLE
- || reason == Bubbles.DISMISS_BLOCKED
- || reason == Bubbles.DISMISS_SHORTCUT_REMOVED
- || reason == Bubbles.DISMISS_PACKAGE_REMOVED
- || reason == Bubbles.DISMISS_USER_CHANGED)) {
+ && shouldRemoveHiddenBubble) {
Bubble b = getOverflowBubbleWithKey(key);
if (DEBUG_BUBBLE_DATA) {
@@ -555,6 +573,17 @@
mStateChange.bubbleRemoved(b, reason);
mStateChange.removedOverflowBubble = b;
}
+ if (hasSuppressedBubbleWithKey(key) && shouldRemoveHiddenBubble) {
+ Bubble b = getSuppressedBubbleWithKey(key);
+ if (DEBUG_BUBBLE_DATA) {
+ Log.d(TAG, "Cancel suppressed bubble: " + b);
+ }
+ if (b != null) {
+ mSuppressedBubbles.remove(b.getLocusId());
+ b.stopInflation();
+ mStateChange.bubbleRemoved(b, reason);
+ }
+ }
return;
}
Bubble bubbleToRemove = mBubbles.get(indexToRemove);
@@ -579,19 +608,73 @@
// Note: If mBubbles.isEmpty(), then mSelectedBubble is now null.
if (Objects.equals(mSelectedBubble, bubbleToRemove)) {
- // Move selection to the new bubble at the same position.
- int newIndex = Math.min(indexToRemove, mBubbles.size() - 1);
- BubbleViewProvider newSelected = mBubbles.get(newIndex);
- setSelectedBubbleInternal(newSelected);
+ setNewSelectedIndex(indexToRemove);
}
maybeSendDeleteIntent(reason, bubbleToRemove);
}
+ private void setNewSelectedIndex(int indexOfSelected) {
+ if (mBubbles.isEmpty()) {
+ Log.w(TAG, "Bubbles list empty when attempting to select index: " + indexOfSelected);
+ return;
+ }
+ // Move selection to the new bubble at the same position.
+ int newIndex = Math.min(indexOfSelected, mBubbles.size() - 1);
+ if (DEBUG_BUBBLE_DATA) {
+ Log.d(TAG, "setNewSelectedIndex: " + indexOfSelected);
+ }
+ BubbleViewProvider newSelected = mBubbles.get(newIndex);
+ setSelectedBubbleInternal(newSelected);
+ }
+
+ private void doSuppress(Bubble bubble) {
+ if (DEBUG_BUBBLE_DATA) {
+ Log.d(TAG, "doSuppressed: " + bubble);
+ }
+ mStateChange.suppressedBubble = bubble;
+ bubble.setSuppressBubble(true);
+
+ int indexToRemove = mBubbles.indexOf(bubble);
+ // Order changes if we are not suppressing the last bubble
+ mStateChange.orderChanged = !(mBubbles.size() - 1 == indexToRemove);
+ mBubbles.remove(indexToRemove);
+
+ // Update selection if we suppressed the selected bubble
+ if (Objects.equals(mSelectedBubble, bubble)) {
+ if (mBubbles.isEmpty()) {
+ // Don't use setSelectedBubbleInternal because we don't want to trigger an
+ // applyUpdate
+ mSelectedBubble = null;
+ } else {
+ // Mark new first bubble as selected
+ setNewSelectedIndex(0);
+ }
+ }
+ }
+
+ private void doUnsuppress(Bubble bubble) {
+ if (DEBUG_BUBBLE_DATA) {
+ Log.d(TAG, "doUnsuppressed: " + bubble);
+ }
+ bubble.setSuppressBubble(false);
+ mStateChange.unsuppressedBubble = bubble;
+ mBubbles.add(bubble);
+ if (mBubbles.size() > 1) {
+ // See where the bubble actually lands
+ repackAll();
+ mStateChange.orderChanged = true;
+ }
+ if (mBubbles.get(0) == bubble) {
+ // Unsuppressed bubble is sorted to first position. Mark it as the selected.
+ setNewSelectedIndex(0);
+ }
+ }
+
void overflowBubble(@DismissReason int reason, Bubble bubble) {
if (bubble.getPendingIntentCanceled()
|| !(reason == Bubbles.DISMISS_AGED
- || reason == Bubbles.DISMISS_USER_GESTURE
- || reason == Bubbles.DISMISS_RELOAD_FROM_DISK)) {
+ || reason == Bubbles.DISMISS_USER_GESTURE
+ || reason == Bubbles.DISMISS_RELOAD_FROM_DISK)) {
return;
}
if (DEBUG_BUBBLE_DATA) {
@@ -619,7 +702,7 @@
if (DEBUG_BUBBLE_DATA) {
Log.d(TAG, "dismissAll: reason=" + reason);
}
- if (mBubbles.isEmpty()) {
+ if (mBubbles.isEmpty() && mSuppressedBubbles.isEmpty()) {
return;
}
setExpandedInternal(false);
@@ -627,6 +710,10 @@
while (!mBubbles.isEmpty()) {
doRemove(mBubbles.get(0).getKey(), reason);
}
+ while (!mSuppressedBubbles.isEmpty()) {
+ Bubble bubble = mSuppressedBubbles.removeAt(0);
+ doRemove(bubble.getKey(), reason);
+ }
dispatchPendingChanges();
}
@@ -635,11 +722,15 @@
* and if there's a matching bubble for that locusId then the bubble may be hidden or shown
* depending on the visibility of the locusId.
*
- * @param taskId the taskId associated with the locusId visibility change.
+ * @param taskId the taskId associated with the locusId visibility change.
* @param locusId the locusId whose visibility has changed.
* @param visible whether the task with the locusId is visible or not.
*/
public void onLocusVisibilityChanged(int taskId, LocusId locusId, boolean visible) {
+ if (DEBUG_BUBBLE_DATA) {
+ Log.d(TAG, "onLocusVisibilityChanged: " + locusId + " visible=" + visible);
+ }
+
Bubble matchingBubble = getBubbleInStackWithLocusId(locusId);
// Don't add the locus if it's from a bubble'd activity, we only suppress for non-bubbled.
if (visible && (matchingBubble == null || matchingBubble.getTaskId() != taskId)) {
@@ -648,20 +739,22 @@
mVisibleLocusIds.remove(locusId);
}
if (matchingBubble == null) {
- return;
+ // Check if there is a suppressed bubble for this LocusId
+ matchingBubble = mSuppressedBubbles.get(locusId);
+ if (matchingBubble == null) {
+ return;
+ }
}
boolean isAlreadySuppressed = mSuppressedBubbles.get(locusId) != null;
if (visible && !isAlreadySuppressed && matchingBubble.isSuppressable()
&& taskId != matchingBubble.getTaskId()) {
mSuppressedBubbles.put(locusId, matchingBubble);
- matchingBubble.setSuppressBubble(true);
- mStateChange.suppressedBubble = matchingBubble;
+ doSuppress(matchingBubble);
dispatchPendingChanges();
} else if (!visible) {
Bubble unsuppressedBubble = mSuppressedBubbles.remove(locusId);
if (unsuppressedBubble != null) {
- unsuppressedBubble.setSuppressBubble(false);
- mStateChange.unsuppressedBubble = unsuppressedBubble;
+ doUnsuppress(unsuppressedBubble);
}
dispatchPendingChanges();
}
@@ -720,14 +813,14 @@
/**
* Logs the bubble UI event.
*
- * @param provider The bubble view provider that is being interacted on. Null value indicates
- * that the user interaction is not specific to one bubble.
- * @param action The user interaction enum
+ * @param provider The bubble view provider that is being interacted on. Null value indicates
+ * that the user interaction is not specific to one bubble.
+ * @param action The user interaction enum
* @param packageName SystemUI package
* @param bubbleCount Number of bubbles in the stack
* @param bubbleIndex Index of bubble in the stack
- * @param normalX Normalized x position of the stack
- * @param normalY Normalized y position of the stack
+ * @param normalX Normalized x position of the stack
+ * @param normalY Normalized y position of the stack
*/
void logBubbleEvent(@Nullable BubbleViewProvider provider, int action, String packageName,
int bubbleCount, int bubbleIndex, float normalX, float normalY) {
@@ -869,6 +962,9 @@
if (b == null) {
b = getOverflowBubbleWithKey(key);
}
+ if (b == null) {
+ b = getSuppressedBubbleWithKey(key);
+ }
return b;
}
@@ -946,6 +1042,23 @@
return null;
}
+ /**
+ * Get a suppressed bubble with given notification <code>key</code>
+ *
+ * @param key notification key
+ * @return bubble that matches or null
+ */
+ @Nullable
+ @VisibleForTesting(visibility = PRIVATE)
+ public Bubble getSuppressedBubbleWithKey(String key) {
+ for (Bubble b : mSuppressedBubbles.values()) {
+ if (b.getKey().equals(key)) {
+ return b;
+ }
+ }
+ return null;
+ }
+
@VisibleForTesting(visibility = PRIVATE)
void setTimeSource(TimeSource timeSource) {
mTimeSource = timeSource;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index 9ae67a9..da8308e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -60,6 +60,7 @@
import androidx.annotation.Nullable;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.wm.shell.R;
import com.android.wm.shell.TaskView;
@@ -418,8 +419,9 @@
mPointerView.setBackground(mCurrentPointer);
}
- private String getBubbleKey() {
- return mBubble != null ? mBubble.getKey() : "null";
+ @VisibleForTesting
+ public String getBubbleKey() {
+ return mBubble != null ? mBubble.getKey() : mIsOverflow ? BubbleOverflow.KEY : null;
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
index dd751d2..eb7929b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
@@ -54,6 +54,7 @@
/** Call before use and again if cleanUpExpandedState was called. */
fun initialize(controller: BubbleController) {
+ createExpandedView()
getExpandedView()?.initialize(controller, controller.stackView, true /* isOverflow */)
}
@@ -123,13 +124,15 @@
overflowBtn?.updateDotVisibility(true /* animate */)
}
+ fun createExpandedView(): BubbleExpandedView? {
+ expandedView = inflater.inflate(R.layout.bubble_expanded_view,
+ null /* root */, false /* attachToRoot */) as BubbleExpandedView
+ expandedView?.applyThemeAttrs()
+ updateResources()
+ return expandedView
+ }
+
override fun getExpandedView(): BubbleExpandedView? {
- if (expandedView == null) {
- expandedView = inflater.inflate(R.layout.bubble_expanded_view,
- null /* root */, false /* attachToRoot */) as BubbleExpandedView
- expandedView?.applyThemeAttrs()
- updateResources()
- }
return expandedView
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 7ab6835..9219baa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -168,26 +168,27 @@
private static final SurfaceSynchronizer DEFAULT_SURFACE_SYNCHRONIZER =
new SurfaceSynchronizer() {
- @Override
- public void syncSurfaceAndRun(Runnable callback) {
- Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() {
- // Just wait 2 frames. There is no guarantee, but this is usually enough time that
- // the requested change is reflected on the screen.
- // TODO: Once SurfaceFlinger provide APIs to sync the state of {@code View} and
- // surfaces, rewrite this logic with them.
- private int mFrameWait = 2;
-
@Override
- public void doFrame(long frameTimeNanos) {
- if (--mFrameWait > 0) {
- Choreographer.getInstance().postFrameCallback(this);
- } else {
- callback.run();
- }
+ public void syncSurfaceAndRun(Runnable callback) {
+ Choreographer.FrameCallback frameCallback = new Choreographer.FrameCallback() {
+ // Just wait 2 frames. There is no guarantee, but this is usually enough
+ // time that the requested change is reflected on the screen.
+ // TODO: Once SurfaceFlinger provide APIs to sync the state of
+ // {@code View} and surfaces, rewrite this logic with them.
+ private int mFrameWait = 2;
+
+ @Override
+ public void doFrame(long frameTimeNanos) {
+ if (--mFrameWait > 0) {
+ Choreographer.getInstance().postFrameCallback(this);
+ } else {
+ callback.run();
+ }
+ }
+ };
+ Choreographer.getInstance().postFrameCallback(frameCallback);
}
- });
- }
- };
+ };
private final BubbleController mBubbleController;
private final BubbleData mBubbleData;
private StackViewState mStackViewState = new StackViewState();
@@ -781,12 +782,12 @@
mPositioner = mBubbleController.getPositioner();
final TypedArray ta = mContext.obtainStyledAttributes(
- new int[] {android.R.attr.dialogCornerRadius});
+ new int[]{android.R.attr.dialogCornerRadius});
mCornerRadius = ta.getDimensionPixelSize(0, 0);
ta.recycle();
final Runnable onBubbleAnimatedOut = () -> {
- if (getBubbleCount() == 0 && !mBubbleData.isShowingOverflow()) {
+ if (getBubbleCount() == 0) {
mBubbleController.onAllBubblesAnimatedOut();
}
};
@@ -942,7 +943,7 @@
});
// If the stack itself is clicked, it means none of its touchable views (bubbles, flyouts,
- // TaskView, etc.) were touched. Collapse the stack if it's expanded.
+ // TaskView, etc.) were touched. Collapse the stack if it's expanded.
setOnClickListener(view -> {
if (mShowingManage) {
showManageMenu(false /* show */);
@@ -1650,13 +1651,17 @@
} else {
bubble.cleanupViews();
}
- updatePointerPosition(false /* forIme */);
updateExpandedView();
logBubbleEvent(bubble, FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__DISMISSED);
return;
}
}
- Log.d(TAG, "was asked to remove Bubble, but didn't find the view! " + bubble);
+ // If a bubble is suppressed, it is not attached to the container. Clean it up.
+ if (bubble.isSuppressed()) {
+ bubble.cleanupViews();
+ } else {
+ Log.d(TAG, "was asked to remove Bubble, but didn't find the view! " + bubble);
+ }
}
private void updateOverflowVisibility() {
@@ -1842,11 +1847,30 @@
}
}
- void setBubbleVisibility(Bubble b, boolean visible) {
- if (b.getIconView() != null) {
- b.getIconView().setVisibility(visible ? VISIBLE : GONE);
+ void setBubbleSuppressed(Bubble bubble, boolean suppressed) {
+ if (DEBUG_BUBBLE_STACK_VIEW) {
+ Log.d(TAG, "setBubbleSuppressed: suppressed=" + suppressed + " bubble=" + bubble);
}
- // TODO(b/181166384): Animate in / out & handle adjusting how the bubbles overlap
+ if (suppressed) {
+ int index = getBubbleIndex(bubble);
+ mBubbleContainer.removeViewAt(index);
+ updateExpandedView();
+ } else {
+ if (bubble.getIconView() == null) {
+ return;
+ }
+ if (bubble.getIconView().getParent() != null) {
+ Log.e(TAG, "Bubble is already added to parent. Can't unsuppress: " + bubble);
+ return;
+ }
+ int index = mBubbleData.getBubbles().indexOf(bubble);
+ // Add the view back to the correct position
+ mBubbleContainer.addView(bubble.getIconView(), index,
+ new LayoutParams(mPositioner.getBubbleSize(),
+ mPositioner.getBubbleSize()));
+ updateBubbleShadows(false /* showForAllBubbles */);
+ requestUpdate();
+ }
}
/**
@@ -2191,7 +2215,7 @@
PhysicsAnimator.getInstance(mAnimatingOutSurfaceContainer)
.spring(DynamicAnimation.TRANSLATION_Y,
mAnimatingOutSurfaceContainer.getTranslationY() - mBubbleSize,
- mTranslateSpringConfig)
+ mTranslateSpringConfig)
.start();
}
@@ -3040,14 +3064,14 @@
* Logs the bubble UI event.
*
* @param provider the bubble view provider that is being interacted on. Null value indicates
- * that the user interaction is not specific to one bubble.
- * @param action the user interaction enum.
+ * that the user interaction is not specific to one bubble.
+ * @param action the user interaction enum.
*/
private void logBubbleEvent(@Nullable BubbleViewProvider provider, int action) {
final String packageName =
(provider != null && provider instanceof Bubble)
- ? ((Bubble) provider).getPackageName()
- : "null";
+ ? ((Bubble) provider).getPackageName()
+ : "null";
mBubbleData.logBubbleEvent(provider,
action,
packageName,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayout.java
index 4ec2c8d..55052e6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayout.java
@@ -364,6 +364,11 @@
final int oldIndex = indexOfChild(view);
super.removeView(view);
+ if (view.getParent() != null) {
+ // View still has a parent. This could have been added as a transient view.
+ // Remove it from transient views.
+ super.removeTransientView(view);
+ }
addViewInternal(view, index, view.getLayoutParams(), true /* isReorder */);
if (mController != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
index 60b6433..3ba056a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
@@ -750,6 +750,12 @@
// Otherwise, animate the bubble in if it's the newest bubble. If we're adding a bubble
// to the back of the stack, it'll be largely invisible so don't bother animating it in.
animateInBubble(child, index);
+ } else {
+ // We are not animating the bubble in. Make sure it has the right alpha and scale values
+ // in case this view was previously removed and is being re-added.
+ child.setAlpha(1f);
+ child.setScaleX(1f);
+ child.setScaleY(1f);
}
}
@@ -785,23 +791,24 @@
}
};
+ boolean swapped = false;
for (int newIndex = 0; newIndex < bubbleViews.size(); newIndex++) {
View view = bubbleViews.get(newIndex);
final int oldIndex = mLayout.indexOfChild(view);
- animateSwap(view, oldIndex, newIndex, updateAllIcons, after);
+ swapped |= animateSwap(view, oldIndex, newIndex, updateAllIcons, after);
+ }
+ if (!swapped) {
+ // All bubbles were at the right position. Make sure badges and z order is correct.
+ updateAllIcons.run();
}
}
- private void animateSwap(View view, int oldIndex, int newIndex,
+ private boolean animateSwap(View view, int oldIndex, int newIndex,
Runnable updateAllIcons, Runnable finishReorder) {
if (newIndex == oldIndex) {
- // Add new bubble to index 0; move existing bubbles down
- updateBadgesAndZOrder(view, newIndex);
- if (newIndex == 0) {
- animateInBubble(view, newIndex);
- } else {
- moveToFinalIndex(view, newIndex, finishReorder);
- }
+ // View order did not change. Make sure position is correct.
+ moveToFinalIndex(view, newIndex, finishReorder);
+ return false;
} else {
// Reorder existing bubbles
if (newIndex == 0) {
@@ -809,6 +816,7 @@
} else {
moveToFinalIndex(view, newIndex, finishReorder);
}
+ return true;
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
index 1039e2a..51067a4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
@@ -191,6 +191,19 @@
return null;
}
+ /**
+ * Gets a token associated with the view that can be used to grant the view focus.
+ */
+ public IBinder getFocusGrantToken(View view) {
+ SurfaceControlViewHost root = mViewRoots.get(view);
+ if (root == null) {
+ Slog.e(TAG, "Couldn't get focus grant token since view does not exist in "
+ + "SystemWindow:" + view);
+ return null;
+ }
+ return root.getFocusGrantToken();
+ }
+
private class PerDisplay {
final int mDisplayId;
private final SparseArray<SysUiWindowManager> mWwms = new SparseArray<>();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
index bdf9d51..7014fcc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
@@ -140,11 +140,8 @@
/**
* Whether the layout is eligible to be shown according to the internal state of the subclass.
- * Returns true by default if subclass doesn't override this method.
*/
- protected boolean eligibleToShowLayout() {
- return true;
- }
+ protected abstract boolean eligibleToShowLayout();
@Override
public void setConfiguration(Configuration configuration) {
@@ -214,8 +211,7 @@
boolean layoutDirectionUpdated =
mTaskConfig.getLayoutDirection() != prevTaskConfig.getLayoutDirection();
if (boundsUpdated || layoutDirectionUpdated) {
- // Reposition the UI surfaces.
- updateSurfacePosition();
+ updateSurface();
}
if (layout != null && layoutDirectionUpdated) {
@@ -226,7 +222,6 @@
return true;
}
-
/**
* Updates the visibility of the layout.
*
@@ -253,8 +248,7 @@
displayLayout.getStableBounds(curStableBounds);
mDisplayLayout = displayLayout;
if (!prevStableBounds.equals(curStableBounds)) {
- // Stable bounds changed, update UI surface positions.
- updateSurfacePosition();
+ updateSurface();
mStableBounds.set(curStableBounds);
}
}
@@ -304,6 +298,14 @@
}
/**
+ * Updates the surface following a change in the task bounds, display layout stable bounds,
+ * or the layout direction.
+ */
+ protected void updateSurface() {
+ updateSurfacePosition();
+ }
+
+ /**
* Updates the position of the surface with respect to the task bounds and display layout
* stable bounds.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java
new file mode 100644
index 0000000..eff2602
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java
@@ -0,0 +1,197 @@
+/*
+ * 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.wm.shell.compatui.letterboxedu;
+
+import static com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation;
+import static com.android.internal.R.styleable.WindowAnimation_windowExitAnimation;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.annotation.AnyRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.util.IntProperty;
+import android.util.Log;
+import android.util.Property;
+import android.view.ContextThemeWrapper;
+import android.view.View;
+import android.view.animation.Animation;
+
+import com.android.internal.policy.TransitionAnimation;
+
+/**
+ * Controls the enter/exit animations of the letterbox education.
+ */
+// TODO(b/215316431): Add tests
+class LetterboxEduAnimationController {
+ private static final String TAG = "LetterboxEduAnimation";
+
+ private final TransitionAnimation mTransitionAnimation;
+ private final String mPackageName;
+ @AnyRes
+ private final int mAnimStyleResId;
+
+ @Nullable
+ private Animation mDialogAnimation;
+ @Nullable
+ private Animator mBackgroundDimAnimator;
+
+ LetterboxEduAnimationController(Context context) {
+ mTransitionAnimation = new TransitionAnimation(context, /* debug= */ false, TAG);
+ mAnimStyleResId = (new ContextThemeWrapper(context,
+ android.R.style.ThemeOverlay_Material_Dialog).getTheme()).obtainStyledAttributes(
+ com.android.internal.R.styleable.Window).getResourceId(
+ com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
+ mPackageName = context.getPackageName();
+ }
+
+ /**
+ * Starts both background dim fade-in animation and the dialog enter animation.
+ */
+ void startEnterAnimation(@NonNull LetterboxEduDialogLayout layout, Runnable endCallback) {
+ // Cancel any previous animation if it's still running.
+ cancelAnimation();
+
+ final View dialogContainer = layout.getDialogContainer();
+ mDialogAnimation = loadAnimation(WindowAnimation_windowEnterAnimation);
+ if (mDialogAnimation == null) {
+ endCallback.run();
+ return;
+ }
+ mDialogAnimation.setAnimationListener(getAnimationListener(
+ /* startCallback= */ () -> dialogContainer.setAlpha(1),
+ /* endCallback= */ () -> {
+ mDialogAnimation = null;
+ endCallback.run();
+ }));
+
+ mBackgroundDimAnimator = getAlphaAnimator(layout.getBackgroundDim(),
+ /* endAlpha= */ LetterboxEduDialogLayout.BACKGROUND_DIM_ALPHA,
+ mDialogAnimation.getDuration());
+ mBackgroundDimAnimator.addListener(getDimAnimatorListener());
+
+ dialogContainer.startAnimation(mDialogAnimation);
+ mBackgroundDimAnimator.start();
+ }
+
+ /**
+ * Starts both the background dim fade-out animation and the dialog exit animation.
+ */
+ void startExitAnimation(@Nullable LetterboxEduDialogLayout layout, Runnable endCallback) {
+ // Cancel any previous animation if it's still running.
+ cancelAnimation();
+
+ if (layout == null) {
+ endCallback.run();
+ return;
+ }
+
+ final View dialogContainer = layout.getDialogContainer();
+ mDialogAnimation = loadAnimation(WindowAnimation_windowExitAnimation);
+ if (mDialogAnimation == null) {
+ endCallback.run();
+ return;
+ }
+ mDialogAnimation.setAnimationListener(getAnimationListener(
+ /* startCallback= */ () -> {},
+ /* endCallback= */ () -> {
+ dialogContainer.setAlpha(0);
+ mDialogAnimation = null;
+ endCallback.run();
+ }));
+
+ mBackgroundDimAnimator = getAlphaAnimator(layout.getBackgroundDim(), /* endAlpha= */ 0,
+ mDialogAnimation.getDuration());
+ mBackgroundDimAnimator.addListener(getDimAnimatorListener());
+
+ dialogContainer.startAnimation(mDialogAnimation);
+ mBackgroundDimAnimator.start();
+ }
+
+ /**
+ * Cancels all animations and resets the state of the controller.
+ */
+ void cancelAnimation() {
+ if (mDialogAnimation != null) {
+ mDialogAnimation.cancel();
+ mDialogAnimation = null;
+ }
+ if (mBackgroundDimAnimator != null) {
+ mBackgroundDimAnimator.cancel();
+ mBackgroundDimAnimator = null;
+ }
+ }
+
+ private Animation loadAnimation(int animAttr) {
+ Animation animation = mTransitionAnimation.loadAnimationAttr(mPackageName, mAnimStyleResId,
+ animAttr, /* translucent= */ false);
+ if (animation == null) {
+ Log.e(TAG, "Failed to load animation " + animAttr);
+ }
+ return animation;
+ }
+
+ private Animation.AnimationListener getAnimationListener(Runnable startCallback,
+ Runnable endCallback) {
+ return new Animation.AnimationListener() {
+ @Override
+ public void onAnimationStart(Animation animation) {
+ startCallback.run();
+ }
+
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ endCallback.run();
+ }
+
+ @Override
+ public void onAnimationRepeat(Animation animation) {}
+ };
+ }
+
+ private AnimatorListenerAdapter getDimAnimatorListener() {
+ return new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mBackgroundDimAnimator = null;
+ }
+ };
+ }
+
+ private static Animator getAlphaAnimator(
+ Drawable drawable, int endAlpha, long duration) {
+ Animator animator = ObjectAnimator.ofInt(drawable, DRAWABLE_ALPHA, endAlpha);
+ animator.setDuration(duration);
+ return animator;
+ }
+
+ private static final Property<Drawable, Integer> DRAWABLE_ALPHA = new IntProperty<Drawable>(
+ "alpha") {
+ @Override
+ public void setValue(Drawable object, int value) {
+ object.setAlpha(value);
+ }
+
+ @Override
+ public Integer get(Drawable object) {
+ return object.getAlpha();
+ }
+ };
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java
index b045a4a..bc1d19b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java
@@ -17,7 +17,9 @@
package com.android.wm.shell.compatui.letterboxedu;
import android.content.Context;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
+import android.view.View;
import android.widget.FrameLayout;
import com.android.wm.shell.R;
@@ -33,9 +35,9 @@
// The alpha of a background is a number between 0 (fully transparent) to 255 (fully opaque).
// 204 is simply 255 * 0.8.
- private static final int BACKGROUND_DIM_ALPHA = 204;
-
- private LetterboxEduWindowManager mWindowManager;
+ static final int BACKGROUND_DIM_ALPHA = 204;
+ private View mDialogContainer;
+ private Drawable mBackgroundDim;
public LetterboxEduDialogLayout(Context context) {
this(context, null);
@@ -54,15 +56,12 @@
super(context, attrs, defStyleAttr, defStyleRes);
}
- void inject(LetterboxEduWindowManager windowManager) {
- mWindowManager = windowManager;
+ View getDialogContainer() {
+ return mDialogContainer;
}
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- // Need to relayout after visibility changes since they affect size.
- mWindowManager.relayout();
+ Drawable getBackgroundDim() {
+ return mBackgroundDim;
}
/**
@@ -77,12 +76,15 @@
setOnClickListener(view -> callback.run());
// We add a no-op on-click listener to the dialog container so that clicks on it won't
// propagate to the listener of the layout (which represents the background dim).
- findViewById(R.id.letterbox_education_dialog_container).setOnClickListener(view -> {});
+ mDialogContainer.setOnClickListener(view -> {});
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- getBackground().mutate().setAlpha(BACKGROUND_DIM_ALPHA);
+ mDialogContainer = findViewById(R.id.letterbox_education_dialog_container);
+ mBackgroundDim = getBackground().mutate();
+ // Set the alpha of the background dim to 0 for enter animation.
+ mBackgroundDim.setAlpha(0);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java
index e9ffca7..074610b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java
@@ -16,11 +16,14 @@
package com.android.wm.shell.compatui.letterboxedu;
+import static android.provider.Settings.Secure.LAUNCHER_TASKBAR_EDUCATION_SHOWING;
+
import android.annotation.Nullable;
import android.app.TaskInfo;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Rect;
+import android.provider.Settings;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
@@ -55,6 +58,8 @@
*/
private final SharedPreferences mSharedPreferences;
+ private final LetterboxEduAnimationController mAnimationController;
+
// Remember the last reported state in case visibility changes due to keyguard or IME updates.
private boolean mEligibleForLetterboxEducation;
@@ -69,6 +74,7 @@
super(context, taskInfo, syncQueue, taskListener, displayLayout);
mOnDismissCallback = onDismissCallback;
mEligibleForLetterboxEducation = taskInfo.topActivityEligibleForLetterboxEducation;
+ mAnimationController = new LetterboxEduAnimationController(context);
mSharedPreferences = mContext.getSharedPreferences(HAS_SEEN_LETTERBOX_EDUCATION_PREF_NAME,
Context.MODE_PRIVATE);
}
@@ -90,9 +96,12 @@
@Override
protected boolean eligibleToShowLayout() {
- // If the layout isn't null then it was previously showing, and we shouldn't check if the
- // user has seen the letterbox education before.
- return mEligibleForLetterboxEducation && (mLayout != null
+ // - If taskbar education is showing, the letterbox education shouldn't be shown for the
+ // given task until the taskbar education is dismissed and the compat info changes (then
+ // the controller will create a new instance of this class since this one isn't eligible).
+ // - If the layout isn't null then it was previously showing, and we shouldn't check if the
+ // user has seen the letterbox education before.
+ return mEligibleForLetterboxEducation && !isTaskbarEduShowing() && (mLayout != null
|| !getHasSeenLetterboxEducation());
}
@@ -100,8 +109,9 @@
protected View createLayout() {
setSeenLetterboxEducation();
mLayout = inflateLayout();
- mLayout.inject(this);
- mLayout.setDismissOnClickListener(this::onDismiss);
+
+ mAnimationController.startEnterAnimation(mLayout, /* endCallback= */
+ this::setDismissOnClickListener);
return mLayout;
}
@@ -111,9 +121,24 @@
R.layout.letterbox_education_dialog_layout, null);
}
+ private void setDismissOnClickListener() {
+ if (mLayout == null) {
+ return;
+ }
+ mLayout.setDismissOnClickListener(this::onDismiss);
+ }
+
private void onDismiss() {
- release();
- mOnDismissCallback.run();
+ mAnimationController.startExitAnimation(mLayout, () -> {
+ release();
+ mOnDismissCallback.run();
+ });
+ }
+
+ @Override
+ public void release() {
+ mAnimationController.cancelAnimation();
+ super.release();
}
@Override
@@ -125,15 +150,22 @@
}
@Override
+ protected void updateSurface() {
+ // We need to relayout because the layout dimensions depend on the task bounds.
+ relayout();
+ }
+
+ @Override
protected void updateSurfacePosition(Rect taskBounds, Rect stableBounds) {
- updateSurfacePosition(/* positionX= */ taskBounds.left, /* positionY= */ taskBounds.top);
+ // Nothing to do, since the position of the surface is fixed to the top left corner (0,0)
+ // of the task (parent surface), which is the default position of a surface.
}
@Override
protected WindowManager.LayoutParams getWindowLayoutParams() {
final Rect taskBounds = mTaskConfig.windowConfiguration.getBounds();
- return getWindowLayoutParams(/* width= */ taskBounds.right - taskBounds.left,
- /* height= */ taskBounds.bottom - taskBounds.top);
+ return getWindowLayoutParams(/* width= */ taskBounds.width(), /* height= */
+ taskBounds.height());
}
private boolean getHasSeenLetterboxEducation() {
@@ -147,4 +179,9 @@
private String getPrefKey() {
return String.valueOf(mContext.getUserId());
}
+
+ private boolean isTaskbarEduShowing() {
+ return Settings.Secure.getInt(mContext.getContentResolver(),
+ LAUNCHER_TASKBAR_EDUCATION_SHOWING, /* def= */ 0) == 1;
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
index 5ebdceb..e8bae0f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -45,10 +45,12 @@
import android.content.ActivityNotFoundException;
import android.content.ClipData;
import android.content.ClipDescription;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.LauncherApps;
+import android.content.pm.ResolveInfo;
import android.graphics.Insets;
import android.graphics.Rect;
import android.os.Bundle;
@@ -62,9 +64,11 @@
import androidx.annotation.VisibleForTesting;
import com.android.internal.logging.InstanceId;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreenController;
import java.lang.annotation.Retention;
@@ -106,12 +110,19 @@
*/
void start(DisplayLayout displayLayout, ClipData data, InstanceId loggerSessionId) {
mLoggerSessionId = loggerSessionId;
- mSession = new DragSession(mContext, mActivityTaskManager, displayLayout, data);
+ mSession = new DragSession(mActivityTaskManager, displayLayout, data);
// TODO(b/169894807): Also update the session data with task stack changes
mSession.update();
}
/**
+ * Returns the last running task.
+ */
+ ActivityManager.RunningTaskInfo getLatestRunningTask() {
+ return mSession.runningTaskInfo;
+ }
+
+ /**
* Returns the target's regions based on the current state of the device and display.
*/
@NonNull
@@ -248,32 +259,68 @@
final UserHandle user = intent.getParcelableExtra(EXTRA_USER);
mStarter.startShortcut(packageName, id, position, opts, user);
} else {
- mStarter.startIntent(intent.getParcelableExtra(EXTRA_PENDING_INTENT),
- null, position, opts);
+ final PendingIntent launchIntent = intent.getParcelableExtra(EXTRA_PENDING_INTENT);
+ mStarter.startIntent(launchIntent, getStartIntentFillInIntent(launchIntent, position),
+ position, opts);
}
}
/**
+ * Returns the fill-in intent to use when starting an app from a drop.
+ */
+ @VisibleForTesting
+ Intent getStartIntentFillInIntent(PendingIntent launchIntent, @SplitPosition int position) {
+ // Get the drag app
+ final List<ResolveInfo> infos = launchIntent.queryIntentComponents(0 /* flags */);
+ final ComponentName dragIntentActivity = !infos.isEmpty()
+ ? infos.get(0).activityInfo.getComponentName()
+ : null;
+
+ // Get the current app (either fullscreen or the remaining app post-drop if in splitscreen)
+ final boolean inSplitScreen = mSplitScreen != null
+ && mSplitScreen.isSplitScreenVisible();
+ final ComponentName currentActivity;
+ if (!inSplitScreen) {
+ currentActivity = mSession.runningTaskInfo != null
+ ? mSession.runningTaskInfo.baseActivity
+ : null;
+ } else {
+ final int nonReplacedSplitPosition = position == SPLIT_POSITION_TOP_OR_LEFT
+ ? SPLIT_POSITION_BOTTOM_OR_RIGHT
+ : SPLIT_POSITION_TOP_OR_LEFT;
+ ActivityManager.RunningTaskInfo nonReplacedTaskInfo =
+ mSplitScreen.getTaskInfo(nonReplacedSplitPosition);
+ currentActivity = nonReplacedTaskInfo.baseActivity;
+ }
+
+ if (currentActivity.equals(dragIntentActivity)) {
+ // Only apply MULTIPLE_TASK if we are dragging the same activity
+ final Intent fillInIntent = new Intent();
+ fillInIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Adding MULTIPLE_TASK");
+ return fillInIntent;
+ }
+ return null;
+ }
+
+ /**
* Per-drag session data.
*/
private static class DragSession {
- private final Context mContext;
private final ActivityTaskManager mActivityTaskManager;
private final ClipData mInitialDragData;
final DisplayLayout displayLayout;
Intent dragData;
- int runningTaskId;
+ ActivityManager.RunningTaskInfo runningTaskInfo;
@WindowConfiguration.WindowingMode
int runningTaskWinMode = WINDOWING_MODE_UNDEFINED;
@WindowConfiguration.ActivityType
int runningTaskActType = ACTIVITY_TYPE_STANDARD;
- boolean runningTaskIsResizeable;
boolean dragItemSupportsSplitscreen;
- DragSession(Context context, ActivityTaskManager activityTaskManager,
+ DragSession(ActivityTaskManager activityTaskManager,
DisplayLayout dispLayout, ClipData data) {
- mContext = context;
mActivityTaskManager = activityTaskManager;
mInitialDragData = data;
displayLayout = dispLayout;
@@ -287,10 +334,9 @@
mActivityTaskManager.getTasks(1, false /* filterOnlyVisibleRecents */);
if (!tasks.isEmpty()) {
final ActivityManager.RunningTaskInfo task = tasks.get(0);
+ runningTaskInfo = task;
runningTaskWinMode = task.getWindowingMode();
runningTaskActType = task.getActivityType();
- runningTaskId = task.taskId;
- runningTaskIsResizeable = task.isResizeable;
}
final ActivityInfo info = mInitialDragData.getItemAt(0).getActivityInfo();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index 7307ba3..d395f95 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -26,7 +26,6 @@
import android.animation.AnimatorListenerAdapter;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
-import android.app.ActivityTaskManager;
import android.app.StatusBarManager;
import android.content.ClipData;
import android.content.Context;
@@ -35,7 +34,6 @@
import android.graphics.Insets;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
-import android.os.RemoteException;
import android.view.DragEvent;
import android.view.SurfaceControl;
import android.view.WindowInsets;
@@ -51,7 +49,6 @@
import com.android.wm.shell.splitscreen.SplitScreenController;
import java.util.ArrayList;
-import java.util.List;
/**
* Coordinates the visible drop targets for the current drag.
@@ -166,17 +163,8 @@
boolean alreadyInSplit = mSplitScreenController != null
&& mSplitScreenController.isSplitScreenVisible();
if (!alreadyInSplit) {
- List<ActivityManager.RunningTaskInfo> tasks = null;
- // Figure out the splashscreen info for the existing task.
- try {
- tasks = ActivityTaskManager.getService().getTasks(1,
- false /* filterOnlyVisibleRecents */,
- false /* keepIntentExtra */);
- } catch (RemoteException e) {
- // don't show an icon / will just use the defaults
- }
- if (tasks != null && !tasks.isEmpty()) {
- ActivityManager.RunningTaskInfo taskInfo1 = tasks.get(0);
+ ActivityManager.RunningTaskInfo taskInfo1 = mPolicy.getLatestRunningTask();
+ if (taskInfo1 != null) {
Drawable icon1 = mIconProvider.getIcon(taskInfo1.topActivityInfo);
int bgColor1 = getResizingBackgroundColor(taskInfo1);
mDropZoneView1.setAppInfo(bgColor1, icon1);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index 6ec8f5b..71cff02 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
@@ -28,7 +28,6 @@
import android.graphics.RectF;
import android.os.Debug;
import android.os.Handler;
-import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.util.Size;
@@ -126,7 +125,6 @@
private int mMenuState;
private PipMenuView mPipMenuView;
- private IBinder mPipMenuInputToken;
private ActionListener mMediaActionListener = new ActionListener() {
@Override
@@ -206,7 +204,6 @@
mApplier = null;
mSystemWindows.removeView(mPipMenuView);
mPipMenuView = null;
- mPipMenuInputToken = null;
}
/**
@@ -392,7 +389,6 @@
if (mApplier == null) {
mApplier = new SyncRtSurfaceTransactionApplier(mPipMenuView);
- mPipMenuInputToken = mPipMenuView.getViewRootImpl().getInputToken();
}
return mApplier != null;
@@ -539,7 +535,8 @@
try {
WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null /* window */,
- mPipMenuInputToken, menuState != MENU_STATE_NONE /* grantFocus */);
+ mSystemWindows.getFocusGrantToken(mPipMenuView),
+ menuState != MENU_STATE_NONE /* grantFocus */);
} catch (RemoteException e) {
Log.e(TAG, "Unable to update focus as menu appears/disappears", e);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
index 32861b6..f838a0b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
@@ -143,6 +143,7 @@
mSystemWindows.addView(mPipMenuView,
getPipMenuLayoutParams(MENU_WINDOW_TITLE, 0 /* width */, 0 /* height */),
0, SHELL_ROOT_LAYER_PIP);
+ mPipMenuView.setFocusGrantToken(mSystemWindows.getFocusGrantToken(mPipMenuView));
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
index 0141b6a..84eae9e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
@@ -28,6 +28,7 @@
import android.app.RemoteAction;
import android.content.Context;
import android.os.Handler;
+import android.os.IBinder;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
@@ -69,6 +70,7 @@
private final ImageView mArrowRight;
private final ImageView mArrowDown;
private final ImageView mArrowLeft;
+ private IBinder mFocusGrantToken = null;
public TvPipMenuView(@NonNull Context context) {
this(context, null);
@@ -108,6 +110,10 @@
mListener = listener;
}
+ void setFocusGrantToken(IBinder token) {
+ mFocusGrantToken = token;
+ }
+
void show(boolean inMoveMode, int gravity) {
if (DEBUG) Log.d(TAG, "show(), inMoveMode: " + inMoveMode);
grantWindowFocus(true);
@@ -162,7 +168,7 @@
try {
WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null /* window */,
- getViewRootImpl().getInputToken(), grantFocus);
+ mFocusGrantToken, grantFocus);
} catch (Exception e) {
Log.e(TAG, "Unable to update focus", e);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 219530b..029d073 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -163,6 +163,7 @@
// and exit, since exit itself can trigger a number of changes that update the stages.
private boolean mShouldUpdateRecents;
private boolean mExitSplitScreenOnHide;
+ private boolean mIsDividerRemoteAnimating;
/** The target stage to dismiss to when unlock after folded. */
@StageType
@@ -389,6 +390,7 @@
RemoteAnimationTarget[] wallpapers,
RemoteAnimationTarget[] nonApps,
final IRemoteAnimationFinishedCallback finishedCallback) {
+ mIsDividerRemoteAnimating = true;
RemoteAnimationTarget[] augmentedNonApps =
new RemoteAnimationTarget[nonApps.length + 1];
for (int i = 0; i < nonApps.length; ++i) {
@@ -400,6 +402,7 @@
new IRemoteAnimationFinishedCallback.Stub() {
@Override
public void onAnimationFinished() throws RemoteException {
+ mIsDividerRemoteAnimating = false;
mShouldUpdateRecents = true;
mSyncQueue.queue(evictWct);
mSyncQueue.runInSync(t -> setDividerVisibility(true, t));
@@ -423,6 +426,7 @@
@Override
public void onAnimationCancelled() {
+ mIsDividerRemoteAnimating = false;
mShouldUpdateRecents = true;
mSyncQueue.queue(evictWct);
mSyncQueue.runInSync(t -> setDividerVisibility(true, t));
@@ -467,6 +471,7 @@
// Using legacy transitions, so we can't use blast sync since it conflicts.
mTaskOrganizer.applyTransaction(wct);
+ mSyncQueue.runInSync(t -> updateSurfaceBounds(mSplitLayout, t));
}
/** Start an intent and a task ordered by {@code intentFirst}. */
@@ -1055,7 +1060,7 @@
private void applyDividerVisibility(SurfaceControl.Transaction t) {
final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash();
- if (dividerLeash == null) return;
+ if (mIsDividerRemoteAnimating || dividerLeash == null) return;
if (mDividerVisible) {
t.show(dividerLeash);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index ddf01a8..5af1530 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -201,6 +201,7 @@
"Display is changing, check if it should be seamless.");
boolean checkedDisplayLayout = false;
boolean hasTask = false;
+ boolean displayExplicitSeamless = false;
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
@@ -209,7 +210,6 @@
// This container isn't rotating, so we can ignore it.
if (change.getEndRotation() == change.getStartRotation()) continue;
-
if ((change.getFlags() & FLAG_IS_DISPLAY) != 0) {
// In the presence of System Alert windows we can not seamlessly rotate.
if ((change.getFlags() & FLAG_DISPLAY_HAS_ALERT_WINDOWS) != 0) {
@@ -217,6 +217,8 @@
" display has system alert windows, so not seamless.");
return false;
}
+ displayExplicitSeamless =
+ change.getRotationAnimation() == ROTATION_ANIMATION_SEAMLESS;
} else if ((change.getFlags() & FLAG_IS_WALLPAPER) != 0) {
if (change.getRotationAnimation() != ROTATION_ANIMATION_SEAMLESS) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
@@ -268,8 +270,8 @@
}
}
- // ROTATION_ANIMATION_SEAMLESS can only be requested by task.
- if (hasTask) {
+ // ROTATION_ANIMATION_SEAMLESS can only be requested by task or display.
+ if (hasTask || displayExplicitSeamless) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Rotation IS seamless.");
return true;
}
@@ -417,8 +419,8 @@
// hasRoundedCorners is currently only enabled for tasks
final Context displayContext =
mDisplayController.getDisplayContext(change.getTaskInfo().displayId);
- cornerRadius =
- ScreenDecorationsUtils.getWindowCornerRadius(displayContext);
+ cornerRadius = displayContext == null ? 0
+ : ScreenDecorationsUtils.getWindowCornerRadius(displayContext);
} else {
cornerRadius = 0;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/CounterRotator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/util/CounterRotator.java
index 7f8eaf1..7e95814 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/util/CounterRotator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/CounterRotator.java
@@ -16,10 +16,14 @@
package com.android.wm.shell.util;
+import android.graphics.Point;
+import android.util.RotationUtils;
import android.view.SurfaceControl;
/**
- * Utility class that takes care of counter-rotating surfaces during a transition animation.
+ * Utility class that takes care of rotating unchanging child-surfaces to match the parent rotation
+ * during a transition animation. This gives the illusion that the child surfaces haven't rotated
+ * relative to the screen.
*/
public class CounterRotator {
private SurfaceControl mSurface = null;
@@ -33,29 +37,30 @@
* Sets up this rotator.
*
* @param rotateDelta is the forward rotation change (the rotation the display is making).
- * @param displayW (and H) Is the size of the rotating display.
+ * @param parentW (and H) Is the size of the rotating parent after the rotation.
*/
public void setup(SurfaceControl.Transaction t, SurfaceControl parent, int rotateDelta,
- float displayW, float displayH) {
+ float parentW, float parentH) {
if (rotateDelta == 0) return;
- // We want to counter-rotate, so subtract from 4
- rotateDelta = 4 - (rotateDelta + 4) % 4;
mSurface = new SurfaceControl.Builder()
.setName("Transition Unrotate")
.setContainerLayer()
.setParent(parent)
.build();
- // column-major
- if (rotateDelta == 1) {
- t.setMatrix(mSurface, 0, 1, -1, 0);
- t.setPosition(mSurface, displayW, 0);
- } else if (rotateDelta == 2) {
- t.setMatrix(mSurface, -1, 0, 0, -1);
- t.setPosition(mSurface, displayW, displayH);
- } else if (rotateDelta == 3) {
- t.setMatrix(mSurface, 0, -1, 1, 0);
- t.setPosition(mSurface, 0, displayH);
+ // Rotate forward to match the new rotation (rotateDelta is the forward rotation the parent
+ // already took). Child surfaces will be in the old rotation relative to the new parent
+ // rotation, so we need to forward-rotate the child surfaces to match.
+ RotationUtils.rotateSurface(t, mSurface, rotateDelta);
+ final Point tmpPt = new Point(0, 0);
+ // parentW/H are the size in the END rotation, the rotation utilities expect the starting
+ // size. So swap them if necessary
+ if ((rotateDelta % 2) != 0) {
+ final float w = parentW;
+ parentW = parentH;
+ parentH = w;
}
+ RotationUtils.rotatePoint(tmpPt, rotateDelta, (int) parentW, (int) parentH);
+ t.setPosition(mSurface, tmpPt.x, tmpPt.y);
t.show(mSurface);
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
index 99f7e23..278ba9b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
@@ -68,9 +68,11 @@
}
teardown {
- notifyManager.setBubblesAllowed(testApp.component.packageName,
+ test {
+ notifyManager.setBubblesAllowed(testApp.component.packageName,
uid, NotificationManager.BUBBLE_PREFERENCE_NONE)
- testApp.exit()
+ testApp.exit()
+ }
}
extraSpec(this)
@@ -95,7 +97,7 @@
fun getParams(): List<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
.getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
- repetitions = 5)
+ repetitions = 3)
}
const val FIND_OBJECT_TIMEOUT = 2000L
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt
index a928bbd..f6abc75 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt
@@ -28,6 +28,9 @@
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.annotation.Group4
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume
+import org.junit.Before
import org.junit.runner.RunWith
import org.junit.Test
import org.junit.runners.Parameterized
@@ -44,11 +47,16 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@Group4
-class DismissBubbleScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen(testSpec) {
+open class DismissBubbleScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen(testSpec) {
private val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
private val displaySize = DisplayMetrics()
+ @Before
+ open fun before() {
+ Assume.assumeFalse(isShellTransitionsEnabled)
+ }
+
override val transition: FlickerBuilder.() -> Unit
get() = buildTransition {
setup {
@@ -68,7 +76,7 @@
@Presubmit
@Test
- fun testAppIsAlwaysVisible() {
+ open fun testAppIsAlwaysVisible() {
testSpec.assertLayers {
this.isVisible(testApp.component)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreenShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreenShellTransit.kt
new file mode 100644
index 0000000..dd744b3
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreenShellTransit.kt
@@ -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 com.android.wm.shell.flicker.bubble
+
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group4
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume
+import org.junit.Before
+
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@Group4
+@FlakyTest(bugId = 217777115)
+class DismissBubbleScreenShellTransit(
+ testSpec: FlickerTestParameter
+) : DismissBubbleScreen(testSpec) {
+ @Before
+ override fun before() {
+ Assume.assumeTrue(isShellTransitionsEnabled)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt
index af629cc..2ec743c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt
@@ -24,6 +24,9 @@
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.annotation.Group4
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume
+import org.junit.Before
import org.junit.runner.RunWith
import org.junit.Test
import org.junit.runners.Parameterized
@@ -42,7 +45,12 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@Group4
-class ExpandBubbleScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen(testSpec) {
+open class ExpandBubbleScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen(testSpec) {
+
+ @Before
+ open fun before() {
+ Assume.assumeFalse(isShellTransitionsEnabled)
+ }
override val transition: FlickerBuilder.() -> Unit
get() = buildTransition {
@@ -61,7 +69,7 @@
@Presubmit
@Test
- fun testAppIsAlwaysVisible() {
+ open fun testAppIsAlwaysVisible() {
testSpec.assertLayers {
this.isVisible(testApp.component)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreenShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreenShellTransit.kt
new file mode 100644
index 0000000..d92ec77
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreenShellTransit.kt
@@ -0,0 +1,42 @@
+/*
+ * 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.wm.shell.flicker.bubble
+
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group4
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume
+import org.junit.Before
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@Group4
+@FlakyTest(bugId = 217777115)
+class ExpandBubbleScreenShellTransit(
+ testSpec: FlickerTestParameter
+) : ExpandBubbleScreen(testSpec) {
+ @Before
+ override fun before() {
+ Assume.assumeTrue(isShellTransitionsEnabled)
+ }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt
index 64636be..a20a201 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt
@@ -22,6 +22,9 @@
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.annotation.Group4
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume
+import org.junit.Before
import org.junit.runner.RunWith
import org.junit.Test
import org.junit.runners.Parameterized
@@ -39,7 +42,12 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@Group4
-class LaunchBubbleScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen(testSpec) {
+open class LaunchBubbleScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen(testSpec) {
+
+ @Before
+ open fun before() {
+ Assume.assumeFalse(isShellTransitionsEnabled)
+ }
override val transition: FlickerBuilder.() -> Unit
get() = buildTransition {
@@ -51,7 +59,7 @@
@Presubmit
@Test
- fun testAppIsAlwaysVisible() {
+ open fun testAppIsAlwaysVisible() {
testSpec.assertLayers {
this.isVisible(testApp.component)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreenShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreenShellTransit.kt
new file mode 100644
index 0000000..9350868
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreenShellTransit.kt
@@ -0,0 +1,42 @@
+/*
+ * 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.wm.shell.flicker.bubble
+
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group4
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume
+import org.junit.Before
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@Group4
+@FlakyTest(bugId = 217777115)
+class LaunchBubbleScreenShellTransit(
+ testSpec: FlickerTestParameter
+) : LaunchBubbleScreen(testSpec) {
+ @Before
+ override fun before() {
+ Assume.assumeTrue(isShellTransitionsEnabled)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt
index add11c1..8d1e315 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt
@@ -25,6 +25,9 @@
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.annotation.Group4
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume
+import org.junit.Before
import org.junit.runner.RunWith
import org.junit.Test
import org.junit.runners.Parameterized
@@ -41,7 +44,12 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@Group4
-class MultiBubblesScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen(testSpec) {
+open class MultiBubblesScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen(testSpec) {
+
+ @Before
+ open fun before() {
+ Assume.assumeFalse(isShellTransitionsEnabled)
+ }
override val transition: FlickerBuilder.() -> Unit
get() = buildTransition {
@@ -69,7 +77,7 @@
@Presubmit
@Test
- fun testAppIsAlwaysVisible() {
+ open fun testAppIsAlwaysVisible() {
testSpec.assertLayers {
this.isVisible(testApp.component)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreenShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreenShellTransit.kt
new file mode 100644
index 0000000..ddebb6f
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreenShellTransit.kt
@@ -0,0 +1,42 @@
+/*
+ * 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.wm.shell.flicker.bubble
+
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group4
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume
+import org.junit.Before
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@Group4
+@FlakyTest(bugId = 217777115)
+class MultiBubblesScreenShellTransit(
+ testSpec: FlickerTestParameter
+) : MultiBubblesScreen(testSpec) {
+ @Before
+ override fun before() {
+ Assume.assumeTrue(isShellTransitionsEnabled)
+ }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
index db94de2..467cadc 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -71,24 +71,6 @@
}
}
- @FlakyTest
- @Test
- fun runPresubmitAssertion() {
- flickerRule.checkPresubmitAssertions()
- }
-
- @FlakyTest
- @Test
- fun runPostsubmitAssertion() {
- flickerRule.checkPostsubmitAssertions()
- }
-
- @FlakyTest
- @Test
- fun runFlakyAssertion() {
- flickerRule.checkFlakyAssertions()
- }
-
/** {@inheritDoc} */
@FlakyTest(bugId = 206753786)
@Test
@@ -205,7 +187,7 @@
fun getParams(): List<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
.getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
- repetitions = 5)
+ repetitions = 3)
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
index afe64e3..accb524 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
@@ -224,7 +224,7 @@
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
.getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
- repetitions = 5)
+ repetitions = 3)
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
index 3a9a070..931d060 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
@@ -98,7 +98,7 @@
@JvmStatic
fun getParams(): List<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- supportedRotations = listOf(Surface.ROTATION_0), repetitions = 5)
+ supportedRotations = listOf(Surface.ROTATION_0), repetitions = 3)
}
}
}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt
index 03c8929f..e00d749 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt
@@ -78,24 +78,6 @@
}
}
- @FlakyTest
- @Test
- fun runPresubmitAssertion() {
- flickerRule.checkPresubmitAssertions()
- }
-
- @FlakyTest
- @Test
- fun runPostsubmitAssertion() {
- flickerRule.checkPostsubmitAssertions()
- }
-
- @FlakyTest
- @Test
- fun runFlakyAssertion() {
- flickerRule.checkFlakyAssertions()
- }
-
/** {@inheritDoc} */
@FlakyTest(bugId = 206753786)
@Test
@@ -117,7 +99,7 @@
@JvmStatic
fun getParams(): List<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- supportedRotations = listOf(Surface.ROTATION_0), repetitions = 5)
+ supportedRotations = listOf(Surface.ROTATION_0), repetitions = 3)
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt
index 976b7c6..5214daa0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt
@@ -67,24 +67,6 @@
}
}
- @FlakyTest
- @Test
- fun runPresubmitAssertion() {
- flickerRule.checkPresubmitAssertions()
- }
-
- @FlakyTest
- @Test
- fun runPostsubmitAssertion() {
- flickerRule.checkPostsubmitAssertions()
- }
-
- @FlakyTest
- @Test
- fun runFlakyAssertion() {
- flickerRule.checkFlakyAssertions()
- }
-
/** {@inheritDoc} */
@FlakyTest(bugId = 206753786)
@Test
@@ -107,7 +89,7 @@
fun getParams(): List<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
.getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
- repetitions = 5)
+ repetitions = 3)
}
}
-}
\ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
index 9061239..332bba6a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
@@ -93,7 +93,7 @@
fun getParams(): List<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
.getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
- repetitions = 5)
+ repetitions = 3)
}
}
}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
index 8d14f70..07c3b15 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
@@ -173,7 +173,7 @@
fun getParams(): List<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
.getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
- repetitions = 5)
+ repetitions = 3)
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt
index e415024..e91bef1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt
@@ -96,7 +96,7 @@
@JvmStatic
fun getParams(): List<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- supportedRotations = listOf(Surface.ROTATION_0), repetitions = 5)
+ supportedRotations = listOf(Surface.ROTATION_0), repetitions = 3)
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt
index 4a4c46c..7e66cd3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt
@@ -96,7 +96,7 @@
@JvmStatic
fun getParams(): List<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- supportedRotations = listOf(Surface.ROTATION_0), repetitions = 5)
+ supportedRotations = listOf(Surface.ROTATION_0), repetitions = 3)
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
index 1d61ab4..1e30f6b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
@@ -31,7 +31,7 @@
import com.android.server.wm.traces.common.FlickerComponentName
import com.android.wm.shell.flicker.helpers.ImeAppHelper
import org.junit.Assume.assumeFalse
-import org.junit.Assume.assumeTrue
+import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -47,9 +47,15 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group4
-class PipKeyboardTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
+@FlakyTest(bugId = 218604389)
+open class PipKeyboardTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
private val imeApp = ImeAppHelper(instrumentation)
+ @Before
+ open fun before() {
+ assumeFalse(isShellTransitionsEnabled)
+ }
+
override val transition: FlickerBuilder.() -> Unit
get() = buildTransition(eachRun = false) {
setup {
@@ -77,25 +83,14 @@
/** {@inheritDoc} */
@FlakyTest(bugId = 206753786)
@Test
- override fun statusBarLayerRotatesScales() {
- // This test doesn't work in shell transitions because of b/206753786
- assumeFalse(isShellTransitionsEnabled)
- super.statusBarLayerRotatesScales()
- }
-
- @FlakyTest(bugId = 214452854)
- @Test
- fun statusBarLayerRotatesScales_shellTransit() {
- assumeTrue(isShellTransitionsEnabled)
- super.statusBarLayerRotatesScales()
- }
+ override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
/**
* Ensure the pip window remains visible throughout any keyboard interactions
*/
@Presubmit
@Test
- fun pipInVisibleBounds() {
+ open fun pipInVisibleBounds() {
testSpec.assertWmVisibleRegion(pipApp.component) {
val displayBounds = WindowUtils.getDisplayBounds(testSpec.startRotation)
coversAtMost(displayBounds)
@@ -107,7 +102,7 @@
*/
@Presubmit
@Test
- fun pipIsAboveAppWindow() {
+ open fun pipIsAboveAppWindow() {
testSpec.assertWmTag(TAG_IME_VISIBLE) {
isAboveWindow(FlickerComponentName.IME, pipApp.component)
}
@@ -121,7 +116,7 @@
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
.getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
- repetitions = 5)
+ repetitions = 3)
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTestShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTestShellTransit.kt
new file mode 100644
index 0000000..1a21d32
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTestShellTransit.kt
@@ -0,0 +1,49 @@
+/*
+ * 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.wm.shell.flicker.pip
+
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group4
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group4
+@FlakyTest(bugId = 217777115)
+class PipKeyboardTestShellTransit(testSpec: FlickerTestParameter) : PipKeyboardTest(testSpec) {
+
+ @Before
+ override fun before() {
+ Assume.assumeTrue(isShellTransitionsEnabled)
+ }
+
+ @FlakyTest(bugId = 214452854)
+ @Test
+ override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
index b2b50ad..c8ced1c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
@@ -27,10 +27,13 @@
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.entireScreenCovered
import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.wm.shell.flicker.helpers.FixedAppHelper
+import org.junit.Assume
+import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -61,11 +64,17 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group4
-class PipRotationTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
+@FlakyTest(bugId = 218604389)
+open class PipRotationTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
private val fixedApp = FixedAppHelper(instrumentation)
private val screenBoundsStart = WindowUtils.getDisplayBounds(testSpec.startRotation)
private val screenBoundsEnd = WindowUtils.getDisplayBounds(testSpec.endRotation)
+ @Before
+ open fun before() {
+ Assume.assumeFalse(isShellTransitionsEnabled)
+ }
+
override val transition: FlickerBuilder.() -> Unit
get() = buildTransition(eachRun = false) {
setup {
@@ -182,7 +191,7 @@
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance().getConfigRotationTests(
supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90),
- repetitions = 5)
+ repetitions = 3)
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTestShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTestShellTransit.kt
new file mode 100644
index 0000000..a017f56
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTestShellTransit.kt
@@ -0,0 +1,43 @@
+/*
+ * 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.wm.shell.flicker.pip
+
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group4
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group4
+@FlakyTest(bugId = 217777115)
+class PipRotationTestShellTransit(testSpec: FlickerTestParameter) : PipRotationTest(testSpec) {
+ @Before
+ override fun before() {
+ Assume.assumeTrue(isShellTransitionsEnabled)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
index 8dd9104..d65388b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
@@ -26,9 +26,12 @@
import com.android.server.wm.flicker.annotation.Group4
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
import com.android.wm.shell.flicker.testapp.Components.FixedActivity.EXTRA_FIXED_ORIENTATION
import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP
+import org.junit.Assume
+import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -44,12 +47,18 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group4
-class SetRequestedOrientationWhilePinnedTest(
+@FlakyTest(bugId = 218604389)
+open class SetRequestedOrientationWhilePinnedTest(
testSpec: FlickerTestParameter
) : PipTransition(testSpec) {
private val startingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_0)
private val endingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_90)
+ @Before
+ open fun before() {
+ Assume.assumeFalse(isShellTransitionsEnabled)
+ }
+
override val transition: FlickerBuilder.() -> Unit
get() = {
setupAndTeardown(this)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTestShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTestShellTransit.kt
new file mode 100644
index 0000000..36e2804
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTestShellTransit.kt
@@ -0,0 +1,45 @@
+/*
+ * 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.wm.shell.flicker.pip
+
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group4
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group4
+@FlakyTest(bugId = 217777115)
+class SetRequestedOrientationWhilePinnedTestShellTransit(
+ testSpec: FlickerTestParameter
+) : SetRequestedOrientationWhilePinnedTest(testSpec) {
+ @Before
+ override fun before() {
+ Assume.assumeTrue(isShellTransitionsEnabled)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/values/styles.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/values/styles.xml
index 87a61a8..23b51cc 100644
--- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/values/styles.xml
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/values/styles.xml
@@ -16,15 +16,19 @@
-->
<resources>
- <style name="CutoutDefault">
+ <style name="DefaultTheme" parent="@android:style/Theme.DeviceDefault">
+ <item name="android:windowBackground">@android:color/darker_gray</item>
+ </style>
+
+ <style name="CutoutDefault" parent="@style/DefaultTheme">
<item name="android:windowLayoutInDisplayCutoutMode">default</item>
</style>
- <style name="CutoutShortEdges">
+ <style name="CutoutShortEdges" parent="@style/DefaultTheme">
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
</style>
- <style name="CutoutNever">
+ <style name="CutoutNever" parent="@style/DefaultTheme">
<item name="android:windowLayoutInDisplayCutoutMode">never</item>
</style>
</resources>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/BubbleOverflowTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/BubbleOverflowTest.java
new file mode 100644
index 0000000..8278c67
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/BubbleOverflowTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.wm.shell;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.WindowManager;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.bubbles.BubbleController;
+import com.android.wm.shell.bubbles.BubbleOverflow;
+import com.android.wm.shell.bubbles.BubbleStackView;
+import com.android.wm.shell.bubbles.TestableBubblePositioner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Unit tests for {@link com.android.wm.shell.bubbles.BubbleOverflow}.
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+public class BubbleOverflowTest extends ShellTestCase {
+
+ private TestableBubblePositioner mPositioner;
+ private BubbleOverflow mOverflow;
+
+ @Mock
+ private BubbleController mBubbleController;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ mPositioner = new TestableBubblePositioner(mContext, mock(WindowManager.class));
+ when(mBubbleController.getPositioner()).thenReturn(mPositioner);
+ when(mBubbleController.getStackView()).thenReturn(mock(BubbleStackView.class));
+
+ mOverflow = new BubbleOverflow(mContext, mPositioner);
+ }
+
+ @Test
+ public void test_initialize() {
+ assertThat(mOverflow.getExpandedView()).isNull();
+
+ mOverflow.initialize(mBubbleController);
+
+ assertThat(mOverflow.getExpandedView()).isNotNull();
+ assertThat(mOverflow.getExpandedView().getBubbleKey()).isEqualTo(BubbleOverflow.KEY);
+ }
+
+ @Test
+ public void test_cleanUpExpandedState() {
+ mOverflow.createExpandedView();
+ assertThat(mOverflow.getExpandedView()).isNotNull();
+
+ mOverflow.cleanUpExpandedState();
+ assertThat(mOverflow.getExpandedView()).isNull();
+ }
+
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java
index 6080f3a..403dbf9 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java
@@ -22,7 +22,7 @@
import android.hardware.display.DisplayManager;
import android.testing.TestableContext;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.After;
import org.junit.Before;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index 21ced0d..9054685 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -16,6 +16,7 @@
package com.android.wm.shell.back;
+import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -24,13 +25,18 @@
import android.app.IActivityTaskManager;
import android.app.WindowConfiguration;
import android.content.Context;
+import android.graphics.Point;
+import android.graphics.Rect;
import android.hardware.HardwareBuffer;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.testing.AndroidTestingRunner;
import android.view.MotionEvent;
+import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
+import android.window.BackEvent;
import android.window.BackNavigationInfo;
+import android.window.IOnBackInvokedCallback;
import androidx.test.filters.SmallTest;
@@ -40,6 +46,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -61,6 +68,9 @@
@Mock
private IActivityTaskManager mActivityTaskManager;
+ @Mock
+ private IOnBackInvokedCallback mIOnBackInvokedCallback;
+
private BackAnimationController mController;
@Before
@@ -70,12 +80,13 @@
mShellExecutor, mTransaction, mActivityTaskManager, mContext);
}
- private void createNavigationInfo(SurfaceControl topWindowLeash,
+ private void createNavigationInfo(RemoteAnimationTarget topAnimationTarget,
SurfaceControl screenshotSurface,
- HardwareBuffer hardwareBuffer) {
+ HardwareBuffer hardwareBuffer,
+ int backType) {
BackNavigationInfo navigationInfo = new BackNavigationInfo(
- BackNavigationInfo.TYPE_RETURN_TO_HOME,
- topWindowLeash,
+ backType,
+ topAnimationTarget,
screenshotSurface,
hardwareBuffer,
new WindowConfiguration(),
@@ -88,27 +99,71 @@
}
}
- @Test
- public void screenshotAttachedAndVisible() {
+ RemoteAnimationTarget createAnimationTarget() {
SurfaceControl topWindowLeash = new SurfaceControl();
+ return new RemoteAnimationTarget(-1, RemoteAnimationTarget.MODE_CLOSING, topWindowLeash,
+ false, new Rect(), new Rect(), -1,
+ new Point(0, 0), new Rect(), new Rect(), new WindowConfiguration(),
+ true, null, null, null, false, -1);
+ }
+
+ @Test
+ public void crossActivity_screenshotAttachedAndVisible() {
SurfaceControl screenshotSurface = new SurfaceControl();
HardwareBuffer hardwareBuffer = mock(HardwareBuffer.class);
- createNavigationInfo(topWindowLeash, screenshotSurface, hardwareBuffer);
- mController.onMotionEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0));
+ createNavigationInfo(createAnimationTarget(), screenshotSurface, hardwareBuffer,
+ BackNavigationInfo.TYPE_CROSS_ACTIVITY);
+ mController.onMotionEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0),
+ BackEvent.EDGE_LEFT);
verify(mTransaction).setBuffer(screenshotSurface, hardwareBuffer);
verify(mTransaction).setVisibility(screenshotSurface, true);
verify(mTransaction).apply();
}
@Test
- public void surfaceMovesWithGesture() {
- SurfaceControl topWindowLeash = new SurfaceControl();
+ public void crossActivity_surfaceMovesWithGesture() {
SurfaceControl screenshotSurface = new SurfaceControl();
HardwareBuffer hardwareBuffer = mock(HardwareBuffer.class);
- createNavigationInfo(topWindowLeash, screenshotSurface, hardwareBuffer);
- mController.onMotionEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0));
- mController.onMotionEvent(MotionEvent.obtain(10, 0, MotionEvent.ACTION_MOVE, 100, 100, 0));
- verify(mTransaction).setPosition(topWindowLeash, 100, 100);
+ RemoteAnimationTarget animationTarget = createAnimationTarget();
+ createNavigationInfo(animationTarget, screenshotSurface, hardwareBuffer,
+ BackNavigationInfo.TYPE_CROSS_ACTIVITY);
+ mController.onMotionEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0),
+ BackEvent.EDGE_LEFT);
+ mController.onMotionEvent(
+ MotionEvent.obtain(10, 0, MotionEvent.ACTION_MOVE, 100, 100, 0),
+ BackEvent.EDGE_LEFT);
+ verify(mTransaction).setPosition(animationTarget.leash, 100, 100);
verify(mTransaction, atLeastOnce()).apply();
}
+
+ @Test
+ public void backToHome_dispatchesEvents() throws RemoteException {
+ mController.setBackToLauncherCallback(mIOnBackInvokedCallback);
+ RemoteAnimationTarget animationTarget = createAnimationTarget();
+ createNavigationInfo(animationTarget, null, null,
+ BackNavigationInfo.TYPE_RETURN_TO_HOME);
+
+ // Check that back start is dispatched.
+ mController.onMotionEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0),
+ BackEvent.EDGE_LEFT);
+ verify(mIOnBackInvokedCallback).onBackStarted();
+
+ // Check that back progress is dispatched.
+ mController.onMotionEvent(
+ MotionEvent.obtain(10, 0, MotionEvent.ACTION_MOVE, 100, 100, 0),
+ BackEvent.EDGE_LEFT);
+ ArgumentCaptor<BackEvent> backEventCaptor = ArgumentCaptor.forClass(BackEvent.class);
+ verify(mIOnBackInvokedCallback).onBackProgressed(backEventCaptor.capture());
+ assertEquals(animationTarget, backEventCaptor.getValue().getDepartingAnimationTarget());
+
+ // Check that back invocation is dispatched.
+ mController.setTriggerBack(true); // Fake trigger back
+ mController.onMotionEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0),
+ BackEvent.EDGE_LEFT);
+ verify(mIOnBackInvokedCallback).onBackInvoked();
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
index 185479b..169f03e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
@@ -32,6 +32,7 @@
import android.app.Notification;
import android.app.PendingIntent;
+import android.content.LocusId;
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.UserHandle;
@@ -39,7 +40,6 @@
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
-import android.util.Log;
import android.util.Pair;
import android.view.WindowManager;
@@ -82,6 +82,7 @@
private BubbleEntry mEntryC1;
private BubbleEntry mEntryInterruptive;
private BubbleEntry mEntryDismissed;
+ private BubbleEntry mEntryLocusId;
private Bubble mBubbleA1;
private Bubble mBubbleA2;
@@ -92,6 +93,7 @@
private Bubble mBubbleC1;
private Bubble mBubbleInterruptive;
private Bubble mBubbleDismissed;
+ private Bubble mBubbleLocusId;
private BubbleData mBubbleData;
private TestableBubblePositioner mPositioner;
@@ -141,6 +143,10 @@
mBubbleDismissed = new Bubble(mEntryDismissed, mSuppressionListener, null,
mMainExecutor);
+ mEntryLocusId = createBubbleEntry(1, "keyLocus", "package.e", null,
+ new LocusId("locusId1"));
+ mBubbleLocusId = new Bubble(mEntryLocusId, mSuppressionListener, null, mMainExecutor);
+
mBubbleA1 = new Bubble(mEntryA1, mSuppressionListener, mPendingIntentCanceledListener,
mMainExecutor);
mBubbleA2 = new Bubble(mEntryA2, mSuppressionListener, mPendingIntentCanceledListener,
@@ -939,6 +945,102 @@
assertOrderChangedTo(mBubbleB3, mBubbleB2, mBubbleB1, mBubbleA3, mBubbleA2);
}
+ /**
+ * There is one bubble in the stack. If a task matching the locusId becomes visible, suppress
+ * the bubble. If it is hidden, unsuppress the bubble.
+ */
+ @Test
+ public void test_onLocusVisibilityChanged_singleBubble() {
+ sendUpdatedEntryAtTime(mEntryLocusId, 1000);
+ mBubbleData.setListener(mListener);
+
+ // Suppress the bubble
+ mBubbleData.onLocusVisibilityChanged(100, mEntryLocusId.getLocusId(), true /* visible */);
+ verifyUpdateReceived();
+ assertBubbleSuppressed(mBubbleLocusId);
+ assertOrderNotChanged();
+ assertBubbleListContains(/* empty list */);
+
+ // Unsuppress the bubble
+ mBubbleData.onLocusVisibilityChanged(100, mEntryLocusId.getLocusId(), false /* visible */);
+ verifyUpdateReceived();
+ assertBubbleUnsuppressed(mBubbleLocusId);
+ assertOrderNotChanged();
+ assertBubbleListContains(mBubbleLocusId);
+ }
+
+ /**
+ * Bubble stack has multiple bubbles. Suppress bubble based on matching locusId. Suppressed
+ * bubble is at the top.
+ *
+ * When suppressed:
+ * - hide bubble
+ * - update order
+ * - update selection
+ *
+ * When unsuppressed:
+ * - show bubble
+ * - update order
+ * - update selection
+ */
+ @Test
+ public void test_onLocusVisibilityChanged_multipleBubbles_suppressTopBubble() {
+ sendUpdatedEntryAtTime(mEntryA1, 1000);
+ sendUpdatedEntryAtTime(mEntryA2, 2000);
+ sendUpdatedEntryAtTime(mEntryLocusId, 3000);
+ mBubbleData.setListener(mListener);
+
+ // Suppress bubble
+ mBubbleData.onLocusVisibilityChanged(100, mEntryLocusId.getLocusId(), true /* visible */);
+ verifyUpdateReceived();
+ assertBubbleSuppressed(mBubbleLocusId);
+ assertSelectionChangedTo(mBubbleA2);
+ assertOrderChangedTo(mBubbleA2, mBubbleA1);
+
+ // Unsuppress bubble
+ mBubbleData.onLocusVisibilityChanged(100, mEntryLocusId.getLocusId(), false /* visible */);
+ verifyUpdateReceived();
+ assertBubbleUnsuppressed(mBubbleLocusId);
+ assertSelectionChangedTo(mBubbleLocusId);
+ assertOrderChangedTo(mBubbleLocusId, mBubbleA2, mBubbleA1);
+ }
+
+ /**
+ * Bubble stack has multiple bubbles. Suppress bubble based on matching locusId. Suppressed
+ * bubble is not at the top.
+ *
+ * When suppressed:
+ * - hide suppressed bubble
+ * - do not update order
+ * - do not update selection
+ *
+ * When unsuppressed:
+ * - show bubble
+ * - do not update order
+ * - do not update selection
+ */
+ @Test
+ public void test_onLocusVisibilityChanged_multipleBubbles_suppressStackedBubble() {
+ sendUpdatedEntryAtTime(mEntryLocusId, 1000);
+ sendUpdatedEntryAtTime(mEntryA1, 2000);
+ sendUpdatedEntryAtTime(mEntryA2, 3000);
+ mBubbleData.setListener(mListener);
+
+ // Suppress bubble
+ mBubbleData.onLocusVisibilityChanged(100, mEntryLocusId.getLocusId(), true /* visible */);
+ verifyUpdateReceived();
+ assertBubbleSuppressed(mBubbleLocusId);
+ assertSelectionNotChanged();
+ assertBubbleListContains(mBubbleA2, mBubbleA1);
+
+ // Unsuppress bubble
+ mBubbleData.onLocusVisibilityChanged(100, mEntryLocusId.getLocusId(), false /* visible */);
+ verifyUpdateReceived();
+ assertBubbleUnsuppressed(mBubbleLocusId);
+ assertSelectionNotChanged();
+ assertBubbleListContains(mBubbleA2, mBubbleA1, mBubbleLocusId);
+ }
+
private void verifyUpdateReceived() {
verify(mListener).applyUpdate(mUpdateCaptor.capture());
reset(mListener);
@@ -995,9 +1097,29 @@
assertThat(update.overflowBubbles).isEqualTo(bubbles);
}
+ private void assertBubbleListContains(Bubble... bubbles) {
+ BubbleData.Update update = mUpdateCaptor.getValue();
+ assertWithMessage("bubbleList").that(update.bubbles).containsExactlyElementsIn(bubbles);
+ }
+
+ private void assertBubbleSuppressed(Bubble expected) {
+ BubbleData.Update update = mUpdateCaptor.getValue();
+ assertWithMessage("suppressedBubble").that(update.suppressedBubble).isEqualTo(expected);
+ }
+
+ private void assertBubbleUnsuppressed(Bubble expected) {
+ BubbleData.Update update = mUpdateCaptor.getValue();
+ assertWithMessage("unsuppressedBubble").that(update.unsuppressedBubble).isEqualTo(expected);
+ }
+
private BubbleEntry createBubbleEntry(int userId, String notifKey, String packageName,
NotificationListenerService.Ranking ranking) {
- return createBubbleEntry(userId, notifKey, packageName, ranking, 1000);
+ return createBubbleEntry(userId, notifKey, packageName, ranking, 1000, null);
+ }
+
+ private BubbleEntry createBubbleEntry(int userId, String notifKey, String packageName,
+ NotificationListenerService.Ranking ranking, LocusId locusId) {
+ return createBubbleEntry(userId, notifKey, packageName, ranking, 1000, locusId);
}
private void setPostTime(BubbleEntry entry, long postTime) {
@@ -1010,15 +1132,18 @@
* as a convenience to create a Notification w/BubbleMetadata.
*/
private BubbleEntry createBubbleEntry(int userId, String notifKey, String packageName,
- NotificationListenerService.Ranking ranking, long postTime) {
+ NotificationListenerService.Ranking ranking, long postTime,
+ LocusId locusId) {
// BubbleMetadata
Notification.BubbleMetadata bubbleMetadata = new Notification.BubbleMetadata.Builder(
mExpandIntent, Icon.createWithResource("", 0))
.setDeleteIntent(mDeleteIntent)
+ .setSuppressableBubble(true)
.build();
// Notification -> BubbleMetadata
Notification notification = mock(Notification.class);
- notification.setBubbleMetadata(bubbleMetadata);
+ when(notification.getBubbleMetadata()).thenReturn(bubbleMetadata);
+ when(notification.getLocusId()).thenReturn(locusId);
// Notification -> extras
notification.extras = new Bundle();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
index 35e4982..bb6026c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
@@ -23,6 +23,8 @@
import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
@@ -32,6 +34,7 @@
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP;
+import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
@@ -50,9 +53,11 @@
import android.app.PendingIntent;
import android.content.ClipData;
import android.content.ClipDescription;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
+import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Insets;
@@ -177,6 +182,12 @@
info.configuration.windowConfiguration.setActivityType(actType);
info.configuration.windowConfiguration.setWindowingMode(winMode);
info.isResizeable = true;
+ info.baseActivity = new ComponentName(getInstrumentation().getContext().getPackageName(),
+ ".ActivityWithMode" + winMode);
+ ActivityInfo activityInfo = new ActivityInfo();
+ activityInfo.packageName = info.baseActivity.getPackageName();
+ activityInfo.name = info.baseActivity.getClassName();
+ info.topActivityInfo = activityInfo;
return info;
}
@@ -252,6 +263,62 @@
}
}
+ @Test
+ public void testLaunchMultipleTask_differentActivity() {
+ setRunningTask(mFullscreenAppTask);
+ mPolicy.start(mLandscapeDisplayLayout, mActivityClipData, mLoggerSessionId);
+ Intent fillInIntent = mPolicy.getStartIntentFillInIntent(mock(PendingIntent.class), 0);
+ assertNull(fillInIntent);
+ }
+
+ @Test
+ public void testLaunchMultipleTask_differentActivity_inSplitscreen() {
+ setRunningTask(mFullscreenAppTask);
+ doReturn(true).when(mSplitScreenStarter).isSplitScreenVisible();
+ doReturn(mFullscreenAppTask).when(mSplitScreenStarter).getTaskInfo(anyInt());
+ mPolicy.start(mLandscapeDisplayLayout, mActivityClipData, mLoggerSessionId);
+ Intent fillInIntent = mPolicy.getStartIntentFillInIntent(mock(PendingIntent.class), 0);
+ assertNull(fillInIntent);
+ }
+
+ @Test
+ public void testLaunchMultipleTask_sameActivity() {
+ setRunningTask(mFullscreenAppTask);
+
+ // Replace the mocked drag pending intent and ensure it resolves to the same activity
+ PendingIntent launchIntent = mock(PendingIntent.class);
+ ResolveInfo launchInfo = new ResolveInfo();
+ launchInfo.activityInfo = mFullscreenAppTask.topActivityInfo;
+ doReturn(Collections.singletonList(launchInfo))
+ .when(launchIntent).queryIntentComponents(anyInt());
+ mActivityClipData.getItemAt(0).getIntent().putExtra(ClipDescription.EXTRA_PENDING_INTENT,
+ launchIntent);
+
+ mPolicy.start(mLandscapeDisplayLayout, mActivityClipData, mLoggerSessionId);
+ Intent fillInIntent = mPolicy.getStartIntentFillInIntent(launchIntent, 0);
+ assertTrue((fillInIntent.getFlags() & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) != 0);
+ }
+
+ @Test
+ public void testLaunchMultipleTask_sameActivity_inSplitScreen() {
+ setRunningTask(mFullscreenAppTask);
+
+ // Replace the mocked drag pending intent and ensure it resolves to the same activity
+ PendingIntent launchIntent = mock(PendingIntent.class);
+ ResolveInfo launchInfo = new ResolveInfo();
+ launchInfo.activityInfo = mFullscreenAppTask.topActivityInfo;
+ doReturn(Collections.singletonList(launchInfo))
+ .when(launchIntent).queryIntentComponents(anyInt());
+ mActivityClipData.getItemAt(0).getIntent().putExtra(ClipDescription.EXTRA_PENDING_INTENT,
+ launchIntent);
+
+ doReturn(true).when(mSplitScreenStarter).isSplitScreenVisible();
+ doReturn(mFullscreenAppTask).when(mSplitScreenStarter).getTaskInfo(anyInt());
+ mPolicy.start(mLandscapeDisplayLayout, mActivityClipData, mLoggerSessionId);
+ Intent fillInIntent = mPolicy.getStartIntentFillInIntent(launchIntent, 0);
+ assertTrue((fillInIntent.getFlags() & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) != 0);
+ }
+
private Target filterTargetByType(ArrayList<Target> targets, int type) {
for (Target t : targets) {
if (type == t.type) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutControllerTest.java
index f10dc16..b976c12 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutControllerTest.java
@@ -24,8 +24,8 @@
import android.testing.TestableContext;
import android.testing.TestableLooper;
-import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
import com.android.wm.shell.common.ShellExecutor;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java
index 078e2b6..16e9239 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java
@@ -45,8 +45,8 @@
import android.window.IWindowContainerToken;
import android.window.WindowContainerToken;
-import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index 0f4a06f..dbf93b4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -591,6 +591,13 @@
.setRotate().build())
.build();
assertFalse(DefaultTransitionHandler.isRotationSeamless(noTask, displays));
+
+ // Seamless if display is explicitly seamless.
+ final TransitionInfo seamlessDisplay = new TransitionInfoBuilder(TRANSIT_CHANGE)
+ .addChange(new ChangeBuilder(TRANSIT_CHANGE).setFlags(FLAG_IS_DISPLAY)
+ .setRotate(ROTATION_ANIMATION_SEAMLESS).build())
+ .build();
+ assertTrue(DefaultTransitionHandler.isRotationSeamless(seamlessDisplay, displays));
}
class TransitionInfoBuilder {
diff --git a/libs/hwui/effects/StretchEffect.cpp b/libs/hwui/effects/StretchEffect.cpp
index 8cb4515..2757c39 100644
--- a/libs/hwui/effects/StretchEffect.cpp
+++ b/libs/hwui/effects/StretchEffect.cpp
@@ -227,7 +227,7 @@
mBuilder->uniform("viewportWidth").set(&width, 1);
mBuilder->uniform("viewportHeight").set(&height, 1);
- auto result = mBuilder->makeShader(nullptr, false);
+ auto result = mBuilder->makeShader();
mBuilder->child(CONTENT_TEXTURE) = nullptr;
return result;
}
diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp
index 899c7d4..0bbd8a8 100644
--- a/libs/hwui/jni/Shader.cpp
+++ b/libs/hwui/jni/Shader.cpp
@@ -264,7 +264,7 @@
static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderBuilder, jlong matrixPtr) {
SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
- sk_sp<SkShader> shader = builder->makeShader(matrix, false);
+ sk_sp<SkShader> shader = builder->makeShader(matrix);
ThrowIAE_IfNull(env, shader);
return reinterpret_cast<jlong>(shader.release());
}
diff --git a/libs/hwui/pipeline/skia/AnimatedDrawables.h b/libs/hwui/pipeline/skia/AnimatedDrawables.h
index d173782..9cf93e6 100644
--- a/libs/hwui/pipeline/skia/AnimatedDrawables.h
+++ b/libs/hwui/pipeline/skia/AnimatedDrawables.h
@@ -110,7 +110,7 @@
const float rotation3 = turbulencePhase * PI_ROTATE_RIGHT + 2.75 * PI;
setUniform2f(effectBuilder, "in_tRotation3", cos(rotation3), sin(rotation3));
- params.paint->value.setShader(effectBuilder.makeShader(nullptr, false));
+ params.paint->value.setShader(effectBuilder.makeShader());
canvas->drawCircle(params.x->value, params.y->value, params.radius->value,
params.paint->value);
}
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index 7c57bd5..2fba13c 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -98,7 +98,7 @@
effectBuilder.uniform(uniform.name.c_str()).set(uniform.value.data(), uniform.value.size());
}
- return effectBuilder.makeShader(nullptr, false);
+ return effectBuilder.makeShader();
}
static bool isHdrDataspace(ui::Dataspace dataspace) {
diff --git a/location/java/android/location/GnssClock.java b/location/java/android/location/GnssClock.java
index ed4bf1b..62f50b5 100644
--- a/location/java/android/location/GnssClock.java
+++ b/location/java/android/location/GnssClock.java
@@ -23,9 +23,9 @@
import android.os.Parcelable;
/**
- * A class containing a GPS clock timestamp.
+ * A class containing a GNSS clock timestamp.
*
- * <p>It represents a measurement of the GPS receiver's clock.
+ * <p>It represents a measurement of the GNSS receiver's clock.
*/
public final class GnssClock implements Parcelable {
// The following enumerations must be in sync with the values declared in gps.h
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index 1fcb194..f1605f1 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -45,8 +45,8 @@
* timestamp, accuracy, and other information such as bearing, altitude and velocity.
*
* <p>All locations generated through {@link LocationManager} are guaranteed to have a valid
- * latitude, longitude, timestamp (both UTC time and elapsed real-time since boot), and accuracy.
- * All other parameters are optional.
+ * latitude, longitude, timestamp (both Unix epoch time and elapsed realtime since boot), and
+ * accuracy. All other parameters are optional.
*/
public class Location implements Parcelable {
@@ -240,36 +240,39 @@
}
/**
- * Return the UTC time of this location fix, in milliseconds since epoch (January 1, 1970).
+ * Returns the Unix epoch time of this location fix, in milliseconds since the start of the Unix
+ * epoch (00:00:00 January 1, 1970 UTC).
*
* <p>There is no guarantee that different locations have times set from the same clock.
* Locations derived from the {@link LocationManager#GPS_PROVIDER} are guaranteed to have their
- * time set from the clock in use by the satellite constellation that provided the fix.
+ * time originate from the clock in use by the satellite constellation that provided the fix.
* Locations derived from other providers may use any clock to set their time, though it is most
- * common to use the device clock (which may be incorrect).
+ * common to use the device's Unix epoch time system clock (which may be incorrect).
*
- * <p>Note that the device clock UTC time is not monotonic; it can jump forwards or backwards
- * unpredictably and may be changed at any time by the user, so this time should not be used to
- * order or compare locations. Prefer {@link #getElapsedRealtimeNanos} for that purpose, as this
- * clock is guaranteed to be monotonic.
+ * <p>Note that the device's Unix epoch time system clock is not monotonic; it can jump forwards
+ * or backwards unpredictably and may be changed at any time by the user, so this time should
+ * not be used to order or compare locations. Prefer {@link #getElapsedRealtimeNanos} for that
+ * purpose, as the elapsed realtime clock is guaranteed to be monotonic.
*
* <p>On the other hand, this method may be useful for presenting a human readable time to the
* user, or as a heuristic for comparing location fixes across reboot or across devices.
*
- * <p>All locations generated by the {@link LocationManager} are guaranteed to have a UTC time
- * set, however remember that the device clock may have changed since the location was
+ * <p>All locations generated by the {@link LocationManager} are guaranteed to have this time
+ * set, however remember that the device's system clock may have changed since the location was
* generated.
*
- * @return UTC time of this location
+ * @return the Unix epoch time of this location
*/
public @IntRange long getTime() {
return mTimeMs;
}
/**
- * Set the UTC time of this location, in milliseconds since epoch (January 1, 1970).
+ * Sets the Unix epoch time of this location fix, in milliseconds since the start of the Unix
+ * epoch (00:00:00 January 1, 1970 UTC).
*
- * @param timeMs UTC time of this location
+ * @param timeMs the Unix epoch time of this location
+ * @see #getTime for more information about times / clocks
*/
public void setTime(@IntRange long timeMs) {
mTimeMs = timeMs;
diff --git a/location/java/android/location/OnNmeaMessageListener.java b/location/java/android/location/OnNmeaMessageListener.java
index 1c02ebd..def688c 100644
--- a/location/java/android/location/OnNmeaMessageListener.java
+++ b/location/java/android/location/OnNmeaMessageListener.java
@@ -31,9 +31,8 @@
/**
* Called when an NMEA message is received.
* @param message NMEA message
- * @param timestamp Date and time of the location fix, as reported by the GNSS
- * chipset. The value is specified in milliseconds since 0:00
- * UTC 1 January 1970.
+ * @param timestamp Timestamp of the location fix, as reported by the GNSS chipset. The value
+ * is specified in Unix time milliseconds since 1st January 1970, 00:00:00 UTC
*/
void onNmeaMessage(String message, long timestamp);
}
diff --git a/media/Android.bp b/media/Android.bp
index 5aedcfb..2f9c520 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -103,6 +103,11 @@
},
java: {
sdk_version: "module_current",
+ min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.car.framework",
+ ],
},
ndk: {
vndk: {
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index cdc3163..3887372 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -91,6 +91,7 @@
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
/**
* AudioManager provides access to volume and ringer mode control.
@@ -8342,6 +8343,106 @@
}
}
+ /**
+ * Add UID's that can be considered as assistant.
+ *
+ * @param assistantUids UID's of the services that can be considered as assistant.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public void addAssistantServicesUids(@NonNull List<Integer> assistantUids) {
+ try {
+ getService().addAssistantServicesUids(assistantUids.stream()
+ .mapToInt(Integer::intValue).toArray());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Remove UID's that can be considered as assistant.
+ *
+ * @param assistantUids UID'S of the services that should be remove.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public void removeAssistantServicesUids(@NonNull List<Integer> assistantUids) {
+ try {
+ getService().removeAssistantServicesUids(assistantUids.stream()
+ .mapToInt(Integer::intValue).toArray());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Get the list of assistants UIDs that been added with the
+ * {@link #addAssistantServicesUids(List)} (List)} and not yet removed with
+ * {@link #removeAssistantServicesUids(List)}
+ *
+ * @return list of assistants UID's
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public @NonNull List<Integer> getAssistantServicesUids() {
+ try {
+ int[] uids = getService().getAssistantServicesUids();
+ return Arrays.stream(uids).boxed().collect(Collectors.toList());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Sets UID's that can be considered as active assistant. Calling the API with a new list will
+ * overwrite previous list. If the list of UIDs is empty then no UID will be considered active.
+ * In this manner calling the API with an empty list will remove all UID's previously set.
+ *
+ * @param assistantUids UID'S of the services that can be considered active assistant. Can be
+ * an empty list, for this no UID will be considered active.
+ *
+ * <p> Note that during audio service crash reset and after boot up the list of active assistant
+ * UID's will be reset to an empty list (i.e. no UID will be considered as an active assistant).
+ * Just after user switch the list of active assistant will also reset to empty.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public void setActiveAssistantServiceUids(@NonNull List<Integer> assistantUids) {
+ try {
+ getService().setActiveAssistantServiceUids(assistantUids.stream()
+ .mapToInt(Integer::intValue).toArray());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Get the list of active assistant UIDs last set with the
+ * {@link #setActiveAssistantServiceUids(List)}
+ *
+ * @return list of active assistants UID's
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public @NonNull List<Integer> getActiveAssistantServicesUids() {
+ try {
+ int[] uids = getService().getActiveAssistantServiceUids();
+ return Arrays.stream(uids).boxed().collect(Collectors.toList());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
private final Object mMuteAwaitConnectionListenerLock = new Object();
@GuardedBy("mMuteAwaitConnectionListenerLock")
diff --git a/media/java/android/media/AudioManagerInternal.java b/media/java/android/media/AudioManagerInternal.java
index cb887f2..c263245 100644
--- a/media/java/android/media/AudioManagerInternal.java
+++ b/media/java/android/media/AudioManagerInternal.java
@@ -38,20 +38,29 @@
public abstract void updateRingerModeAffectedStreamsInternal();
- /**
- * Notify the UID of the currently active {@link android.service.voice.HotwordDetectionService}.
- *
- * <p>The caller is expected to take care of any performance implications, e.g. by using a
- * background thread to call this method.</p>
- *
- * @param uid UID of the currently active service or {@link android.os.Process#INVALID_UID} if
- * none.
- */
- public abstract void setHotwordDetectionServiceUid(int uid);
-
public abstract void setAccessibilityServiceUids(IntArray uids);
/**
+ * Add the UID for a new assistant service
+ *
+ * @param uid UID of the newly available assistants
+ */
+ public abstract void addAssistantServiceUid(int uid);
+
+ /**
+ * Remove the UID for an existing assistant service
+ *
+ * @param uid UID of the currently available assistant
+ */
+ public abstract void removeAssistantServiceUid(int uid);
+
+ /**
+ * Set the currently active assistant service UIDs
+ * @param activeUids active UIDs of the assistant service
+ */
+ public abstract void setActiveAssistantServicesUids(IntArray activeUids);
+
+ /**
* Called by {@link com.android.server.inputmethod.InputMethodManagerService} to notify the UID
* of the currently used {@link android.inputmethodservice.InputMethodService}.
*
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 536b4ad..6cacebb 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -1856,16 +1856,15 @@
/**
* @hide
- * Communicate UID of active assistant to audio policy service.
+ * Communicate UIDs of the active assistant to audio policy service.
*/
- public static native int setAssistantUid(int uid);
+ public static native int setActiveAssistantServicesUids(int[] uids);
/**
- * Communicate UID of the current {@link android.service.voice.HotwordDetectionService} to audio
- * policy service.
* @hide
+ * Communicate UIDs of assistant to audio policy service.
*/
- public static native int setHotwordDetectionServiceUid(int uid);
+ public static native int setAssistantServicesUids(int[] uids);
/**
* @hide
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index fec14de..a6fdf6c 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -402,6 +402,14 @@
boolean isSpatializerAvailable();
+ boolean isSpatializerAvailableForDevice(in AudioDeviceAttributes device);
+
+ boolean hasHeadTracker(in AudioDeviceAttributes device);
+
+ void setHeadTrackerEnabled(boolean enabled, in AudioDeviceAttributes device);
+
+ boolean isHeadTrackerEnabled(in AudioDeviceAttributes device);
+
void setSpatializerEnabled(boolean enabled);
boolean canBeSpatialized(in AudioAttributes aa, in AudioFormat af);
@@ -465,4 +473,19 @@
List<AudioFocusInfo> getFocusStack();
boolean sendFocusLoss(in AudioFocusInfo focusLoser, in IAudioPolicyCallback apcb);
+
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)")
+ void addAssistantServicesUids(in int[] assistantUID);
+
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)")
+ void removeAssistantServicesUids(in int[] assistantUID);
+
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)")
+ void setActiveAssistantServiceUids(in int[] activeUids);
+
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)")
+ int[] getAssistantServicesUids();
+
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)")
+ int[] getActiveAssistantServiceUids();
}
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 939b679..4563259 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -16,9 +16,12 @@
package android.media;
+import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.ImageFormat;
import android.graphics.Rect;
@@ -1934,12 +1937,41 @@
@NonNull
public static MediaCodec createByCodecName(@NonNull String name)
throws IOException {
- return new MediaCodec(
- name, false /* nameIsType */, false /* unused */);
+ return new MediaCodec(name, false /* nameIsType */, false /* encoder */);
}
- private MediaCodec(
- @NonNull String name, boolean nameIsType, boolean encoder) {
+ /**
+ * This is the same as createByCodecName, but allows for instantiating a codec on behalf of a
+ * client process. This is used for system apps or system services that create MediaCodecs on
+ * behalf of other processes and will reclaim resources as necessary from processes with lower
+ * priority than the client process, rather than processes with lower priority than the system
+ * app or system service. Likely to be used with information obtained from
+ * {@link android.media.MediaCodecList}.
+ * @param name
+ * @param clientPid
+ * @param clientUid
+ * @throws IOException if the codec cannot be created.
+ * @throws IllegalArgumentException if name is not valid.
+ * @throws NullPointerException if name is null.
+ * @throws SecurityException if the MEDIA_RESOURCE_OVERRIDE_PID permission is not granted.
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ @RequiresPermission(Manifest.permission.MEDIA_RESOURCE_OVERRIDE_PID)
+ public static MediaCodec createByCodecNameForClient(@NonNull String name, int clientPid,
+ int clientUid) throws IOException {
+ return new MediaCodec(name, false /* nameIsType */, false /* encoder */, clientPid,
+ clientUid);
+ }
+
+ private MediaCodec(@NonNull String name, boolean nameIsType, boolean encoder) {
+ this(name, nameIsType, encoder, -1 /* pid */, -1 /* uid */);
+ }
+
+ private MediaCodec(@NonNull String name, boolean nameIsType, boolean encoder, int pid,
+ int uid) {
Looper looper;
if ((looper = Looper.myLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
@@ -1957,7 +1989,7 @@
// save name used at creation
mNameAtCreation = nameIsType ? null : name;
- native_setup(name, nameIsType, encoder);
+ native_setup(name, nameIsType, encoder, pid, uid);
}
private String mNameAtCreation;
@@ -4991,7 +5023,7 @@
private static native final void native_init();
private native final void native_setup(
- @NonNull String name, boolean nameIsType, boolean encoder);
+ @NonNull String name, boolean nameIsType, boolean encoder, int pid, int uid);
private native final void native_finalize();
diff --git a/media/java/android/media/MediaRoute2ProviderInfo.java b/media/java/android/media/MediaRoute2ProviderInfo.java
index afe002e..809ee23 100644
--- a/media/java/android/media/MediaRoute2ProviderInfo.java
+++ b/media/java/android/media/MediaRoute2ProviderInfo.java
@@ -151,7 +151,7 @@
}
/**
- * Sets the unique id of the provider info.
+ * Sets the package name and unique id of the provider info.
* <p>
* The unique id is automatically set by
* {@link com.android.server.media.MediaRouterService} and used to identify providers.
@@ -160,7 +160,7 @@
* @hide
*/
@NonNull
- public Builder setUniqueId(@Nullable String uniqueId) {
+ public Builder setUniqueId(@Nullable String packageName, @Nullable String uniqueId) {
if (TextUtils.equals(mUniqueId, uniqueId)) {
return this;
}
@@ -169,6 +169,7 @@
final ArrayMap<String, MediaRoute2Info> newRoutes = new ArrayMap<>();
for (Map.Entry<String, MediaRoute2Info> entry : mRoutes.entrySet()) {
MediaRoute2Info routeWithProviderId = new MediaRoute2Info.Builder(entry.getValue())
+ .setPackageName(packageName)
.setProviderId(mUniqueId)
.build();
newRoutes.put(routeWithProviderId.getOriginalId(), routeWithProviderId);
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 13c1498..7d57734 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -60,21 +60,21 @@
import java.util.concurrent.CopyOnWriteArrayList;
/**
- * MediaRouter allows applications to control the routing of media channels
+ * This API is not recommended for new applications. Use the
+ * <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/mediarouter/media/package-summary.html">Media Router
+ * Library</a> for consistent behavior across all devices.
+ *
+ * <p>MediaRouter allows applications to control the routing of media channels
* and streams from the current device to external speakers and destination devices.
*
* <p>A MediaRouter is retrieved through {@link Context#getSystemService(String)
* Context.getSystemService()} of a {@link Context#MEDIA_ROUTER_SERVICE
* Context.MEDIA_ROUTER_SERVICE}.
*
- * <p>The media router API is not thread-safe; all interactions with it must be
- * done from the main thread of the process.</p>
- *
- * <p>
- * We recommend using {@link android.media.MediaRouter2} APIs for new applications.
- * </p>
+ * <p>This API is not thread-safe; all interactions with it must be done from the main thread of the
+ * process.
*/
-//TODO: Link androidx.media2.MediaRouter when we are ready.
@SystemService(Context.MEDIA_ROUTER_SERVICE)
public class MediaRouter {
private static final String TAG = "MediaRouter";
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index b485eb5..311476c 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -52,13 +52,13 @@
import java.util.stream.Collectors;
/**
- * 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/mediarouter/media/package-summary.html">Media Router
+ * 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/mediarouter/media/package-summary.html">Media Router
* Library</a> for consistent behavior across all devices.
*
- * Media Router 2 allows applications to control the routing of media channels
- * and streams from the current device to remote speakers and devices.
+ * <p>MediaRouter2 allows applications to control the routing of media channels and streams from
+ * the current device to remote speakers and devices.
*/
// TODO(b/157873330): Add method names at the beginning of log messages. (e.g. selectRoute)
// Not only MediaRouter2, but also to service / manager / provider.
@@ -478,13 +478,8 @@
if (mShouldUpdateRoutes) {
mShouldUpdateRoutes = false;
- List<MediaRoute2Info> filteredRoutes = new ArrayList<>();
- for (MediaRoute2Info route : mRoutes.values()) {
- if (route.hasAnyFeatures(mDiscoveryPreference.getPreferredFeatures())) {
- filteredRoutes.add(route);
- }
- }
- mFilteredRoutes = Collections.unmodifiableList(filteredRoutes);
+ mFilteredRoutes = Collections.unmodifiableList(
+ filterRoutes(List.copyOf(mRoutes.values()), mDiscoveryPreference));
}
}
return mFilteredRoutes;
@@ -1087,16 +1082,17 @@
List<MediaRoute2Info> filteredRoutes = new ArrayList<>();
for (MediaRoute2Info route : getSortedRoutes(routes, discoveryPreference)) {
- if (!route.hasAllFeatures(discoveryPreference.getRequiredFeatures())
- || !route.hasAnyFeatures(discoveryPreference.getPreferredFeatures())) {
+ if (!route.hasAnyFeatures(discoveryPreference.getPreferredFeatures())) {
continue;
}
if (!discoveryPreference.getAllowedPackages().isEmpty()
- && !discoveryPreference.getAllowedPackages().contains(route.getPackageName())) {
+ && (route.getPackageName() == null
+ || !discoveryPreference.getAllowedPackages()
+ .contains(route.getPackageName()))) {
continue;
}
if (discoveryPreference.shouldRemoveDuplicates()) {
- if (Collections.disjoint(deduplicationIdSet, route.getDeduplicationIds())) {
+ if (!Collections.disjoint(deduplicationIdSet, route.getDeduplicationIds())) {
continue;
}
deduplicationIdSet.addAll(route.getDeduplicationIds());
@@ -2087,19 +2083,17 @@
}
@Override
- public void onPreferredFeaturesChanged(@NonNull String packageName,
- @NonNull List<String> preferredFeatures) {
+ public void onDiscoveryPreferenceChanged(@NonNull String packageName,
+ @NonNull RouteDiscoveryPreference preference) {
if (!TextUtils.equals(mClientPackageName, packageName)) {
return;
}
synchronized (mLock) {
- mDiscoveryPreference = new RouteDiscoveryPreference.Builder(
- preferredFeatures, true).build();
+ mDiscoveryPreference = preference;
}
-
updateAllRoutesFromManager();
- notifyPreferredFeaturesChanged(preferredFeatures);
+ notifyPreferredFeaturesChanged(preference.getPreferredFeatures());
}
@Override
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 8635c0e..071667a 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -254,7 +254,7 @@
@NonNull
public List<MediaRoute2Info> getAvailableRoutes(@NonNull RoutingSessionInfo sessionInfo) {
return getFilteredRoutes(sessionInfo, /*includeSelectedRoutes=*/true,
- null);
+ /*additionalFilter=*/null);
}
/**
@@ -315,20 +315,20 @@
routes.add(route);
continue;
}
- if (!route.hasAllFeatures(discoveryPreference.getRequiredFeatures())
- || !route.hasAnyFeatures(discoveryPreference.getPreferredFeatures())) {
+ if (!route.hasAnyFeatures(discoveryPreference.getPreferredFeatures())) {
continue;
}
if (!discoveryPreference.getAllowedPackages().isEmpty()
- && !discoveryPreference.getAllowedPackages()
- .contains(route.getPackageName())) {
+ && (route.getPackageName() == null
+ || !discoveryPreference.getAllowedPackages()
+ .contains(route.getPackageName()))) {
continue;
}
if (additionalFilter != null && !additionalFilter.test(route)) {
continue;
}
if (discoveryPreference.shouldRemoveDuplicates()) {
- if (Collections.disjoint(deduplicationIdSet, route.getDeduplicationIds())) {
+ if (!Collections.disjoint(deduplicationIdSet, route.getDeduplicationIds())) {
continue;
}
deduplicationIdSet.addAll(route.getDeduplicationIds());
diff --git a/media/java/android/media/RouteDiscoveryPreference.java b/media/java/android/media/RouteDiscoveryPreference.java
index e609226..0ba36fe 100644
--- a/media/java/android/media/RouteDiscoveryPreference.java
+++ b/media/java/android/media/RouteDiscoveryPreference.java
@@ -24,7 +24,6 @@
import android.os.Parcelable;
import android.text.TextUtils;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
@@ -65,8 +64,6 @@
@NonNull
private final List<String> mPreferredFeatures;
@NonNull
- private final List<String> mRequiredFeatures;
- @NonNull
private final List<String> mPackageOrder;
@NonNull
private final List<String> mAllowedPackages;
@@ -85,7 +82,6 @@
RouteDiscoveryPreference(@NonNull Builder builder) {
mPreferredFeatures = builder.mPreferredFeatures;
- mRequiredFeatures = builder.mRequiredFeatures;
mPackageOrder = builder.mPackageOrder;
mAllowedPackages = builder.mAllowedPackages;
mShouldPerformActiveScan = builder.mActiveScan;
@@ -94,7 +90,6 @@
RouteDiscoveryPreference(@NonNull Parcel in) {
mPreferredFeatures = in.createStringArrayList();
- mRequiredFeatures = in.createStringArrayList();
mPackageOrder = in.createStringArrayList();
mAllowedPackages = in.createStringArrayList();
mShouldPerformActiveScan = in.readBoolean();
@@ -109,8 +104,6 @@
* {@link MediaRoute2Info#FEATURE_LIVE_AUDIO}, {@link MediaRoute2Info#FEATURE_LIVE_VIDEO},
* or {@link MediaRoute2Info#FEATURE_REMOTE_PLAYBACK} or custom features defined by a provider.
* </p>
- *
- * @see #getRequiredFeatures()
*/
@NonNull
public List<String> getPreferredFeatures() {
@@ -118,21 +111,6 @@
}
/**
- * Gets the required features of routes that media router would like to discover.
- * <p>
- * Routes that have all the required features will be discovered.
- * They may include predefined features such as
- * {@link MediaRoute2Info#FEATURE_LIVE_AUDIO}, {@link MediaRoute2Info#FEATURE_LIVE_VIDEO},
- * or {@link MediaRoute2Info#FEATURE_REMOTE_PLAYBACK} or custom features defined by a provider.
- *
- * @see #getPreferredFeatures()
- */
- @NonNull
- public List<String> getRequiredFeatures() {
- return mRequiredFeatures;
- }
-
- /**
* Gets the ordered list of package names used to remove duplicate routes.
* <p>
* Duplicate route removal is enabled if the returned list is non-empty. Routes are deduplicated
@@ -193,7 +171,6 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeStringList(mPreferredFeatures);
- dest.writeStringList(mRequiredFeatures);
dest.writeStringList(mPackageOrder);
dest.writeStringList(mAllowedPackages);
dest.writeBoolean(mShouldPerformActiveScan);
@@ -224,7 +201,6 @@
}
RouteDiscoveryPreference other = (RouteDiscoveryPreference) o;
return Objects.equals(mPreferredFeatures, other.mPreferredFeatures)
- && Objects.equals(mRequiredFeatures, other.mRequiredFeatures)
&& Objects.equals(mPackageOrder, other.mPackageOrder)
&& Objects.equals(mAllowedPackages, other.mAllowedPackages)
&& mShouldPerformActiveScan == other.mShouldPerformActiveScan;
@@ -232,7 +208,7 @@
@Override
public int hashCode() {
- return Objects.hash(mPreferredFeatures, mRequiredFeatures, mPackageOrder, mAllowedPackages,
+ return Objects.hash(mPreferredFeatures, mPackageOrder, mAllowedPackages,
mShouldPerformActiveScan);
}
@@ -241,7 +217,6 @@
*/
public static final class Builder {
List<String> mPreferredFeatures;
- List<String> mRequiredFeatures;
List<String> mPackageOrder;
List<String> mAllowedPackages;
@@ -253,7 +228,6 @@
Objects.requireNonNull(preferredFeatures, "preferredFeatures must not be null");
mPreferredFeatures = preferredFeatures.stream().filter(str -> !TextUtils.isEmpty(str))
.collect(Collectors.toList());
- mRequiredFeatures = List.of();
mPackageOrder = List.of();
mAllowedPackages = List.of();
mActiveScan = activeScan;
@@ -263,7 +237,6 @@
Objects.requireNonNull(preference, "preference must not be null");
mPreferredFeatures = preference.getPreferredFeatures();
- mRequiredFeatures = preference.getRequiredFeatures();
mPackageOrder = preference.getDeduplicationPackageOrder();
mAllowedPackages = preference.getAllowedPackages();
mActiveScan = preference.shouldPerformActiveScan();
@@ -271,14 +244,8 @@
}
/**
- * A constructor to combine multiple preferences into a single preference. The combined
- * preference will discover a superset of the union of the routes discoverable by each of
- * the individual preferences.
- * <p>
- * When routes need to be discovered for multiple preferences, the combined preference can
- * be used to query route providers once and obtain all routes of interest. The obtained
- * routes can then be filtered for each of the individual preferences. This is typically
- * more efficient than querying route providers with each of the individual preferences.
+ * A constructor to combine multiple preferences into a single preference.
+ * It ignores extras of preferences.
*
* @hide
*/
@@ -286,15 +253,21 @@
Objects.requireNonNull(preferences, "preferences must not be null");
Set<String> preferredFeatures = new HashSet<>();
+ Set<String> allowedPackages = new HashSet<>();
+ mPackageOrder = List.of();
boolean activeScan = false;
for (RouteDiscoveryPreference preference : preferences) {
preferredFeatures.addAll(preference.mPreferredFeatures);
+
+ allowedPackages.addAll(preference.mAllowedPackages);
activeScan |= preference.mShouldPerformActiveScan;
+ // Choose one of either
+ if (mPackageOrder.isEmpty() && !preference.mPackageOrder.isEmpty()) {
+ mPackageOrder = List.copyOf(preference.mPackageOrder);
+ }
}
- mPreferredFeatures = new ArrayList<>(preferredFeatures);
- mRequiredFeatures = List.of();
- mPackageOrder = List.of();
- mAllowedPackages = List.of();
+ mPreferredFeatures = List.copyOf(preferredFeatures);
+ mAllowedPackages = List.copyOf(allowedPackages);
mActiveScan = activeScan;
}
@@ -316,17 +289,6 @@
}
/**
- * Sets the required route features to discover.
- */
- @NonNull
- public Builder setRequiredFeatures(@NonNull List<String> requiredFeatures) {
- Objects.requireNonNull(requiredFeatures, "preferredFeatures must not be null");
- mRequiredFeatures = requiredFeatures.stream().filter(str -> !TextUtils.isEmpty(str))
- .collect(Collectors.toList());
- return this;
- }
-
- /**
* Sets the list of package names of providers that media router would like to discover.
* <p>
* If it's non-empty, media router only discovers route from the provider in the list.
diff --git a/media/java/android/media/Spatializer.java b/media/java/android/media/Spatializer.java
index 030d212..be0ef37 100644
--- a/media/java/android/media/Spatializer.java
+++ b/media/java/android/media/Spatializer.java
@@ -108,6 +108,83 @@
}
}
+ /**
+ * @hide
+ * Returns whether spatialization is available for a given audio device
+ * Reasons for spatialization being unavailable include situations where audio output is
+ * incompatible with sound spatialization, such as the device being a monophonic speaker, or
+ * the spatializer effect not supporting transaural processing when querying for speaker.
+ * @param device the audio device for which spatializer availability is queried
+ * @return {@code true} if the spatializer effect is available and capable
+ * of processing the audio over the given audio device,
+ * {@code false} otherwise.
+ * @see #isEnabled()
+ */
+ @SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
+ @RequiresPermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS)
+ public boolean isAvailableForDevice(@NonNull AudioDeviceAttributes device) {
+ Objects.requireNonNull(device);
+ try {
+ return mAm.getService().isSpatializerAvailableForDevice(device);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return false;
+ }
+
+ /**
+ * @hide
+ * Returns whether the given device has an associated headtracker
+ * @param device the audio device to query
+ * @return true if the device has a head tracker, false otherwise
+ */
+ @SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
+ @RequiresPermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS)
+ public boolean hasHeadTracker(@NonNull AudioDeviceAttributes device) {
+ Objects.requireNonNull(device);
+ try {
+ return mAm.getService().hasHeadTracker(device);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return false;
+ }
+
+ /**
+ * @hide
+ * Enables or disables the head tracker of the given device
+ * @param enabled true to enable, false to disable
+ * @param device the device whose head tracker state is changed
+ */
+ @SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
+ @RequiresPermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS)
+ public void setHeadTrackerEnabled(boolean enabled, @NonNull AudioDeviceAttributes device) {
+ Objects.requireNonNull(device);
+ try {
+ mAm.getService().setHeadTrackerEnabled(enabled, device);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ * Returns whether the head tracker of the device is enabled
+ * @param device the device to query
+ * @return true if the head tracker is enabled, false if disabled or if there isn't one
+ */
+ @SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
+ @RequiresPermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS)
+ public boolean isHeadTrackerEnabled(@NonNull AudioDeviceAttributes device) {
+ Objects.requireNonNull(device);
+ try {
+ return mAm.getService().isHeadTrackerEnabled(device);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return false;
+ }
+
/** @hide */
@IntDef(flag = false, value = {
SPATIALIZER_IMMERSIVE_LEVEL_OTHER,
diff --git a/media/java/android/media/metrics/BundleSession.java b/media/java/android/media/metrics/BundleSession.java
new file mode 100644
index 0000000..743d233
--- /dev/null
+++ b/media/java/android/media/metrics/BundleSession.java
@@ -0,0 +1,72 @@
+/*
+ * 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.media.metrics;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.PersistableBundle;
+
+import com.android.internal.util.AnnotationValidations;
+
+import java.util.Objects;
+
+/**
+ * An instances of this class represents a session with data stored in a bundle.
+ */
+public final class BundleSession implements AutoCloseable {
+ private final @NonNull String mId;
+ private final @NonNull MediaMetricsManager mManager;
+ private final @NonNull LogSessionId mLogSessionId;
+
+ /** @hide */
+ public BundleSession(@NonNull String id, @NonNull MediaMetricsManager manager) {
+ mId = id;
+ mManager = manager;
+ AnnotationValidations.validate(NonNull.class, null, mId);
+ AnnotationValidations.validate(NonNull.class, null, mManager);
+ mLogSessionId = new LogSessionId(mId);
+ }
+
+ /**
+ * Reports metrics via bundle.
+ *
+ */
+ public void reportBundleMetrics(@NonNull PersistableBundle metrics) {
+ mManager.reportBundleMetrics(mId, metrics);
+ }
+
+ public @NonNull LogSessionId getSessionId() {
+ return mLogSessionId;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ BundleSession that = (BundleSession) o;
+ return Objects.equals(mId, that.mId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mId);
+ }
+
+ @Override
+ public void close() {
+ }
+}
diff --git a/media/java/android/media/metrics/EditingSession.java b/media/java/android/media/metrics/EditingSession.java
new file mode 100644
index 0000000..2a48a72
--- /dev/null
+++ b/media/java/android/media/metrics/EditingSession.java
@@ -0,0 +1,63 @@
+/*
+ * 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.media.metrics;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.util.AnnotationValidations;
+
+import java.util.Objects;
+
+/**
+ * An instances of this class represents a session of media editing.
+ */
+public final class EditingSession implements AutoCloseable {
+ private final @NonNull String mId;
+ private final @NonNull MediaMetricsManager mManager;
+ private final @NonNull LogSessionId mLogSessionId;
+
+ /** @hide */
+ public EditingSession(@NonNull String id, @NonNull MediaMetricsManager manager) {
+ mId = id;
+ mManager = manager;
+ AnnotationValidations.validate(NonNull.class, null, mId);
+ AnnotationValidations.validate(NonNull.class, null, mManager);
+ mLogSessionId = new LogSessionId(mId);
+ }
+
+ public @NonNull LogSessionId getSessionId() {
+ return mLogSessionId;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ EditingSession that = (EditingSession) o;
+ return Objects.equals(mId, that.mId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mId);
+ }
+
+ @Override
+ public void close() {
+ }
+}
diff --git a/media/java/android/media/metrics/IMediaMetricsManager.aidl b/media/java/android/media/metrics/IMediaMetricsManager.aidl
index f2c0d44..a774403 100644
--- a/media/java/android/media/metrics/IMediaMetricsManager.aidl
+++ b/media/java/android/media/metrics/IMediaMetricsManager.aidl
@@ -21,6 +21,7 @@
import android.media.metrics.PlaybackMetrics;
import android.media.metrics.PlaybackStateEvent;
import android.media.metrics.TrackChangeEvent;
+import android.os.PersistableBundle;
/**
* Interface to the playback manager service.
@@ -28,10 +29,16 @@
*/
interface IMediaMetricsManager {
void reportPlaybackMetrics(in String sessionId, in PlaybackMetrics metrics, int userId);
+
String getPlaybackSessionId(int userId);
String getRecordingSessionId(int userId);
void reportNetworkEvent(in String sessionId, in NetworkEvent event, int userId);
void reportPlaybackErrorEvent(in String sessionId, in PlaybackErrorEvent event, int userId);
void reportPlaybackStateEvent(in String sessionId, in PlaybackStateEvent event, int userId);
void reportTrackChangeEvent(in String sessionId, in TrackChangeEvent event, int userId);
-}
\ No newline at end of file
+
+ String getTranscodingSessionId(int userId);
+ String getEditingSessionId(int userId);
+ String getBundleSessionId(int userId);
+ void reportBundleMetrics(in String sessionId, in PersistableBundle metrics, int userId);
+}
diff --git a/media/java/android/media/metrics/MediaMetricsManager.java b/media/java/android/media/metrics/MediaMetricsManager.java
index 23b697f..7229c47 100644
--- a/media/java/android/media/metrics/MediaMetricsManager.java
+++ b/media/java/android/media/metrics/MediaMetricsManager.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.SystemService;
import android.content.Context;
+import android.os.PersistableBundle;
import android.os.RemoteException;
/**
@@ -53,6 +54,17 @@
}
}
/**
+ * Reports bundle metrics.
+ * @hide
+ */
+ public void reportBundleMetrics(@NonNull String sessionId, PersistableBundle metrics) {
+ try {
+ mService.reportBundleMetrics(sessionId, metrics, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ /**
* Reports network event.
* @hide
*/
@@ -117,6 +129,48 @@
}
/**
+ * Creates a transcoding session.
+ */
+ @NonNull
+ public TranscodingSession createTranscodingSession() {
+ try {
+ String id = mService.getTranscodingSessionId(mUserId);
+ TranscodingSession session = new TranscodingSession(id, this);
+ return session;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Creates a editing session.
+ */
+ @NonNull
+ public EditingSession createEditingSession() {
+ try {
+ String id = mService.getEditingSessionId(mUserId);
+ EditingSession session = new EditingSession(id, this);
+ return session;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Creates a generic bundle session.
+ */
+ @NonNull
+ public BundleSession createBundleSession() {
+ try {
+ String id = mService.getBundleSessionId(mUserId);
+ BundleSession session = new BundleSession(id, this);
+ return session;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Reports error event.
* @hide
*/
diff --git a/media/java/android/media/metrics/TranscodingSession.java b/media/java/android/media/metrics/TranscodingSession.java
new file mode 100644
index 0000000..e6d359a
--- /dev/null
+++ b/media/java/android/media/metrics/TranscodingSession.java
@@ -0,0 +1,63 @@
+/*
+ * 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.media.metrics;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.util.AnnotationValidations;
+
+import java.util.Objects;
+
+/**
+ * An instances of this class represents a session of media Transcoding.
+ */
+public final class TranscodingSession implements AutoCloseable {
+ private final @NonNull String mId;
+ private final @NonNull MediaMetricsManager mManager;
+ private final @NonNull LogSessionId mLogSessionId;
+
+ /** @hide */
+ public TranscodingSession(@NonNull String id, @NonNull MediaMetricsManager manager) {
+ mId = id;
+ mManager = manager;
+ AnnotationValidations.validate(NonNull.class, null, mId);
+ AnnotationValidations.validate(NonNull.class, null, mManager);
+ mLogSessionId = new LogSessionId(mId);
+ }
+
+ public @NonNull LogSessionId getSessionId() {
+ return mLogSessionId;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ TranscodingSession that = (TranscodingSession) o;
+ return Objects.equals(mId, that.mId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mId);
+ }
+
+ @Override
+ public void close() {
+ }
+}
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 955ae3c..37050df 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -407,7 +407,7 @@
/**
* 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/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 73e96a2..96809bd 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -1877,6 +1877,7 @@
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.TUNER_RESOURCE_ACCESS)
public int getClientPriority(@TvInputService.PriorityHintUseCaseType int useCase,
@Nullable String sessionId) {
return getClientPriorityInternal(useCase, sessionId);
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 4d6739e..31e1817 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -623,7 +623,7 @@
Image_setBufferItem(env, image, buffer);
env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp,
static_cast<jlong>(buffer->mTimestamp));
- env->SetLongField(image, gSurfaceImageClassInfo.mDataSpace,
+ env->SetIntField(image, gSurfaceImageClassInfo.mDataSpace,
static_cast<jint>(buffer->mDataSpace));
auto transform = buffer->mTransform;
if (buffer->mTransformToDisplayInverse) {
diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp
index 0f88afb..6c6fccb 100644
--- a/media/jni/android_media_ImageWriter.cpp
+++ b/media/jni/android_media_ImageWriter.cpp
@@ -901,7 +901,7 @@
env->SetIntField(thiz, gSurfaceImageClassInfo.mNativeFenceFd, reinterpret_cast<jint>(fenceFd));
- env->SetLongField(thiz, gSurfaceImageClassInfo.mDataSpace, dataSpace);
+ env->SetIntField(thiz, gSurfaceImageClassInfo.mDataSpace, dataSpace);
}
static void Image_unlockIfLocked(JNIEnv* env, jobject thiz) {
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index f694482..c8d2d1e 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -202,7 +202,7 @@
JMediaCodec::JMediaCodec(
JNIEnv *env, jobject thiz,
- const char *name, bool nameIsType, bool encoder)
+ const char *name, bool nameIsType, bool encoder, int pid, int uid)
: mClass(NULL),
mObject(NULL) {
jclass clazz = env->GetObjectClass(thiz);
@@ -220,12 +220,12 @@
ANDROID_PRIORITY_VIDEO);
if (nameIsType) {
- mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus);
+ mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus, pid, uid);
if (mCodec == nullptr || mCodec->getName(&mNameAtCreation) != OK) {
mNameAtCreation = "(null)";
}
} else {
- mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus);
+ mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus, pid, uid);
mNameAtCreation = name;
}
CHECK((mCodec != NULL) != (mInitStatus != OK));
@@ -3136,7 +3136,7 @@
static void android_media_MediaCodec_native_setup(
JNIEnv *env, jobject thiz,
- jstring name, jboolean nameIsType, jboolean encoder) {
+ jstring name, jboolean nameIsType, jboolean encoder, int pid, int uid) {
if (name == NULL) {
jniThrowException(env, "java/lang/NullPointerException", NULL);
return;
@@ -3148,24 +3148,33 @@
return;
}
- sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder);
+ sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder, pid, uid);
const status_t err = codec->initCheck();
if (err == NAME_NOT_FOUND) {
// fail and do not try again.
jniThrowException(env, "java/lang/IllegalArgumentException",
- String8::format("Failed to initialize %s, error %#x", tmp, err));
+ String8::format("Failed to initialize %s, error %#x (NAME_NOT_FOUND)", tmp, err));
env->ReleaseStringUTFChars(name, tmp);
return;
- } if (err == NO_MEMORY) {
+ }
+ if (err == NO_MEMORY) {
throwCodecException(env, err, ACTION_CODE_TRANSIENT,
- String8::format("Failed to initialize %s, error %#x", tmp, err));
+ String8::format("Failed to initialize %s, error %#x (NO_MEMORY)", tmp, err));
env->ReleaseStringUTFChars(name, tmp);
return;
- } else if (err != OK) {
+ }
+ if (err == PERMISSION_DENIED) {
+ jniThrowException(env, "java/lang/SecurityException",
+ String8::format("Failed to initialize %s, error %#x (PERMISSION_DENIED)", tmp,
+ err));
+ env->ReleaseStringUTFChars(name, tmp);
+ return;
+ }
+ if (err != OK) {
// believed possible to try again
jniThrowException(env, "java/io/IOException",
- String8::format("Failed to find matching codec %s, error %#x", tmp, err));
+ String8::format("Failed to find matching codec %s, error %#x (?)", tmp, err));
env->ReleaseStringUTFChars(name, tmp);
return;
}
@@ -3174,7 +3183,7 @@
codec->registerSelf();
- setMediaCodec(env,thiz, codec);
+ setMediaCodec(env, thiz, codec);
}
static void android_media_MediaCodec_native_finalize(
@@ -3478,7 +3487,7 @@
{ "native_init", "()V", (void *)android_media_MediaCodec_native_init },
- { "native_setup", "(Ljava/lang/String;ZZ)V",
+ { "native_setup", "(Ljava/lang/String;ZZII)V",
(void *)android_media_MediaCodec_native_setup },
{ "native_finalize", "()V",
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index ee456c9..616c31b 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -55,7 +55,7 @@
struct JMediaCodec : public AHandler {
JMediaCodec(
JNIEnv *env, jobject thiz,
- const char *name, bool nameIsType, bool encoder);
+ const char *name, bool nameIsType, bool encoder, int pid, int uid);
status_t initCheck() const;
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
index d7e9ae9..b4aad9d 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
@@ -71,6 +71,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
@@ -276,6 +277,42 @@
assertNotNull(routes.get(ROUTE_ID_SPECIAL_FEATURE));
}
+ @Test
+ public void testNoAllowedPackages_returnsZeroRoutes() throws Exception {
+ RouteDiscoveryPreference preference =
+ new RouteDiscoveryPreference.Builder(FEATURES_ALL, true)
+ .setAllowedPackages(List.of("random package name"))
+ .build();
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(preference);
+
+ int remoteRouteCount = 0;
+ for (MediaRoute2Info route : routes.values()) {
+ if (!route.isSystemRoute()) {
+ remoteRouteCount++;
+ }
+ }
+
+ assertEquals(0, remoteRouteCount);
+ }
+
+ @Test
+ public void testAllowedPackages() throws Exception {
+ RouteDiscoveryPreference preference =
+ new RouteDiscoveryPreference.Builder(FEATURES_ALL, true)
+ .setAllowedPackages(List.of("com.android.mediaroutertest"))
+ .build();
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(preference);
+
+ int remoteRouteCount = 0;
+ for (MediaRoute2Info route : routes.values()) {
+ if (!route.isSystemRoute()) {
+ remoteRouteCount++;
+ }
+ }
+
+ assertTrue(remoteRouteCount > 0);
+ }
+
/**
* Tests if MR2.SessionCallback.onSessionCreated is called
* when a route is selected from MR2Manager.
@@ -818,8 +855,14 @@
Map<String, MediaRoute2Info> waitAndGetRoutesWithManager(List<String> routeFeatures)
throws Exception {
+ return waitAndGetRoutesWithManager(
+ new RouteDiscoveryPreference.Builder(routeFeatures, true).build());
+ }
+
+ Map<String, MediaRoute2Info> waitAndGetRoutesWithManager(RouteDiscoveryPreference preference)
+ throws Exception {
CountDownLatch addedLatch = new CountDownLatch(1);
- CountDownLatch featuresLatch = new CountDownLatch(1);
+ CountDownLatch preferenceLatch = new CountDownLatch(1);
// A dummy callback is required to send route feature info.
RouteCallback routeCallback = new RouteCallback() {};
@@ -828,7 +871,8 @@
public void onRoutesAdded(List<MediaRoute2Info> routes) {
for (MediaRoute2Info route : routes) {
if (!route.isSystemRoute()
- && hasMatchingFeature(route.getFeatures(), routeFeatures)) {
+ && hasMatchingFeature(route.getFeatures(), preference
+ .getPreferredFeatures())) {
addedLatch.countDown();
break;
}
@@ -836,20 +880,19 @@
}
@Override
- public void onPreferredFeaturesChanged(String packageName,
- List<String> preferredFeatures) {
+ public void onDiscoveryPreferenceChanged(String packageName,
+ RouteDiscoveryPreference discoveryPreference) {
if (TextUtils.equals(mPackageName, packageName)
- && preferredFeatures.size() == routeFeatures.size()
- && preferredFeatures.containsAll(routeFeatures)) {
- featuresLatch.countDown();
+ && Objects.equals(preference, discoveryPreference)) {
+ preferenceLatch.countDown();
}
}
};
mManager.registerCallback(mExecutor, managerCallback);
- mRouter2.registerRouteCallback(mExecutor, routeCallback,
- new RouteDiscoveryPreference.Builder(routeFeatures, true).build());
+ mRouter2.registerRouteCallback(mExecutor, routeCallback, preference);
+
try {
- featuresLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS);
+ preferenceLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS);
if (mManager.getAvailableRoutes(mPackageName).isEmpty()) {
addedLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS);
}
diff --git a/native/android/OWNERS b/native/android/OWNERS
index 02dfd39..cfe9734 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 = codewiz@google.com, 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 b7beb6e..3009a36 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -205,6 +205,7 @@
ASensorManager_destroyEventQueue;
ASensorManager_getDefaultSensor;
ASensorManager_getDefaultSensorEx; # introduced=21
+ ASensorManager_getDynamicSensorList; # introduced=33
ASensorManager_getInstance;
ASensorManager_getInstanceForPackage; # introduced=26
ASensorManager_getSensorList;
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
index 63082fd..968de34 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -83,6 +83,16 @@
return c;
}
+ssize_t ASensorManager_getDynamicSensorList(ASensorManager* manager, ASensorList* list) {
+ RETURN_IF_MANAGER_IS_NULL(android::BAD_VALUE);
+ Sensor const* const* l;
+ ssize_t c = static_cast<SensorManager*>(manager)->getDynamicSensorList(&l);
+ if (list) {
+ *list = reinterpret_cast<ASensorList>(l);
+ }
+ return c;
+}
+
ASensor const* ASensorManager_getDefaultSensor(ASensorManager* manager, int type) {
RETURN_IF_MANAGER_IS_NULL(nullptr);
return static_cast<SensorManager*>(manager)->getDefaultSensor(type);
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
index d01a30e..6eff629 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -141,7 +141,7 @@
}
struct ASurfaceControlStats {
- int64_t acquireTime;
+ std::variant<int64_t, sp<Fence>> acquireTimeOrFence;
sp<Fence> previousReleaseFence;
uint64_t frameNumber;
};
@@ -153,7 +153,7 @@
const SurfaceStats& surfaceStats) {
ASurfaceControlStats aSurfaceControlStats;
- aSurfaceControlStats.acquireTime = surfaceStats.acquireTime;
+ aSurfaceControlStats.acquireTimeOrFence = surfaceStats.acquireTimeOrFence;
aSurfaceControlStats.previousReleaseFence = surfaceStats.previousReleaseFence;
aSurfaceControlStats.frameNumber = surfaceStats.eventStats.frameNumber;
@@ -171,7 +171,15 @@
}
int64_t ASurfaceControlStats_getAcquireTime(ASurfaceControlStats* stats) {
- return stats->acquireTime;
+ if (const auto* fence = std::get_if<sp<Fence>>(&stats->acquireTimeOrFence)) {
+ // We got a fence instead of the acquire time due to latch unsignaled.
+ // Ideally the client could just get the acquire time dericly from
+ // the fence instead of calling this function which needs to block.
+ (*fence)->waitForever("ASurfaceControlStats_getAcquireTime");
+ return (*fence)->getSignalTime();
+ }
+
+ return std::get<int64_t>(stats->acquireTimeOrFence);
}
uint64_t ASurfaceControlStats_getFrameNumber(ASurfaceControlStats* stats) {
@@ -250,7 +258,7 @@
aSurfaceControlStats == aSurfaceTransactionStats->aSurfaceControlStats.end(),
"ASurfaceControl not found");
- return aSurfaceControlStats->second.acquireTime;
+ return ASurfaceControlStats_getAcquireTime(&aSurfaceControlStats->second);
}
int ASurfaceTransactionStats_getPreviousReleaseFenceFd(
@@ -294,9 +302,10 @@
auto& aSurfaceControlStats = aSurfaceTransactionStats.aSurfaceControlStats;
- for (const auto& [surfaceControl, latchTime, acquireTime, presentFence, previousReleaseFence, transformHint, frameEvents] : surfaceControlStats) {
+ for (const auto& [surfaceControl, latchTime, acquireTimeOrFence, presentFence,
+ previousReleaseFence, transformHint, frameEvents] : surfaceControlStats) {
ASurfaceControl* aSurfaceControl = reinterpret_cast<ASurfaceControl*>(surfaceControl.get());
- aSurfaceControlStats[aSurfaceControl].acquireTime = acquireTime;
+ aSurfaceControlStats[aSurfaceControl].acquireTimeOrFence = acquireTimeOrFence;
aSurfaceControlStats[aSurfaceControl].previousReleaseFence = previousReleaseFence;
}
@@ -643,13 +652,12 @@
aSurfaceTransactionStats.transactionCompleted = false;
auto& aSurfaceControlStats = aSurfaceTransactionStats.aSurfaceControlStats;
- for (const auto&
- [surfaceControl, latchTime, acquireTime, presentFence,
- previousReleaseFence, transformHint,
- frameEvents] : surfaceControlStats) {
+ for (const auto& [surfaceControl, latchTime, acquireTimeOrFence, presentFence,
+ previousReleaseFence, transformHint, frameEvents] :
+ surfaceControlStats) {
ASurfaceControl* aSurfaceControl =
reinterpret_cast<ASurfaceControl*>(surfaceControl.get());
- aSurfaceControlStats[aSurfaceControl].acquireTime = acquireTime;
+ aSurfaceControlStats[aSurfaceControl].acquireTimeOrFence = acquireTimeOrFence;
}
(*func)(callback_context, &aSurfaceTransactionStats);
diff --git a/omapi/aidl/vts/functional/config/Android.bp b/omapi/aidl/vts/functional/config/Android.bp
new file mode 100644
index 0000000..7c08257
--- /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 0000000..ffeb7a0
--- /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 0000000..c2e930b
--- /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 0000000..e69de29
--- /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 0000000..e69de29
--- /dev/null
+++ b/omapi/aidl/vts/functional/config/schema/last_removed.txt
diff --git a/omapi/aidl/vts/functional/config/schema/removed.txt b/omapi/aidl/vts/functional/config/schema/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/omapi/aidl/vts/functional/config/schema/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/omapi/aidl/vts/functional/omapi/Android.bp b/omapi/aidl/vts/functional/omapi/Android.bp
index c3ab8d1..c41479f 100644
--- a/omapi/aidl/vts/functional/omapi/Android.bp
+++ b/omapi/aidl/vts/functional/omapi/Android.bp
@@ -39,6 +39,11 @@
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 @@
"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 319cb7e..5303651 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 @@
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 @@
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, 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 0000000..3ee0414
--- /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/src/android/app/usage/NetworkStatsManager.java b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
index 0414bb7..ca080ce 100644
--- a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
@@ -699,7 +699,9 @@
* @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);
@@ -723,7 +725,9 @@
* @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);
@@ -740,8 +744,9 @@
* {@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.
@@ -750,6 +755,9 @@
* @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/EthernetManager.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
index 1f67f6d..1a955c4 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
@@ -16,14 +16,16 @@
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;
@@ -33,13 +35,15 @@
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
*/
@@ -54,11 +58,13 @@
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));
}
}
}
@@ -68,19 +74,93 @@
@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;
}
}
/**
- * A listener interface to receive notification on changes in Ethernet.
+ * The interface is absent.
* @hide
*/
- public interface Listener {
+ @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 the 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 extends InterfaceStateListener {
/**
* Called when Ethernet port's availability is changed.
* @param iface Ethernet interface name
@@ -89,6 +169,13 @@
*/
@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));
+ }
+
}
/**
@@ -121,7 +208,7 @@
* @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) {
@@ -155,9 +242,8 @@
/**
* 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
@@ -169,6 +255,8 @@
/**
* 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.
@@ -176,6 +264,28 @@
*/
@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");
}
@@ -206,15 +316,13 @@
/**
* 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()) {
@@ -228,12 +336,26 @@
}
/**
+ * 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);
diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkSpecifier.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkSpecifier.java
index 925d12b..e4d6e24 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 @@
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 @@
* 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 @@
return mInterfaceName;
}
+ /** @hide */
@Override
public boolean canBeSatisfiedBy(@Nullable NetworkSpecifier other) {
return equals(other);
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl b/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl
index 782fa19..6d2ba03 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/IpSecManager.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java
index a423783..9cb0947 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 @@
* 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 4ebaf2b..a48f94b 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.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 @@
final int mType;
final int mRatType;
+ final int mSubId;
final String mSubscriberId;
final String mWifiNetworkKey;
final boolean mRoaming;
@@ -96,7 +98,7 @@
/** @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 @@
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 @@
&& 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 @@
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();
}
@@ -256,6 +261,11 @@
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 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 @@
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 @@
private boolean mMetered;
private boolean mDefaultNetwork;
private int mOemManaged;
+ private int mSubId;
/**
* Creates a new Builder.
@@ -359,6 +374,7 @@
mMetered = false;
mDefaultNetwork = false;
mOemManaged = NetworkTemplate.OEM_MANAGED_NO;
+ mSubId = INVALID_SUBSCRIPTION_ID;
}
/**
@@ -537,6 +553,19 @@
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 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 2236d70..56461ba 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 @@
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 @@
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 @@
* @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 @@
out.writeBoolean(ident.isMetered());
out.writeBoolean(ident.isDefaultNetwork());
out.writeInt(ident.getOemManaged());
+ out.writeInt(ident.getSubId());
}
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.java
index d577aa8..c018e91 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 @@
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/service/src/com/android/server/net/InterfaceMapValue.java b/packages/ConnectivityT/service/src/com/android/server/net/InterfaceMapValue.java
index 061f323..42c0044 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/NetworkStatsObservers.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsObservers.java
index 1953624..fdfc893 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 @@
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 @@
*
* @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 @@
}
}
- 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/NetworkStatsService.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
index 7a5ba09..e8b3d4c 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
@@ -1067,7 +1067,7 @@
@Override
public NetworkStats getUidStatsForTransport(int transport) {
- enforceAnyPermissionOf(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
try {
final String[] relevantIfaces =
transport == TRANSPORT_WIFI ? mWifiIfaces : mMobileIfaces;
@@ -1229,7 +1229,7 @@
DataUsageRequest normalizedRequest;
final long token = Binder.clearCallingIdentity();
try {
- normalizedRequest = mStatsObservers.register(
+ normalizedRequest = mStatsObservers.register(mContext,
request, callback, callingUid, accessLevel);
} finally {
Binder.restoreCallingIdentity(token);
@@ -1484,10 +1484,15 @@
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);
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ActivityTile.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ActivityTile.java
index b739ee6..98ea8b34 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ActivityTile.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ActivityTile.java
@@ -35,8 +35,7 @@
private static final String TAG = "ActivityTile";
public ActivityTile(ActivityInfo info, String category) {
- super(info, category);
- setMetaData(info.metaData);
+ super(info, category, info.metaData);
}
ActivityTile(Parcel in) {
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ProviderTile.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ProviderTile.java
index 312d30e..54da585 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ProviderTile.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ProviderTile.java
@@ -43,8 +43,7 @@
private String mKey;
public ProviderTile(ProviderInfo info, String category, Bundle metaData) {
- super(info, category);
- setMetaData(metaData);
+ super(info, category, metaData);
mAuthority = info.authority;
mKey = metaData.getString(META_DATA_PREFERENCE_KEYHINT);
}
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java
index 220cf6b..a0c8ac4 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java
@@ -71,16 +71,19 @@
private Bundle mMetaData;
private String mCategory;
- public Tile(ComponentInfo info, String category) {
+ public Tile(ComponentInfo info, String category, Bundle metaData) {
mComponentInfo = info;
mComponentPackage = mComponentInfo.packageName;
mComponentName = mComponentInfo.name;
mCategory = category;
+ mMetaData = metaData;
mIntent = new Intent().setClassName(mComponentPackage, mComponentName);
+ if (isNewTask()) {
+ mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ }
}
Tile(Parcel in) {
- final boolean isProviderTile = in.readBoolean();
mComponentPackage = in.readString();
mComponentName = in.readString();
mIntent = new Intent().setClassName(mComponentPackage, mComponentName);
@@ -90,6 +93,9 @@
}
mCategory = in.readString();
mMetaData = in.readBundle();
+ if (isNewTask()) {
+ mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ }
}
@Override
@@ -332,8 +338,7 @@
/**
* Whether the {@link Activity} should be launched in a separate task.
*/
- public boolean isNewTask(Context context) {
- ensureMetadataNotStale(context);
+ public boolean isNewTask() {
if (mMetaData != null
&& mMetaData.containsKey(META_DATA_NEW_TASK)) {
return mMetaData.getBoolean(META_DATA_NEW_TASK);
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 597815d..734cc5d 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -641,6 +641,5 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Luggehalte"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Uitsaai-inligting"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Kies \'n profielprent"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Verstekgebruikerikoon"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 7d3bece..bb4899e 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -641,6 +641,5 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"የአየር ጥራት"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"የCast መረጃ"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"የመገለጫ ሥዕል ይምረጡ"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"ነባሪ የተጠቃሚ አዶ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 6e406a7..f3df256 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"تم قطع اتصال Ethernet."</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"إيثرنت"</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"لا يتم الاتصال."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"الوقت"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"التاريخ"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"الطقس"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"جودة الهواء"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"معلومات البث"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"اختيار صورة الملف الشخصي"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"رمز المستخدم التلقائي"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index e7a3547..5499852 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ইথাৰনেট সংযোগ বিচ্ছিন্ন হৈছে।"</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"ইথাৰনেট।"</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"কল কৰা নহয়"</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"সময়"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"তাৰিখ"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"বতৰ"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"বায়ুৰ গুণগত মান"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"কাষ্টৰ তথ্য"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"এখন প্ৰ’ফাইল চিত্ৰ বাছনি কৰক"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"ডিফ’ল্ট ব্যৱহাৰকাৰীৰ চিহ্ন"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 226fc85..ee61930 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -641,6 +641,5 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Havanın keyfiyyəti"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Yayım məlumatı"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Profil şəkli seçin"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Defolt istifadəçi ikonası"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 85be8c3..f7834b7 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -641,6 +641,5 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Kvalitet vazduha"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Podaci o prebacivanju"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Odaberite sliku profila"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Podrazumevana ikona korisnika"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 94f107d..e63cddd 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet адлучаны."</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"Ethernet."</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"Ніякіх выклікаў."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"Час"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"Дата"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"Надвор\'е"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Якасць паветра"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Даныя пра трансляцыю"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Выберыце відарыс профілю"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Стандартны карыстальніцкі значок"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 408804f2..538f0f1 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Връзката с Ethernet е прекратена."</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"Ethernet."</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"Без обаждания."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"Час"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"Дата"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"Времето"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Качество на въздуха"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Предаване: Инф."</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Изберете снимка на потребителския профил"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Икона за основния потребител"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index ecfbbc3..9a9fabb 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ইথারনেটের সংযোগ বিচ্ছিন্ন হয়েছে৷"</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"ইথারনেট।"</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"কল করবেন না।"</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"সময়"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"তারিখ"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"আবহাওয়া"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"এয়ার কোয়ালিটি"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"কাস্ট সম্পর্কিত তথ্য"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"একটি প্রোফাইল ছবি বেছে নিন"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"ডিফল্ট ব্যবহারকারীর আইকন"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index f742859..ba5cc4e 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -641,6 +641,5 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Kvalitet zraka"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Podaci o emitiranju"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Odaberite sliku profila"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Zadana ikona korisnika"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 1b45287..30dfbe5 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -641,6 +641,5 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Qualitat de l\'aire"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Informació d\'emissió"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Tria una foto de perfil"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Icona d\'usuari predeterminat"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index b28bca5..0006a76 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Síť ethernet je odpojena."</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"Ethernet."</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"Bez volání."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"Čas"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"Datum"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"Počasí"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Kvalita vzduchu"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info o odesílání"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Vyberte profilový obrázek"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Výchozí uživatelská ikona"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 3c8a4aa..63e462a 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet er ikke tilsluttet."</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"Ethernet."</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"Opkald er deaktiveret."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"Klokkeslæt"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"Dato"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"Vejr"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Luftkvalitet"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Cast-oplysninger"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Vælg et profilbillede"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Ikon for standardbruger"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 4c76217..3ca2115 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Το Ethernet αποσυνδέθηκε."</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"Ethernet."</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"Χωρίς κλήσεις."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"Ώρα"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"Ημερομηνία"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"Καιρός"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Ποιότητα αέρα"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Πληροφορίες ηθοποιών"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Επιλογή φωτογραφίας προφίλ"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Προεπιλεγμένο εικονίδιο χρήστη"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 44d0904..63c56ba0 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet desconectada"</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"Ethernet."</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"Sin llamadas."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"Hora"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"Fecha"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"Clima"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Calidad del aire"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info de reparto"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Elige una foto de perfil"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Ícono de usuario predeterminado"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 646d45b..743e81c 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -246,7 +246,7 @@
<string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Empareja nuevos dispositivos con el escáner de códigos QR"</string>
<string name="adb_pair_method_code_title" msgid="1122590300445142904">"Emparejar dispositivo con código de sincronización"</string>
<string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Empareja nuevos dispositivos con un código de seis dígitos"</string>
- <string name="adb_paired_devices_title" msgid="5268997341526217362">"Dispositivos vinculados"</string>
+ <string name="adb_paired_devices_title" msgid="5268997341526217362">"Dispositivos emparejados"</string>
<string name="adb_wireless_device_connected_summary" msgid="3039660790249148713">"Conectados actualmente"</string>
<string name="adb_wireless_device_details_title" msgid="7129369670526565786">"Datos del dispositivo"</string>
<string name="adb_device_forget" msgid="193072400783068417">"Olvidar"</string>
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Conexión Ethernet desconectada."</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"Ethernet"</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"Sin llamadas."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"Hora"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"Fecha"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"Info. meteorológica"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Calidad del aire"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info. de emisión"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Elige una imagen de perfil"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Icono de usuario predeterminado"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 6b44437..63998f9 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Etherneti-ühendus on katkestatud."</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"Ethernet."</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"Helistamine pole võimalik."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"Kellaaeg"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"Kuupäev"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"Ilm"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Õhukvaliteet"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Osatäitjate teave"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Valige profiilipilt"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Vaikekasutajaikoon"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index ac38a13..4152219 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -641,6 +641,5 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"کیفیت هوا"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"اطلاعات ارسال محتوا"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"انتخاب عکس نمایه"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"نماد کاربر پیشفرض"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 47613d8..2b5b550 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet on irrotettu."</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"Ethernet"</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"Ei puheluita."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"Aika"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"Päivämäärä"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"Sää"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Ilmanlaatu"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Striimaustiedot"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Valitse profiilikuva"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Oletuskäyttäjäkuvake"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 40784fd..7ecaa38 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet déconnecté."</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"Ethernet."</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"Aucun appel."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"Heure"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"Date"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"Météo"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Qualité de l\'air"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info diffusion"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Choisir une photo de profil"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Icône d\'utilisateur par défaut"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index d8ca2b6..dbc398e 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet déconnecté"</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"Ethernet."</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"Pas d\'appels."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"Heure"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"Date"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"Météo"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Qualité de l\'air"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Infos distribution"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Choisissez une photo de profil"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Icône de l\'utilisateur par défaut"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 675bc9f..b211606 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -641,6 +641,5 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Calidade do aire"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Datos da emisión"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Escolle unha imaxe do perfil"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Icona do usuario predeterminado"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 0a8554e..203a298 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ઇથરનેટ ડિસ્કનેક્ટ થયું."</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"ઇથરનેટ."</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"કોઈ કૉલિંગ નહીં."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"સમય"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"તારીખ"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"હવામાન"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"હવાની ક્વૉલિટી"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"કાસ્ટ વિશેની માહિતી"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"પ્રોફાઇલ ફોટો પસંદ કરો"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"ડિફૉલ્ટ વપરાશકર્તાનું આઇકન"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 15d1218..d934b46 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -641,6 +641,5 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Kvaliteta zraka"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Inform. o emitiranju"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Odabir profilne slike"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Ikona zadanog korisnika"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index b9d1ed0..cd09a85 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -641,6 +641,5 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Levegőminőség"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Átküldési információ"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Profilkép választása"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Alapértelmezett felhasználó ikonja"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 4d0d39f..0a2c406 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet-ը անջատված է:"</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"Ethernet։"</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"Զանգել հնարավոր չէ։"</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"Ժամ"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"Ամսաթիվ"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"Եղանակ"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Օդի որակը"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Հեռարձակման տվյալներ"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Պրոֆիլի նկար ընտրեք"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Օգտատիրոջ կանխադրված պատկերակ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 7f76d40..12e0691 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet terputus."</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"Ethernet."</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"Tidak ada panggilan."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"Waktu"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"Tanggal"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"Cuaca"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Kualitas Udara"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info Transmisi"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Pilih foto profil"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Ikon pengguna default"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 3b551d0..bf7021e 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet aftengt."</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"Ethernet."</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"Engin símtöl."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"Tími"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"Dagsetning"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"Veður"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Loftgæði"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Útsendingaruppl."</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Veldu prófílmynd"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Tákn sjálfgefins notanda"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 2740710..5bccf24 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Connessione Ethernet annullata."</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"Ethernet."</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"Chiamate non disponibili."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"Ora"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"Data"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"Meteo"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Qualità dell\'aria"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info sul cast"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Scegli un\'immagine del profilo"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Icona dell\'utente predefinito"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 0599762..bc17f9e 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"אתרנט מנותק."</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"אתרנט."</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"אין שיחות."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"שעה"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"תאריך"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"מזג אוויר"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"איכות האוויר"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"פרטי ההעברה"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"בחירה של תמונת פרופיל"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"סמל המשתמש שמוגדר כברירת מחדל"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index d639381..aa274a5 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -641,6 +641,5 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"大気質"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"キャスト情報"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"プロフィール写真の選択"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"デフォルト ユーザー アイコン"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 14bdbf1..395c7f9 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -641,6 +641,5 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"ჰაერის ხარისხი"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ტრანსლირების ინფო"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"აირჩიეთ პროფილის სურათი"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"მომხმარებლის ნაგულისხმევი ხატულა"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 0f7bcde..74e0957 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -641,6 +641,5 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Ауа сапасы"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Трансляция ақпараты"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Профиль суретін таңдау"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Әдепкі пайдаланушы белгішесі"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 22f8d14..cf043e7 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -641,6 +641,5 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"គុណភាពខ្យល់"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ព័ត៌មានអំពីការបញ្ជូន"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"ជ្រើសរើសរូបភាពកម្រងព័ត៌មាន"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"រូបអ្នកប្រើប្រាស់លំនាំដើម"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 02ed98f..31bd310 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"이더넷에서 연결 해제되었습니다."</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"이더넷에 연결되었습니다."</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"통화 모드가 없습니다."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"시간"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"날짜"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"날씨"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"대기 상태"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"전송 정보"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"프로필 사진 선택하기"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"기본 사용자 아이콘"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 542f3ad..ad38373 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -641,6 +641,5 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Абанын сапаты"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Тышкы экранга чыгаруу маалыматы"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Профилдин сүрөтүн тандоо"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Демейки колдонуучунун сүрөтчөсү"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 5d9a478..725a135 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -641,6 +641,5 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"ຄຸນນະພາບອາກາດ"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ຂໍ້ມູນການສົ່ງສັນຍານ"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"ເລືອກຮູບໂປຣໄຟລ໌"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"ໄອຄອນຜູ້ໃຊ້ເລີ່ມຕົ້ນ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 5d6ad42..5d34208 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Atsijungta nuo eterneto."</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"Eternetas."</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"Nekviečiama."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"Laikas"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"Data"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"Orai"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Oro kokybė"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Perdav. informacija"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Pasirinkite profilio nuotrauką"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Numatytojo naudotojo piktograma"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 04490a8..ed4b8e6 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Pārtraukts savienojums ar tīklu Ethernet."</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"Tīkls Ethernet"</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"Zvanīšana nav pieejama."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"Laiks"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"Datums"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"Laikapstākļi"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Gaisa kvalitāte"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Apraides informācija"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Profila attēla izvēle"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Noklusējuma lietotāja ikona"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 2b9a413..663f355 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -641,6 +641,5 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Квалитет на воздух"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Инфо за улогите"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Изберете профилна слика"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Икона за стандарден корисник"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 9179083..7b1605a 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -641,6 +641,5 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Агаарын чанар"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Дамжуулах мэдээлэл"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Профайл зураг сонгох"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Өгөгдмөл хэрэглэгчийн дүрс тэмдэг"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 2f92d3f..8edf739 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -641,6 +641,5 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Kualiti Udara"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Maklumat Pelakon"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Pilih gambar profil"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Ikon pengguna lalai"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index ecb3b75..061760f 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet နှင့်ချိတ်ဆက်မှုပြတ်တောက်"</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"အီသာနက်။"</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"ခေါ်ဆိုမှု မရှိပါ။"</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"အချိန်"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"ရက်စွဲ"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"မိုးလေဝသ"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"လေထုအရည်အသွေး"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ကာစ် အချက်အလက်"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"ပရိုဖိုင်ပုံ ရွေးပါ"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"မူရင်းအသုံးပြုသူ သင်္ကေတ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 3f10e2a..f47fae3 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet er frakoblet."</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"Ethernet."</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"Ingen ringing."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"Klokkeslett"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"Dato"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"Vær"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Luftkvalitet"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Castinformasjon"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Velg et profilbilde"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Standard brukerikon"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index e30cd46..4eb4400 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernetverbinding verbroken."</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"Ethernet."</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"Geen gesprekken."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"Tijd"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"Datum"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"Weer"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Luchtkwaliteit"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Castinformatie"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Kies een profielfoto"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Standaard gebruikersicoon"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 8376c83..42b6038 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -641,6 +641,5 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"ବାୟୁର ଗୁଣବତ୍ତା"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"କାଷ୍ଟ ସୂଚନା"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"ଏକ ପ୍ରୋଫାଇଲ ଛବି ବାଛନ୍ତୁ"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"ଡିଫଲ୍ଟ ଉପଯୋଗକର୍ତ୍ତା ଆଇକନ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 4bf903b..a02cd5b 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ਈਥਰਨੈੱਟ ਡਿਸਕਨੈਕਟ ਹੋ ਗਿਆ।"</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"ਈਥਰਨੈੱਟ।"</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"ਕਾਲਿੰਗ ਸੇਵਾ ਉਪਲਬਧ ਨਹੀਂ ਹੈ।"</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"ਸਮਾਂ"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"ਤਾਰੀਖ"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"ਮੌਸਮ"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"ਹਵਾ ਦੀ ਕੁਆਲਿਟੀ"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ਕਾਸਟ ਸੰਬੰਧੀ ਜਾਣਕਾਰੀ"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"ਕੋਈ ਪ੍ਰੋਫਾਈਲ ਤਸਵੀਰ ਚੁਣੋ"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਵਰਤੋਂਕਾਰ ਪ੍ਰਤੀਕ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index b667bfb..f69ffb7 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Rozłączono z siecią Ethernet."</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"Ethernet."</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"Brak połączenia."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"Godzina"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"Data"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"Pogoda"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Jakość powietrza"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Obsada"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Wybierz zdjęcie profilowe"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Ikona domyślnego użytkownika"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 96145d5..d856b48 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -438,7 +438,7 @@
<string name="transcode_notification" msgid="5560515979793436168">"Mostrar notificações de transcodificação"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Desativar cache da transcodificação"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Serviços em execução"</string>
- <string name="runningservices_settings_summary" msgid="1046080643262665743">"Visualizar e controlar os serviços em execução no momento"</string>
+ <string name="runningservices_settings_summary" msgid="1046080643262665743">"Ver e controlar os serviços em execução no momento"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementação do WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Configurar implementação do WebView"</string>
<string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Esta opção não é mais válida. Tente novamente."</string>
@@ -641,6 +641,5 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Qualidade do ar"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info. de transmissão"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Escolher a foto do perfil"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Ícone de usuário padrão"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 96145d5..d856b48 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -438,7 +438,7 @@
<string name="transcode_notification" msgid="5560515979793436168">"Mostrar notificações de transcodificação"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Desativar cache da transcodificação"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Serviços em execução"</string>
- <string name="runningservices_settings_summary" msgid="1046080643262665743">"Visualizar e controlar os serviços em execução no momento"</string>
+ <string name="runningservices_settings_summary" msgid="1046080643262665743">"Ver e controlar os serviços em execução no momento"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementação do WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Configurar implementação do WebView"</string>
<string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Esta opção não é mais válida. Tente novamente."</string>
@@ -641,6 +641,5 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Qualidade do ar"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info. de transmissão"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Escolher a foto do perfil"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Ícone de usuário padrão"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index b04af7b..9fb13aa 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -641,6 +641,5 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Calitatea aerului"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Informații artiști"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Alegeți o fotografie de profil"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Pictograma prestabilită a utilizatorului"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 97a4717..b0b3d14 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Устройство отключено от Ethernet."</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"Ethernet."</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"Совершение вызовов невозможно."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"Время"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"Дата"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"Погода"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Качество воздуха"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Данные о трансляции"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Выберите фото профиля"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Значок пользователя по умолчанию"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 2dcabe1..a391e71 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ඊතර්නෙට් විසන්ධි කරන ලදී."</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"ඊතර්නෙට්."</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"ඇමතුම් නැත."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"වේලාව"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"දිනය"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"කාලගුණය"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"වායු ගුණත්වය"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"විකාශ තතු"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"පැතිකඩ පින්තූරයක් තේරීම"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"පෙරනිමි පරිශීලක නිරූපකය"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index d4a94fa..1d3320e 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Sieť ethernet je odpojená"</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"Ethernet."</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"Žiadne volanie."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"Čas"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"Dátum"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"Počasie"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Kvalita vzduchu"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Informácie o prenose"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Výber profilovej fotky"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Predvolená ikona používateľa"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 65829d4..d38ab74 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Lidhja e eternetit u shkëput."</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"Eternet."</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"Telefonatat nuk ofrohen"</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"Ora"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"Data"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"Moti"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Cilësia e ajrit"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Të dhënat e aktorëve"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Zgjidh një fotografi profili"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Ikona e parazgjedhur e përdoruesit"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index d0b69e5..03ee28c 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -641,6 +641,5 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Квалитет ваздуха"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Подаци о пребацивању"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Одаберите слику профила"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Подразумевана икона корисника"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 28653ef..1efae32 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet har kopplats från."</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"Ethernet."</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"Inga anrop."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"Tid"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"Datum"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"Väder"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Luftkvalitet"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info om rollistan"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Välj en profilbild"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Ikon för standardanvändare"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index d24d5e0..d8d5629 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethaneti imeondolewa."</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"Ethaneti."</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"Huwezi kupiga wala kupokea simu."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"Saa"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"Tarehe"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"Hali ya Hewa"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Ubora wa Hewa"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Maelezo ya Wahusika"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Chagua picha ya wasifu"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Aikoni chaguomsingi ya mtumiaji"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index eec1a55..4bc0728 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -641,6 +641,5 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"คุณภาพอากาศ"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ข้อมูลแคสต์"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"เลือกรูปโปรไฟล์"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"ไอคอนผู้ใช้เริ่มต้น"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index fe0f4a3b..5db99d9 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -641,6 +641,5 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Kalidad ng Hangin"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Impormasyon ng Cast"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Pumili ng larawan sa profile"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Icon ng default na user"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 8a0042f..68fd199 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet bağlantısı kesildi."</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"Ethernet."</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"Çağrı yok."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"Saat"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"Tarih"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"Hava durumu"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Hava Kalitesi"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Yayın Bilgisi"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Profil fotoğrafı seç"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Varsayılan kullanıcı simgesi"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 6fd7788..207e890 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet відключено."</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"Ethernet."</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"Виклики недоступні."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"Час"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"Дата"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"Погода"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Якість повітря"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Акторський склад"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Вибрати зображення профілю"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Значок користувача за умовчанням"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index f0449b4..3163277 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ایتھرنیٹ منقطع ہے۔"</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"ایتھرنیٹ۔"</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"کوئی کالنگ نہیں ہے۔"</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"وقت"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"تاریخ"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"موسم"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"ہوا کا معیار"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"کاسٹ کرنے کی معلومات"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"پروفائل کی تصویر منتخب کریں"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"ڈیفالٹ صارف کا آئیکن"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index c17415f..09dcdc0 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -641,6 +641,5 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Havo sifati"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Translatsiya axboroti"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Profil rasmini tanlash"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Foydalanuvchining standart belgisi"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 89e1325..12af588 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Đã ngắt kết nối Ethernet."</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"Ethernet."</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"Không thể gọi điện."</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"Giờ"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"Ngày"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"Thời tiết"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Chất lượng không khí"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Thông tin về dàn nghệ sĩ"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Chọn một ảnh hồ sơ"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Biểu tượng người dùng mặc định"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index e125680..f6912b1 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -641,6 +641,5 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"空气质量"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"投射信息"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"选择个人资料照片"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"默认用户图标"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 6278fdc..2580cde 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -635,17 +635,11 @@
<string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"未連上乙太網路。"</string>
<string name="accessibility_ethernet_connected" msgid="6175942685957461563">"乙太網路。"</string>
<string name="accessibility_no_calling" msgid="3540827068323895748">"不顯示在螢幕上。"</string>
- <!-- no translation found for dream_complication_title_time (701747800712893499) -->
- <skip />
- <!-- no translation found for dream_complication_title_date (8661176085446135789) -->
- <skip />
- <!-- no translation found for dream_complication_title_weather (598609151677172783) -->
- <skip />
- <!-- no translation found for dream_complication_title_aqi (4587552608957834110) -->
- <skip />
- <!-- no translation found for dream_complication_title_cast_info (4038776652841885084) -->
- <skip />
+ <string name="dream_complication_title_time" msgid="701747800712893499">"時間"</string>
+ <string name="dream_complication_title_date" msgid="8661176085446135789">"日期"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"天氣"</string>
+ <string name="dream_complication_title_aqi" msgid="4587552608957834110">"空氣品質"</string>
+ <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"演出者資訊"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"選擇個人資料相片"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"預設使用者圖示"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 29a431d..5250aa5 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -641,6 +641,5 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Ikhwalithi Yomoya"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Ulwazi Lokusakaza"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Khetha isithombe sephrofayela"</string>
- <!-- no translation found for default_user_icon_description (6554047177298972638) -->
- <skip />
+ <string name="default_user_icon_description" msgid="6554047177298972638">"Isithonjana somsebenzisi sokuzenzakalelayo"</string>
</resources>
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index e1bd9f7..25d6c55 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -110,4 +110,10 @@
<dimen name="avatar_picker_icon_inset">25dp</dimen>
+ <!-- Minimum increment between density scales. -->
+ <fraction name="display_density_min_scale_interval">9%</fraction>
+ <!-- Maximum density scale. The actual scale used depends on the device. -->
+ <fraction name="display_density_max_scale">150%</fraction>
+ <!-- Minimum density scale. This is available on all devices. -->
+ <fraction name="display_density_min_scale">85%</fraction>
</resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 0fe869f..8965144e 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1077,7 +1077,7 @@
<!-- Subtitle for the accessibility preference to configure display color space correction. [CHAR LIMIT=NONE] -->
<string name="accessibility_display_daltonizer_preference_subtitle">
<![CDATA[
- Adjust how colors display on your device. This can be helpful when you want to:<br/><br/>
+ Color correction can be helpful when you want to:<br/>
<ol>
<li> See colors more accurately</li>
<li> Remove colors to help you focus</li>
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
index f7b2974..17db45d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
@@ -138,8 +138,6 @@
return true;
}
if (mDisabledByAppOps) {
- Preconditions.checkState(Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU,
- "Build SDK version needs >= T");
RestrictedLockUtilsInternal.sendShowRestrictedSettingDialogIntent(mContext, packageName,
uid);
return true;
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
index 5c05a1b..342189d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
@@ -61,6 +61,7 @@
final TypedValue restrictedSwitchSummary = attributes.peekValue(
R.styleable.RestrictedSwitchPreference_restrictedSwitchSummary);
+ attributes.recycle();
if (restrictedSwitchSummary != null
&& restrictedSwitchSummary.type == TypedValue.TYPE_STRING) {
if (restrictedSwitchSummary.resourceId != 0) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/RecentAppOpsAccess.java b/packages/SettingsLib/src/com/android/settingslib/applications/RecentAppOpsAccess.java
index 2e7cfcb..9a29f22 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/RecentAppOpsAccess.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/RecentAppOpsAccess.java
@@ -51,6 +51,9 @@
private static final int[] MICROPHONE_OPS = new int[]{
AppOpsManager.OP_RECORD_AUDIO,
};
+ private static final int[] CAMERA_OPS = new int[]{
+ AppOpsManager.OP_CAMERA,
+ };
private static final String TAG = RecentAppOpsAccess.class.getSimpleName();
@@ -99,6 +102,13 @@
}
/**
+ * Creates an instance of {@link RecentAppOpsAccess} for camera access.
+ */
+ public static RecentAppOpsAccess createForCamera(Context context) {
+ return new RecentAppOpsAccess(context, CAMERA_OPS);
+ }
+
+ /**
* Fills a list of applications which queried for access recently within specified time.
* Apps are sorted by recency. Apps with more recent accesses are in the front.
*/
diff --git a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
index a38091d..8b34cf3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
@@ -38,15 +38,6 @@
public class DisplayDensityUtils {
private static final String LOG_TAG = "DisplayDensityUtils";
- /** Minimum increment between density scales. */
- private static final float MIN_SCALE_INTERVAL = 0.09f;
-
- /** Minimum density scale. This is available on all devices. */
- private static final float MIN_SCALE = 0.85f;
-
- /** Maximum density scale. The actual scale used depends on the device. */
- private static final float MAX_SCALE = 1.50f;
-
/** Summary used for "default" scale. */
public static final int SUMMARY_DEFAULT = R.string.screen_zoom_summary_default;
@@ -105,11 +96,16 @@
// Compute number of "larger" and "smaller" scales for this display.
final int minDimensionPx = Math.min(metrics.widthPixels, metrics.heightPixels);
final int maxDensity = DisplayMetrics.DENSITY_MEDIUM * minDimensionPx / MIN_DIMENSION_DP;
- final float maxScale = Math.min(MAX_SCALE, maxDensity / (float) defaultDensity);
- final float minScale = MIN_SCALE;
- final int numLarger = (int) MathUtils.constrain((maxScale - 1) / MIN_SCALE_INTERVAL,
+ final float maxScaleDimen = context.getResources().getFraction(
+ R.fraction.display_density_max_scale, 1, 1);
+ final float maxScale = Math.min(maxScaleDimen, maxDensity / (float) defaultDensity);
+ final float minScale = context.getResources().getFraction(
+ R.fraction.display_density_min_scale, 1, 1);
+ final float minScaleInterval = context.getResources().getFraction(
+ R.fraction.display_density_min_scale_interval, 1, 1);
+ final int numLarger = (int) MathUtils.constrain((maxScale - 1) / minScaleInterval,
0, SUMMARIES_LARGER.length);
- final int numSmaller = (int) MathUtils.constrain((1 - minScale) / MIN_SCALE_INTERVAL,
+ final int numSmaller = (int) MathUtils.constrain((1 - minScale) / minScaleInterval,
0, SUMMARIES_SMALLER.length);
String[] entries = new String[1 + numSmaller + numLarger];
diff --git a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
index d179b82..bd3deae 100644
--- a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
@@ -26,8 +26,6 @@
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -35,21 +33,14 @@
import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
import android.text.TextUtils;
-import android.util.AttributeSet;
import android.util.Log;
-import android.util.Xml;
import com.android.settingslib.R;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
@@ -185,15 +176,18 @@
dreamInfo.componentName = componentName;
dreamInfo.isActive = dreamInfo.componentName.equals(activeDream);
- final DreamMetadata dreamMetadata = getDreamMetadata(pm, resolveInfo);
- dreamInfo.settingsComponentName = dreamMetadata.mSettingsActivity;
- dreamInfo.previewImage = dreamMetadata.mPreviewImage;
+ final DreamService.DreamMetadata dreamMetadata = DreamService.getDreamMetadata(mContext,
+ resolveInfo.serviceInfo);
+ if (dreamMetadata != null) {
+ dreamInfo.settingsComponentName = dreamMetadata.settingsActivity;
+ dreamInfo.previewImage = dreamMetadata.previewImage;
+ }
if (dreamInfo.previewImage == null) {
dreamInfo.previewImage = mDreamPreviewDefault;
}
dreamInfos.add(dreamInfo);
}
- Collections.sort(dreamInfos, mComparator);
+ dreamInfos.sort(mComparator);
return dreamInfos;
}
@@ -450,25 +444,31 @@
}
final Intent intent = new Intent()
.setComponent(dreamInfo.settingsComponentName)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ .addFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
uiContext.startActivity(intent);
}
- public void preview(DreamInfo dreamInfo) {
- logd("preview(%s)", dreamInfo);
- if (mDreamManager == null || dreamInfo == null || dreamInfo.componentName == null)
+ /**
+ * Preview a dream, given the component name.
+ */
+ public void preview(ComponentName componentName) {
+ logd("preview(%s)", componentName);
+ if (mDreamManager == null || componentName == null) {
return;
+ }
try {
- mDreamManager.testDream(mContext.getUserId(), dreamInfo.componentName);
+ mDreamManager.testDream(mContext.getUserId(), componentName);
} catch (RemoteException e) {
- Log.w(TAG, "Failed to preview " + dreamInfo, e);
+ Log.w(TAG, "Failed to preview " + componentName, e);
}
}
public void startDreaming() {
logd("startDreaming()");
- if (mDreamManager == null)
+ if (mDreamManager == null) {
return;
+ }
try {
mDreamManager.dream();
} catch (RemoteException e) {
@@ -483,78 +483,6 @@
return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name);
}
- private static final class DreamMetadata {
- @Nullable
- Drawable mPreviewImage;
- @Nullable
- ComponentName mSettingsActivity;
- }
-
- @Nullable
- private static TypedArray readMetadata(PackageManager pm, ServiceInfo serviceInfo) {
- if (serviceInfo == null || serviceInfo.metaData == null) {
- return null;
- }
- try (XmlResourceParser parser =
- serviceInfo.loadXmlMetaData(pm, DreamService.DREAM_META_DATA)) {
- if (parser == null) {
- Log.w(TAG, "No " + DreamService.DREAM_META_DATA + " meta-data");
- return null;
- }
- Resources res = pm.getResourcesForApplication(serviceInfo.applicationInfo);
- AttributeSet attrs = Xml.asAttributeSet(parser);
- while (true) {
- final int type = parser.next();
- if (type == XmlPullParser.END_DOCUMENT || type == XmlPullParser.START_TAG) {
- break;
- }
- }
- String nodeName = parser.getName();
- if (!"dream".equals(nodeName)) {
- Log.w(TAG, "Meta-data does not start with dream tag");
- return null;
- }
- return res.obtainAttributes(attrs, com.android.internal.R.styleable.Dream);
- } catch (PackageManager.NameNotFoundException | IOException | XmlPullParserException e) {
- Log.w(TAG, "Error parsing : " + serviceInfo.packageName, e);
- return null;
- }
- }
-
- private static ComponentName convertToComponentName(String flattenedString,
- ServiceInfo serviceInfo) {
- if (flattenedString == null) return null;
-
- if (flattenedString.indexOf('/') < 0) {
- flattenedString = serviceInfo.packageName + "/" + flattenedString;
- }
-
- ComponentName cn = ComponentName.unflattenFromString(flattenedString);
-
- if (cn == null) return null;
- if (!cn.getPackageName().equals(serviceInfo.packageName)) {
- Log.w(TAG,
- "Inconsistent package name in component: " + cn.getPackageName()
- + ", should be: " + serviceInfo.packageName);
- return null;
- }
-
- return cn;
- }
-
- private static DreamMetadata getDreamMetadata(PackageManager pm, ResolveInfo resolveInfo) {
- DreamMetadata result = new DreamMetadata();
- if (resolveInfo == null) return result;
- TypedArray rawMetadata = readMetadata(pm, resolveInfo.serviceInfo);
- if (rawMetadata == null) return result;
- result.mSettingsActivity = convertToComponentName(rawMetadata.getString(
- com.android.internal.R.styleable.Dream_settingsActivity), resolveInfo.serviceInfo);
- result.mPreviewImage = rawMetadata.getDrawable(
- com.android.internal.R.styleable.Dream_previewImage);
- rawMetadata.recycle();
- return result;
- }
-
private static void logd(String msg, Object... args) {
if (DEBUG) {
Log.d(TAG, args == null || args.length == 0 ? msg : String.format(msg, args));
diff --git a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodPreference.java b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodPreference.java
index 26e3e04..1f4cafc 100644
--- a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodPreference.java
@@ -32,7 +32,6 @@
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
import android.widget.ImageView;
-import android.widget.LinearLayout;
import android.widget.Switch;
import android.widget.Toast;
@@ -156,14 +155,10 @@
final int iconSize = getContext().getResources().getDimensionPixelSize(
R.dimen.secondary_app_icon_size);
if (icon != null && iconSize > 0) {
- if (isTv()) {
- ViewGroup.LayoutParams params = icon.getLayoutParams();
- params.height = iconSize;
- params.width = iconSize;
- icon.setLayoutParams(params);
- } else {
- icon.setLayoutParams(new LinearLayout.LayoutParams(iconSize, iconSize));
- }
+ ViewGroup.LayoutParams params = icon.getLayoutParams();
+ params.height = iconSize;
+ params.width = iconSize;
+ icon.setLayoutParams(params);
}
}
@@ -226,8 +221,8 @@
setSwitchEnabled(false);
} else if (!mIsAllowedByOrganization) {
EnforcedAdmin admin =
- RestrictedLockUtilsInternal.checkIfInputMethodDisallowed(getContext(),
- mImi.getPackageName(), UserHandle.myUserId());
+ RestrictedLockUtilsInternal.checkIfInputMethodDisallowed(
+ getContext(), mImi.getPackageName(), mUserId);
setDisabledByAdmin(admin);
} else {
setEnabled(true);
diff --git a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java
index b4c95e6..2c2be03 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.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 @@
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 @@
+ "</style>\n"
+ "</head>"
+ "<body topmargin=\"0\" leftmargin=\"0\" rightmargin=\"0\" bottommargin=\"0\">\n"
- + "<div class=\"toc\">\n"
- + "<ul>";
+ + "<div class=\"toc\">\n";
+ 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 @@
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 @@
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 @@
parse(xmlFile);
}
- if (mFileNameToContentIdMap.isEmpty() || mContentIdToFileContentMap.isEmpty()) {
+ if (mFileNameToLibraryToContentIdMap.isEmpty() || mContentIdToFileContentMap.isEmpty()) {
return false;
}
@@ -128,7 +137,7 @@
try {
writer = new PrintWriter(outputFile);
- generateHtml(mFileNameToContentIdMap, mContentIdToFileContentMap, writer,
+ generateHtml(mFileNameToLibraryToContentIdMap, mContentIdToFileContentMap, writer,
noticeHeader);
writer.flush();
@@ -157,7 +166,7 @@
in = new FileReader(xmlFile);
}
- parse(in, mFileNameToContentIdMap, mContentIdToFileContentMap);
+ parse(in, mFileNameToLibraryToContentIdMap, mContentIdToFileContentMap);
in.close();
} catch (XmlPullParserException | IOException e) {
@@ -180,7 +189,8 @@
*
* <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 @@
* </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 @@
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 @@
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 @@
}
@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,56 @@
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);
+ }
+
// 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);
- int id = contentIdToOrderMap.get(contentId);
- contentIdAndFileNamesList.get(id).mFileNameList.add(fileName);
- writer.format("<li><a href=\"#id%d\">%s</a></li>\n", id, fileName);
+ // An index in contentIdAndFileNamesList is the order of each element.
+ contentIdAndFileNamesList.add(new ContentIdAndFileNames(contentId));
+ count++;
+ }
+
+ 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 +363,27 @@
// 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/src/com/android/settingslib/location/InjectedSetting.java b/packages/SettingsLib/src/com/android/settingslib/location/InjectedSetting.java
index 1805f1a..42e3af0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/location/InjectedSetting.java
+++ b/packages/SettingsLib/src/com/android/settingslib/location/InjectedSetting.java
@@ -46,12 +46,12 @@
public final String className;
/**
- * The {@link android.support.v7.preference.Preference#getTitle()} value.
+ * The {@link androidx.preference.Preference#getTitle()} value.
*/
public final String title;
/**
- * The {@link android.support.v7.preference.Preference#getIcon()} value.
+ * The {@link androidx.preference.Preference#getIcon()} value.
*/
public final int iconId;
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
index 360361b..dd7db21 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
@@ -19,6 +19,7 @@
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.graphics.drawable.Drawable;
+import android.media.AudioManager;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2Manager;
@@ -34,11 +35,13 @@
private static final String TAG = "BluetoothMediaDevice";
private CachedBluetoothDevice mCachedDevice;
+ private final AudioManager mAudioManager;
BluetoothMediaDevice(Context context, CachedBluetoothDevice device,
MediaRouter2Manager routerManager, MediaRoute2Info info, String packageName) {
super(context, routerManager, info, packageName);
mCachedDevice = device;
+ mAudioManager = context.getSystemService(AudioManager.class);
initDeviceRecord();
}
@@ -98,6 +101,12 @@
}
@Override
+ public boolean isMutingExpectedDevice() {
+ return mAudioManager.getMutingExpectedDevice() != null && mCachedDevice.getAddress().equals(
+ mAudioManager.getMutingExpectedDevice().getAddress());
+ }
+
+ @Override
public boolean isConnected() {
return mCachedDevice.getBondState() == BluetoothDevice.BOND_BONDED
&& mCachedDevice.isConnected();
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/DeviceIconUtil.java b/packages/SettingsLib/src/com/android/settingslib/media/DeviceIconUtil.java
new file mode 100644
index 0000000..6c0eab3
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/media/DeviceIconUtil.java
@@ -0,0 +1,126 @@
+/*
+ * 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.settingslib.media;
+
+import android.annotation.DrawableRes;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.media.AudioDeviceInfo;
+import android.media.MediaRoute2Info;
+
+import com.android.settingslib.R;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/** A util class to get the appropriate icon for different device types. */
+public class DeviceIconUtil {
+ // A map from a @AudioDeviceInfo.AudioDeviceType to full device information.
+ private final Map<Integer, Device> mAudioDeviceTypeToIconMap = new HashMap<>();
+ // A map from a @MediaRoute2Info.Type to full device information.
+ private final Map<Integer, Device> mMediaRouteTypeToIconMap = new HashMap<>();
+ // A default icon to use if the type is not present in the map.
+ @DrawableRes private static final int DEFAULT_ICON = R.drawable.ic_smartphone;
+
+ public DeviceIconUtil() {
+ List<Device> deviceList = Arrays.asList(
+ new Device(
+ AudioDeviceInfo.TYPE_USB_DEVICE,
+ MediaRoute2Info.TYPE_USB_DEVICE,
+ R.drawable.ic_headphone),
+ new Device(
+ AudioDeviceInfo.TYPE_USB_HEADSET,
+ MediaRoute2Info.TYPE_USB_HEADSET,
+ R.drawable.ic_headphone),
+ new Device(
+ AudioDeviceInfo.TYPE_USB_ACCESSORY,
+ MediaRoute2Info.TYPE_USB_ACCESSORY,
+ R.drawable.ic_headphone),
+ new Device(
+ AudioDeviceInfo.TYPE_DOCK,
+ MediaRoute2Info.TYPE_DOCK,
+ R.drawable.ic_headphone),
+ new Device(
+ AudioDeviceInfo.TYPE_HDMI,
+ MediaRoute2Info.TYPE_HDMI,
+ R.drawable.ic_headphone),
+ new Device(
+ AudioDeviceInfo.TYPE_WIRED_HEADSET,
+ MediaRoute2Info.TYPE_WIRED_HEADSET,
+ R.drawable.ic_headphone),
+ new Device(
+ AudioDeviceInfo.TYPE_WIRED_HEADPHONES,
+ MediaRoute2Info.TYPE_WIRED_HEADPHONES,
+ R.drawable.ic_headphone),
+ new Device(
+ AudioDeviceInfo.TYPE_BUILTIN_SPEAKER,
+ MediaRoute2Info.TYPE_BUILTIN_SPEAKER,
+ R.drawable.ic_smartphone));
+ for (int i = 0; i < deviceList.size(); i++) {
+ Device device = deviceList.get(i);
+ mAudioDeviceTypeToIconMap.put(device.mAudioDeviceType, device);
+ mMediaRouteTypeToIconMap.put(device.mMediaRouteType, device);
+ }
+ }
+
+ /** Returns a drawable for an icon representing the given audioDeviceType. */
+ public Drawable getIconFromAudioDeviceType(
+ @AudioDeviceInfo.AudioDeviceType int audioDeviceType, Context context) {
+ return context.getDrawable(getIconResIdFromAudioDeviceType(audioDeviceType));
+ }
+
+ /** Returns a drawable res ID for an icon representing the given audioDeviceType. */
+ @DrawableRes
+ public int getIconResIdFromAudioDeviceType(
+ @AudioDeviceInfo.AudioDeviceType int audioDeviceType) {
+ if (mAudioDeviceTypeToIconMap.containsKey(audioDeviceType)) {
+ return mAudioDeviceTypeToIconMap.get(audioDeviceType).mIconDrawableRes;
+ }
+ return DEFAULT_ICON;
+ }
+
+ /** Returns a drawable res ID for an icon representing the given mediaRouteType. */
+ @DrawableRes
+ public int getIconResIdFromMediaRouteType(
+ @MediaRoute2Info.Type int mediaRouteType) {
+ if (mMediaRouteTypeToIconMap.containsKey(mediaRouteType)) {
+ return mMediaRouteTypeToIconMap.get(mediaRouteType).mIconDrawableRes;
+ }
+ return DEFAULT_ICON;
+ }
+
+ private static class Device {
+ @AudioDeviceInfo.AudioDeviceType
+ private final int mAudioDeviceType;
+
+ @MediaRoute2Info.Type
+ private final int mMediaRouteType;
+
+ @DrawableRes
+ private final int mIconDrawableRes;
+
+ Device(@AudioDeviceInfo.AudioDeviceType int audioDeviceType,
+ @MediaRoute2Info.Type int mediaRouteType,
+ @DrawableRes int iconDrawableRes) {
+ mAudioDeviceType = audioDeviceType;
+ mMediaRouteType = mediaRouteType;
+ mIconDrawableRes = iconDrawableRes;
+ }
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index b5facf3..31d5921 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -21,6 +21,7 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
+import android.graphics.drawable.Drawable;
import android.media.RoutingSessionInfo;
import android.os.Build;
import android.text.TextUtils;
@@ -227,6 +228,18 @@
}
/**
+ * Dispatch a change in the about-to-connect device. See
+ * {@link DeviceCallback#onAboutToConnectDeviceChanged} for more information.
+ */
+ public void dispatchAboutToConnectDeviceChanged(
+ @Nullable String deviceName,
+ @Nullable Drawable deviceIcon) {
+ for (DeviceCallback callback : getCallbacks()) {
+ callback.onAboutToConnectDeviceChanged(deviceName, deviceIcon);
+ }
+ }
+
+ /**
* Stop scan MediaDevice
*/
public void stopScan() {
@@ -674,6 +687,21 @@
* {@link android.media.MediaRoute2ProviderService#REASON_INVALID_COMMAND},
*/
default void onRequestFailed(int reason){};
+
+ /**
+ * Callback for notifying that we have a new about-to-connect device.
+ *
+ * An about-to-connect device is a device that is not yet connected but is expected to
+ * connect imminently and should be displayed as the current device in the media player.
+ * See [AudioManager.muteAwaitConnection] for more details.
+ *
+ * @param deviceName the name of the device (displayed to the user).
+ * @param deviceIcon the icon that should be used with the device.
+ */
+ default void onAboutToConnectDeviceChanged(
+ @Nullable String deviceName,
+ @Nullable Drawable deviceIcon
+ ) {}
}
/**
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
index 970abff..c759962 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
@@ -320,6 +320,13 @@
}
if (mType == another.mType) {
+ // Check device is muting expected device
+ if (isMutingExpectedDevice()) {
+ return -1;
+ } else if (another.isMutingExpectedDevice()) {
+ return 1;
+ }
+
// Check fast pair device
if (isFastPairDevice()) {
return -1;
@@ -392,6 +399,14 @@
return false;
}
+ /**
+ * Check if it is muting expected device
+ * @return {@code true} if it is muting expected device, otherwise return {@code false}
+ */
+ protected boolean isMutingExpectedDevice() {
+ return false;
+ }
+
@Override
public boolean equals(Object obj) {
if (!(obj instanceof MediaDevice)) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
index c16ecb5..921c245 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
@@ -47,10 +47,12 @@
private String mSummary = "";
+ private final DeviceIconUtil mDeviceIconUtil;
+
PhoneMediaDevice(Context context, MediaRouter2Manager routerManager, MediaRoute2Info info,
String packageName) {
super(context, routerManager, info, packageName);
-
+ mDeviceIconUtil = new DeviceIconUtil();
initDeviceRecord();
}
@@ -94,23 +96,7 @@
@VisibleForTesting
int getDrawableResId() {
- int resId;
- switch (mRouteInfo.getType()) {
- case TYPE_USB_DEVICE:
- case TYPE_USB_HEADSET:
- case TYPE_USB_ACCESSORY:
- case TYPE_DOCK:
- case TYPE_HDMI:
- case TYPE_WIRED_HEADSET:
- case TYPE_WIRED_HEADPHONES:
- resId = R.drawable.ic_headphone;
- break;
- case TYPE_BUILTIN_SPEAKER:
- default:
- resId = R.drawable.ic_smartphone;
- break;
- }
- return resId;
+ return mDeviceIconUtil.getIconResIdFromMediaRouteType(mRouteInfo.getType());
}
@Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java b/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
index dee6894..6a1cee3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
@@ -16,6 +16,7 @@
package com.android.settingslib.notification;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.AlertDialog;
@@ -42,8 +43,6 @@
import android.widget.TextView;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.policy.PhoneWindow;
import com.android.settingslib.R;
@@ -72,6 +71,9 @@
private static final int SECONDS_MS = 1000;
private static final int MINUTES_MS = 60 * SECONDS_MS;
+ @Nullable
+ private final ZenModeDialogMetricsLogger mMetricsLogger;
+
@VisibleForTesting
protected Uri mForeverId;
private int mBucketIndex = -1;
@@ -102,13 +104,16 @@
}
public EnableZenModeDialog(Context context, int themeResId) {
- this(context, themeResId, false /* cancelIsNeutral */);
+ this(context, themeResId, false /* cancelIsNeutral */,
+ new ZenModeDialogMetricsLogger(context));
}
- public EnableZenModeDialog(Context context, int themeResId, boolean cancelIsNeutral) {
+ public EnableZenModeDialog(Context context, int themeResId, boolean cancelIsNeutral,
+ ZenModeDialogMetricsLogger metricsLogger) {
mContext = context;
mThemeResId = themeResId;
mCancelIsNeutral = cancelIsNeutral;
+ mMetricsLogger = metricsLogger;
}
public AlertDialog createDialog() {
@@ -129,17 +134,11 @@
ConditionTag tag = getConditionTagAt(checkedId);
if (isForever(tag.condition)) {
- MetricsLogger.action(mContext,
- MetricsProto.MetricsEvent.
- NOTIFICATION_ZEN_MODE_TOGGLE_ON_FOREVER);
+ mMetricsLogger.logOnEnableZenModeForever();
} else if (isAlarm(tag.condition)) {
- MetricsLogger.action(mContext,
- MetricsProto.MetricsEvent.
- NOTIFICATION_ZEN_MODE_TOGGLE_ON_ALARM);
+ mMetricsLogger.logOnEnableZenModeUntilAlarm();
} else if (isCountdown(tag.condition)) {
- MetricsLogger.action(mContext,
- MetricsProto.MetricsEvent.
- NOTIFICATION_ZEN_MODE_TOGGLE_ON_COUNTDOWN);
+ mMetricsLogger.logOnEnableZenModeUntilCountdown();
} else {
Slog.d(TAG, "Invalid manual condition: " + tag.condition);
}
@@ -222,8 +221,7 @@
if (isChecked) {
tag.rb.setChecked(true);
if (DEBUG) Log.d(TAG, "onCheckedChanged " + conditionId);
- MetricsLogger.action(mContext,
- MetricsProto.MetricsEvent.QS_DND_CONDITION_SELECT);
+ mMetricsLogger.logOnConditionSelected();
updateAlarmWarningText(tag.condition);
}
}
@@ -435,7 +433,7 @@
}
private void onClickTimeButton(View row, ConditionTag tag, boolean up, int rowId) {
- MetricsLogger.action(mContext, MetricsProto.MetricsEvent.QS_DND_TIME, up);
+ mMetricsLogger.logOnClickTimeButton(up);
Condition newCondition = null;
final int N = MINUTE_BUCKETS.length;
if (mBucketIndex == -1) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/ZenModeDialogMetricsLogger.java b/packages/SettingsLib/src/com/android/settingslib/notification/ZenModeDialogMetricsLogger.java
new file mode 100644
index 0000000..088a37d
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/ZenModeDialogMetricsLogger.java
@@ -0,0 +1,76 @@
+/*
+ * 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.settingslib.notification;
+
+import android.content.Context;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
+
+/**
+ * Logs ui events for {@link EnableZenModeDialog}.
+ */
+public class ZenModeDialogMetricsLogger {
+ private final Context mContext;
+
+ public ZenModeDialogMetricsLogger(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * User enabled DND from the QS DND dialog to last until manually turned off
+ */
+ public void logOnEnableZenModeForever() {
+ MetricsLogger.action(
+ mContext,
+ MetricsProto.MetricsEvent.NOTIFICATION_ZEN_MODE_TOGGLE_ON_FOREVER);
+ }
+
+ /**
+ * User enabled DND from the QS DND dialog to last until the next alarm goes off
+ */
+ public void logOnEnableZenModeUntilAlarm() {
+ MetricsLogger.action(
+ mContext,
+ MetricsProto.MetricsEvent.NOTIFICATION_ZEN_MODE_TOGGLE_ON_ALARM);
+ }
+
+ /**
+ * User enabled DND from the QS DND dialog to last until countdown is done
+ */
+ public void logOnEnableZenModeUntilCountdown() {
+ MetricsLogger.action(
+ mContext,
+ MetricsProto.MetricsEvent.NOTIFICATION_ZEN_MODE_TOGGLE_ON_COUNTDOWN);
+ }
+
+ /**
+ * User selected an option on the DND dialog
+ */
+ public void logOnConditionSelected() {
+ MetricsLogger.action(
+ mContext,
+ MetricsProto.MetricsEvent.QS_DND_CONDITION_SELECT);
+ }
+
+ /**
+ * User increased or decreased countdown duration of DND from the DND dialog
+ */
+ public void logOnClickTimeButton(boolean up) {
+ MetricsLogger.action(mContext, MetricsProto.MetricsEvent.QS_DND_TIME, up);
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java
index f6affb8..1b63e3e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java
@@ -30,6 +30,7 @@
import androidx.preference.PreferenceViewHolder;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -57,6 +58,7 @@
}
@Test
+ @Ignore
public void bindPreference_disabled_shouldDisplayDisabledSummary() {
final TextView summaryView = mock(TextView.class, RETURNS_DEEP_STUBS);
when(mViewHolder.itemView.findViewById(android.R.id.summary))
@@ -73,6 +75,7 @@
}
@Test
+ @Ignore
public void bindPreference_notDisabled_shouldNotHideSummary() {
final TextView summaryView = mock(TextView.class, RETURNS_DEEP_STUBS);
when(mViewHolder.itemView.findViewById(android.R.id.summary))
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 e87461f..bf07004 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
@@ -18,6 +18,7 @@
import static com.google.common.truth.Truth.assertThat;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
@@ -35,8 +36,9 @@
import java.util.Set;
@RunWith(RobolectricTestRunner.class)
+@Ignore
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 +46,15 @@
+ "<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 +74,13 @@
+ "</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 +107,181 @@
+ "</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\">Notices for file(s):</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\">Notices for file(s):</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_HTML_STRING_WITH_CUSTOM_HEADING =
- HTML_HEAD_STRING + HTML_CUSTOM_HEADING + "\n" + HTML_BODY_STRING;
+ private static final String EXPECTED_OLD_HTML_STRING = HTML_HEAD_STRING + HTML_OLD_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(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_OLD_XML_STRING.getBytes())),
+ fileNameToLibraryToContentIdMap, contentIdToFileContentMap);
+ assertThat(fileNameToLibraryToContentIdMap.size()).isEqualTo(1);
+ assertThat(fileNameToLibraryToContentIdMap.get("").size()).isEqualTo(2);
+ assertThat(fileNameToLibraryToContentIdMap.get("").get("/file0")).containsExactly("0");
+ assertThat(fileNameToLibraryToContentIdMap.get("").get("/file1")).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(VALID_NEW_XML_STRING.getBytes())),
+ fileNameToLibraryToContentIdMap, contentIdToFileContentMap);
+ assertThat(fileNameToLibraryToContentIdMap.size()).isEqualTo(2);
+ assertThat(fileNameToLibraryToContentIdMap.get("libA").size()).isEqualTo(1);
+ assertThat(fileNameToLibraryToContentIdMap.get("libB").size()).isEqualTo(1);
+ assertThat(fileNameToLibraryToContentIdMap.get("libA").get("/file0")).containsExactly("0");
+ assertThat(fileNameToLibraryToContentIdMap.get("libB").get("/file1")).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<>();
- fileNameToContentIdMap.put("/file0", new HashSet<String>(Arrays.asList("0", "1")));
- fileNameToContentIdMap.put("/file1", new HashSet<String>(Arrays.asList("0")));
+ 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(
- fileNameToContentIdMap, contentIdToFileContentMap, new PrintWriter(output), "");
- assertThat(output.toString()).isEqualTo(EXPECTED_HTML_STRING);
+ 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")));
+
+ 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_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<>();
- fileNameToContentIdMap.put("/file0", new HashSet<String>(Arrays.asList("0", "1")));
- fileNameToContentIdMap.put("/file1", new HashSet<String>(Arrays.asList("0")));
+ 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(
- 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_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")));
+
+ 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_NEW_HTML_STRING_WITH_CUSTOM_HEADING);
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/DeviceIconUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/DeviceIconUtilTest.java
new file mode 100644
index 0000000..72dfc17
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/DeviceIconUtilTest.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright 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.settingslib.media;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.media.AudioDeviceInfo;
+import android.media.MediaRoute2Info;
+
+import com.android.settingslib.R;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class DeviceIconUtilTest {
+ private final DeviceIconUtil mDeviceIconUtil = new DeviceIconUtil();
+
+ @Test
+ public void getIconResIdFromMediaRouteType_usbDevice_isHeadphone() {
+ assertThat(mDeviceIconUtil.getIconResIdFromMediaRouteType(MediaRoute2Info.TYPE_USB_DEVICE))
+ .isEqualTo(R.drawable.ic_headphone);
+ }
+
+ @Test
+ public void getIconResIdFromMediaRouteType_usbHeadset_isHeadphone() {
+ assertThat(mDeviceIconUtil.getIconResIdFromMediaRouteType(MediaRoute2Info.TYPE_USB_HEADSET))
+ .isEqualTo(R.drawable.ic_headphone);
+ }
+
+ @Test
+ public void getIconResIdFromMediaRouteType_usbAccessory_isHeadphone() {
+ assertThat(
+ mDeviceIconUtil.getIconResIdFromMediaRouteType(MediaRoute2Info.TYPE_USB_ACCESSORY))
+ .isEqualTo(R.drawable.ic_headphone);
+ }
+
+ @Test
+ public void getIconResIdFromMediaRouteType_dock_isHeadphone() {
+ assertThat(mDeviceIconUtil.getIconResIdFromMediaRouteType(MediaRoute2Info.TYPE_DOCK))
+ .isEqualTo(R.drawable.ic_headphone);
+ }
+
+ @Test
+ public void getIconResIdFromMediaRouteType_hdmi_isHeadphone() {
+ assertThat(mDeviceIconUtil.getIconResIdFromMediaRouteType(MediaRoute2Info.TYPE_HDMI))
+ .isEqualTo(R.drawable.ic_headphone);
+ }
+
+ @Test
+ public void getIconResIdFromMediaRouteType_wiredHeadset_isHeadphone() {
+ assertThat(
+ mDeviceIconUtil.getIconResIdFromMediaRouteType(MediaRoute2Info.TYPE_WIRED_HEADSET))
+ .isEqualTo(R.drawable.ic_headphone);
+ }
+
+ @Test
+ public void getIconResIdFromMediaRouteType_wiredHeadphones_isHeadphone() {
+ assertThat(
+ mDeviceIconUtil.getIconResIdFromMediaRouteType(MediaRoute2Info.TYPE_WIRED_HEADPHONES))
+ .isEqualTo(R.drawable.ic_headphone);
+ }
+
+ @Test
+ public void getIconResIdFromMediaRouteType_builtinSpeaker_isSmartphone() {
+ assertThat(
+ mDeviceIconUtil.getIconResIdFromMediaRouteType(MediaRoute2Info.TYPE_BUILTIN_SPEAKER))
+ .isEqualTo(R.drawable.ic_smartphone);
+ }
+
+ @Test
+ public void getIconResIdFromMediaRouteType_unsupportedType_isSmartphone() {
+ assertThat(mDeviceIconUtil.getIconResIdFromMediaRouteType(MediaRoute2Info.TYPE_UNKNOWN))
+ .isEqualTo(R.drawable.ic_smartphone);
+ }
+
+ @Test
+ public void getIconResIdFromAudioDeviceType_usbDevice_isHeadphone() {
+ assertThat(mDeviceIconUtil.getIconResIdFromAudioDeviceType(AudioDeviceInfo.TYPE_USB_DEVICE))
+ .isEqualTo(R.drawable.ic_headphone);
+ }
+
+ @Test
+ public void getIconResIdFromAudioDeviceType_usbHeadset_isHeadphone() {
+ assertThat(
+ mDeviceIconUtil.getIconResIdFromAudioDeviceType(AudioDeviceInfo.TYPE_USB_HEADSET))
+ .isEqualTo(R.drawable.ic_headphone);
+ }
+
+ @Test
+ public void getIconResIdFromAudioDeviceType_usbAccessory_isHeadphone() {
+ assertThat(
+ mDeviceIconUtil.getIconResIdFromAudioDeviceType(AudioDeviceInfo.TYPE_USB_ACCESSORY))
+ .isEqualTo(R.drawable.ic_headphone);
+ }
+
+ @Test
+ public void getIconResIdFromAudioDeviceType_dock_isHeadphone() {
+ assertThat(mDeviceIconUtil.getIconResIdFromAudioDeviceType(AudioDeviceInfo.TYPE_DOCK))
+ .isEqualTo(R.drawable.ic_headphone);
+ }
+
+ @Test
+ public void getIconResIdFromAudioDeviceType_hdmi_isHeadphone() {
+ assertThat(mDeviceIconUtil.getIconResIdFromAudioDeviceType(AudioDeviceInfo.TYPE_HDMI))
+ .isEqualTo(R.drawable.ic_headphone);
+ }
+
+ @Test
+ public void getIconResIdFromAudioDeviceType_wiredHeadset_isHeadphone() {
+ assertThat(
+ mDeviceIconUtil.getIconResIdFromAudioDeviceType(AudioDeviceInfo.TYPE_WIRED_HEADSET))
+ .isEqualTo(R.drawable.ic_headphone);
+ }
+
+ @Test
+ public void getIconResIdFromAudioDeviceType_wiredHeadphones_isHeadphone() {
+ assertThat(
+ mDeviceIconUtil.getIconResIdFromAudioDeviceType(AudioDeviceInfo.TYPE_WIRED_HEADPHONES))
+ .isEqualTo(R.drawable.ic_headphone);
+ }
+
+ @Test
+ public void getIconResIdFromAudioDeviceType_builtinSpeaker_isSmartphone() {
+ assertThat(
+ mDeviceIconUtil.getIconResIdFromAudioDeviceType(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER))
+ .isEqualTo(R.drawable.ic_smartphone);
+ }
+
+ @Test
+ public void getIconResIdFromAudioDeviceType_unsupportedType_isSmartphone() {
+ assertThat(mDeviceIconUtil.getIconResIdFromAudioDeviceType(AudioDeviceInfo.TYPE_UNKNOWN))
+ .isEqualTo(R.drawable.ic_smartphone);
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/EditUserInfoControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/EditUserInfoControllerTest.java
index a5ee4c3..f28572f 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/EditUserInfoControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/EditUserInfoControllerTest.java
@@ -39,6 +39,7 @@
import com.android.settingslib.R;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
@@ -54,6 +55,7 @@
import java.util.stream.Stream;
@RunWith(RobolectricTestRunner.class)
+@Ignore
public class EditUserInfoControllerTest {
private static final int MAX_USER_NAME_LENGTH = 100;
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
index a6bfc408b..716ee84 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
@@ -43,6 +43,7 @@
Settings.System.FONT_SCALE,
Settings.System.DIM_SCREEN,
Settings.System.SCREEN_OFF_TIMEOUT,
+ Settings.System.SCREEN_OFF_TIMEOUT_DOCKED,
Settings.System.SCREEN_BRIGHTNESS_MODE,
Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ,
Settings.System.SCREEN_BRIGHTNESS_FOR_VR,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index 06712cc..d430296 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -111,6 +111,7 @@
});
VALIDATORS.put(System.DISPLAY_COLOR_MODE_VENDOR_HINT, ANY_STRING_VALIDATOR);
VALIDATORS.put(System.SCREEN_OFF_TIMEOUT, NON_NEGATIVE_INTEGER_VALIDATOR);
+ VALIDATORS.put(System.SCREEN_OFF_TIMEOUT_DOCKED, NON_NEGATIVE_INTEGER_VALIDATOR);
VALIDATORS.put(System.SCREEN_BRIGHTNESS_FOR_VR, new InclusiveIntegerRangeValidator(0, 255));
VALIDATORS.put(System.SCREEN_BRIGHTNESS_MODE, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.ADAPTIVE_SLEEP, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 86ee3b3..0c6d40aa 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -652,29 +652,31 @@
return Collections.emptySet();
}
- Cursor cursor = getContentResolver().query(settingsUri, new String[] {
- Settings.NameValueTable.NAME, Settings.NameValueTable.IS_PRESERVED_IN_RESTORE },
- /* selection */ null, /* selectionArgs */ null, /* sortOrder */ null);
+ try (Cursor cursor = getContentResolver().query(settingsUri, new String[]{
+ Settings.NameValueTable.NAME,
+ Settings.NameValueTable.IS_PRESERVED_IN_RESTORE},
+ /* selection */ null, /* selectionArgs */ null, /* sortOrder */ null)) {
- if (!cursor.moveToFirst()) {
- Slog.i(TAG, "No settings to be preserved in restore");
- return Collections.emptySet();
- }
-
- int nameIndex = cursor.getColumnIndex(Settings.NameValueTable.NAME);
- int isPreservedIndex = cursor.getColumnIndex(
- Settings.NameValueTable.IS_PRESERVED_IN_RESTORE);
-
- Set<String> preservedSettings = new HashSet<>();
- while (!cursor.isAfterLast()) {
- if (Boolean.parseBoolean(cursor.getString(isPreservedIndex))) {
- preservedSettings.add(getQualifiedKeyForSetting(cursor.getString(nameIndex),
- settingsUri));
+ if (!cursor.moveToFirst()) {
+ Slog.i(TAG, "No settings to be preserved in restore");
+ return Collections.emptySet();
}
- cursor.moveToNext();
- }
- return preservedSettings;
+ int nameIndex = cursor.getColumnIndex(Settings.NameValueTable.NAME);
+ int isPreservedIndex = cursor.getColumnIndex(
+ Settings.NameValueTable.IS_PRESERVED_IN_RESTORE);
+
+ Set<String> preservedSettings = new HashSet<>();
+ while (!cursor.isAfterLast()) {
+ if (Boolean.parseBoolean(cursor.getString(isPreservedIndex))) {
+ preservedSettings.add(getQualifiedKeyForSetting(cursor.getString(nameIndex),
+ settingsUri));
+ }
+ cursor.moveToNext();
+ }
+
+ return preservedSettings;
+ }
}
/**
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index e9f940a..741fe4f 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -603,6 +603,9 @@
<uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_ROUTING" />
+ <!-- Permission required for CTS test - CtsAmbientContextDetectionServiceDeviceTest -->
+ <uses-permission android:name="android.permission.ACCESS_AMBIENT_CONTEXT_EVENT" />
+
<!-- Permission required for CTS test - CallAudioInterceptionTest -->
<uses-permission android:name="android.permission.CALL_AUDIO_INTERCEPTION" />
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteTransitionAdapter.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteTransitionAdapter.kt
index 7ef0901..2e9a16f 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteTransitionAdapter.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteTransitionAdapter.kt
@@ -24,6 +24,7 @@
import android.os.RemoteException
import android.util.ArrayMap
import android.util.Log
+import android.util.RotationUtils
import android.view.IRemoteAnimationFinishedCallback
import android.view.IRemoteAnimationRunner
import android.view.RemoteAnimationAdapter
@@ -345,39 +346,33 @@
* Sets up this rotator.
*
* @param rotateDelta is the forward rotation change (the rotation the display is making).
- * @param displayW (and H) Is the size of the rotating display.
+ * @param parentW (and H) Is the size of the rotating parent.
*/
fun setup(
t: SurfaceControl.Transaction,
parent: SurfaceControl,
rotateDelta: Int,
- displayW: Float,
- displayH: Float
+ parentW: Float,
+ parentH: Float
) {
- var rotateDelta = rotateDelta
if (rotateDelta == 0) return
- // We want to counter-rotate, so subtract from 4
- rotateDelta = 4 - (rotateDelta + 4) % 4
- surface = SurfaceControl.Builder()
+ val surface = SurfaceControl.Builder()
.setName("Transition Unrotate")
.setContainerLayer()
.setParent(parent)
.build()
- // column-major
- when (rotateDelta) {
- 1 -> {
- t.setMatrix(surface, 0f, 1f, -1f, 0f)
- t.setPosition(surface!!, displayW, 0f)
- }
- 2 -> {
- t.setMatrix(surface, -1f, 0f, 0f, -1f)
- t.setPosition(surface!!, displayW, displayH)
- }
- 3 -> {
- t.setMatrix(surface, 0f, -1f, 1f, 0f)
- t.setPosition(surface!!, 0f, displayH)
- }
- }
+ // Rotate forward to match the new rotation (rotateDelta is the forward rotation the
+ // parent already took). Child surfaces will be in the old rotation relative to the new
+ // parent rotation, so we need to forward-rotate the child surfaces to match.
+ RotationUtils.rotateSurface(t, surface, rotateDelta)
+ val tmpPt = Point(0, 0)
+ // parentW/H are the size in the END rotation, the rotation utilities expect the
+ // starting size. So swap them if necessary
+ val flipped = rotateDelta % 2 != 0
+ val pw = if (flipped) parentH else parentW
+ val ph = if (flipped) parentW else parentH
+ RotationUtils.rotatePoint(tmpPt, rotateDelta, pw.toInt(), ph.toInt())
+ t.setPosition(surface, tmpPt.x.toFloat(), tmpPt.y.toFloat())
t.show(surface)
}
diff --git a/packages/SystemUI/docs/keyguard/aod.md b/packages/SystemUI/docs/keyguard/aod.md
index 6d76ed5..7f89984 100644
--- a/packages/SystemUI/docs/keyguard/aod.md
+++ b/packages/SystemUI/docs/keyguard/aod.md
@@ -1 +1,77 @@
# Always-on Display (AOD)
+
+AOD provides an alternatative 'screen-off' experience. Instead, of completely turning the display off, it provides a distraction-free, glanceable experience for the phone in a low-powered mode. In this low-powered mode, the display will have a lower refresh rate and the UI should frequently shift its displayed contents in order to prevent burn-in.
+
+The default doze component is specified by `config_dozeComponent` in the [framework config][1]. SystemUI provides a default Doze Component: [DozeService][2]. [DozeService][2] builds a [DozeMachine][3] with dependencies specified in [DozeModule][4] and configurations in [AmbientDisplayConfiguration][13] and [DozeParameters][14].
+
+[DozeMachine][3] handles the following main states:
+* AOD - persistently showing UI when the device is in a low-powered state
+* Pulsing - waking up the screen to show notifications (from AOD and screen off)
+* Docked UI - UI to show when the device is docked
+* Wake-up gestures - including lift to wake and tap to wake (from AOD and screen off)
+
+## Doze States ([see DozeMachine.State][3])
+### DOZE
+Device is asleep and listening for enabled pulsing and wake-up gesture triggers. In this state, no UI shows.
+
+### DOZE_AOD
+Device is asleep, showing UI, and listening for enabled pulsing and wake-up triggers. In this state, screen brightness is handled by [DozeScreenBrightness][5] which uses the brightness sensor specified by `doze_brightness_sensor_type` in the [SystemUI config][6]. To save power, this should be a low-powered sensor that shouldn't trigger as often as the light sensor used for on-screen adaptive brightness.
+
+### DOZE_AOD_PAUSED
+Device is asleep and would normally be in state `DOZE_AOD`; however, instead the display is temporarily off since the proximity sensor reported near for a minimum abount of time. [DozePauser][7] handles transitioning from `DOZE_AOD_PAUSING` after the minimum timeout after the NEAR is reported by the proximity sensor from [DozeTriggers][8]).
+
+### DOZE_PULSING
+Device is awake and showing UI. This is state typically occurs in response to incoming notification, but may also be from other pulse triggers specified in [DozeTriggers][8].
+
+### DOZE_AOD_DOCKED
+Device is awake, showing docking UI and listening for enabled pulsing and wake-up triggers. The default DockManager is provided by an empty interface at [DockManagerImpl][9]. SystemUI should override the DockManager for the DozeService to handle docking events.
+
+[DozeDockHandler][11] listens for Dock state changes from [DockManager][10] and updates the doze docking state.
+
+## Wake-up gestures
+Doze sensors are registered in [DozeTriggers][8] via [DozeSensors][12]. Sensors can be configured per posture for foldable devices.
+
+Relevant sensors include:
+* Proximity sensor
+* Brightness sensor
+* Wake-up gestures
+ * tap to wake
+ * double tap to wake
+ * lift to wake
+ * significant motion
+
+And are configured in the [AmbientDisplayConfiguration][13] with some related configurations specified in [DozeParameters][14].
+
+## Debugging Tips
+Enable DozeLog to print directly to logcat:
+```
+adb shell settings put global systemui/buffer/DozeLog v
+```
+
+Enable all DozeService logs to print directly to logcat:
+```
+adb shell setprop log.tag.DozeService DEBUG
+```
+
+Other helpful dumpsys commands (`adb shell dumpsys <service>`):
+* activity service com.android.systemui/.doze.DozeService
+* activity service com.android.systemui/.SystemUIService
+* display
+* power
+* dreams
+* sensorservice
+
+[1]: /frameworks/base/core/res/res/values/config.xml
+[2]: /frameworks/base/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+[3]: /frameworks/base/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+[4]: /frameworks/base/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java
+[5]: /frameworks/base/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+[6]: /frameworks/base/packages/SystemUI/res/values/config.xml
+[7]: /frameworks/base/packages/SystemUI/src/com/android/systemui/doze/DozePauser.java
+[8]: /frameworks/base/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+[9]: /frameworks/base/packages/SystemUI/src/com/android/systemui/dock/DockManagerImpl.java
+[10]: /frameworks/base/packages/SystemUI/src/com/android/systemui/dock/DockManager.java
+[11]: /frameworks/base/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
+[12]: /frameworks/base/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+[13]: /frameworks/base/core/java/android/hardware/display/AmbientDisplayConfiguration.java
+[14]: /frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/DarkIconDispatcher.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/DarkIconDispatcher.java
index c7bc858..757ed76 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/DarkIconDispatcher.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/DarkIconDispatcher.java
@@ -25,6 +25,8 @@
import com.android.systemui.plugins.annotations.DependsOn;
import com.android.systemui.plugins.annotations.ProvidesInterface;
+import java.util.ArrayList;
+
/**
* Dispatches events to {@link DarkReceiver}s about changes in darkness, tint area and dark
* intensity. Accessible through {@link PluginDependency}
@@ -32,15 +34,15 @@
@ProvidesInterface(version = DarkIconDispatcher.VERSION)
@DependsOn(target = DarkReceiver.class)
public interface DarkIconDispatcher {
- int VERSION = 1;
+ int VERSION = 2;
/**
* Sets the dark area so {@link #applyDark} only affects the icons in the specified area.
*
- * @param r the area in which icons should change its tint, in logical screen
+ * @param r the areas in which icons should change its tint, in logical screen
* coordinates
*/
- void setIconsDarkArea(Rect r);
+ void setIconsDarkArea(ArrayList<Rect> r);
/**
* Adds a receiver to receive callbacks onDarkChanged
@@ -76,8 +78,8 @@
* @return the tint to apply to view depending on the desired tint color and
* the screen tintArea in which to apply that tint
*/
- static int getTint(Rect tintArea, View view, int color) {
- if (isInArea(tintArea, view)) {
+ static int getTint(ArrayList<Rect> tintAreas, View view, int color) {
+ if (isInAreas(tintAreas, view)) {
return color;
} else {
return DEFAULT_ICON_TINT;
@@ -85,15 +87,16 @@
}
/**
- * @return the dark intensity to apply to view depending on the desired dark
- * intensity and the screen tintArea in which to apply that intensity
+ * @return true if more than half of the view area are in any of the given
+ * areas, false otherwise
*/
- static float getDarkIntensity(Rect tintArea, View view, float intensity) {
- if (isInArea(tintArea, view)) {
- return intensity;
- } else {
- return 0f;
+ static boolean isInAreas(ArrayList<Rect> areas, View view) {
+ for (Rect area : areas) {
+ if (isInArea(area, view)) {
+ return true;
+ }
}
+ return false;
}
/**
@@ -122,7 +125,7 @@
*/
@ProvidesInterface(version = DarkReceiver.VERSION)
interface DarkReceiver {
- int VERSION = 1;
- void onDarkChanged(Rect area, float darkIntensity, int tint);
+ int VERSION = 2;
+ void onDarkChanged(ArrayList<Rect> areas, float darkIntensity, int tint);
}
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/DetailAdapter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/DetailAdapter.java
deleted file mode 100644
index 6d1408d..0000000
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/DetailAdapter.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 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 com.android.systemui.plugins.qs;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.android.internal.logging.UiEventLogger;
-import com.android.systemui.plugins.annotations.ProvidesInterface;
-
-@ProvidesInterface(version = DetailAdapter.VERSION)
-public interface DetailAdapter {
- public static final int VERSION = 1;
-
- CharSequence getTitle();
- Boolean getToggleState();
-
- default boolean getToggleEnabled() {
- return true;
- }
-
- View createDetailView(Context context, View convertView, ViewGroup parent);
-
- /**
- * @return intent for opening more settings related to this detail panel. If null, the more
- * settings button will not be shown
- */
- Intent getSettingsIntent();
-
- /**
- * @return resource id of the string to use for opening the settings intent. If
- * {@code Resources.ID_NULL}, then use the default string:
- * {@code com.android.systemui.R.string.quick_settings_more_settings}
- */
- default int getSettingsText() {
- return Resources.ID_NULL;
- }
-
- /**
- * @return resource id of the string to use for closing the detail panel. If
- * {@code Resources.ID_NULL}, then use the default string:
- * {@code com.android.systemui.R.string.quick_settings_done}
- */
- default int getDoneText() {
- return Resources.ID_NULL;
- }
-
- void setToggleState(boolean state);
- int getMetricsCategory();
-
- /**
- * Indicates whether the detail view wants to have its header (back button, title and
- * toggle) shown.
- */
- default boolean hasHeader() {
- return true;
- }
-
- /**
- * Indicates whether the detail view wants to animate when shown. This has no affect over the
- * closing animation. Detail panels will always animate when closed.
- */
- default boolean shouldAnimate() {
- return true;
- }
-
- /**
- * @return true if the callback handled the event and wants to keep the detail panel open, false
- * otherwise. Returning false will close the panel.
- */
- default boolean onDoneButtonClicked() {
- return false;
- }
-
- default UiEventLogger.UiEventEnum openDetailEvent() {
- return INVALID;
- }
-
- default UiEventLogger.UiEventEnum closeDetailEvent() {
- return INVALID;
- }
-
- default UiEventLogger.UiEventEnum moreSettingsEvent() {
- return INVALID;
- }
-
- UiEventLogger.UiEventEnum INVALID = () -> 0;
-}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
index 1ef5324..669d6a3 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
@@ -35,14 +35,12 @@
@ProvidesInterface(version = QSTile.VERSION)
@DependsOn(target = QSIconView.class)
-@DependsOn(target = DetailAdapter.class)
@DependsOn(target = Callback.class)
@DependsOn(target = Icon.class)
@DependsOn(target = State.class)
public interface QSTile {
- int VERSION = 2;
+ int VERSION = 3;
- DetailAdapter getDetailAdapter();
String getTileSpec();
boolean isAvailable();
@@ -117,12 +115,9 @@
}
@ProvidesInterface(version = Callback.VERSION)
- public interface Callback {
- public static final int VERSION = 1;
+ interface Callback {
+ static final int VERSION = 2;
void onStateChanged(State state);
- void onShowDetail(boolean show);
- void onToggleStateChanged(boolean state);
- void onScanStateChanged(boolean state);
}
@ProvidesInterface(version = Icon.VERSION)
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index ce63b44..6352f81 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -1,3 +1,6 @@
+# Preserve line number information for debugging stack traces.
+-keepattributes SourceFile,LineNumberTable
+
-keep class com.android.systemui.recents.OverviewProxyRecentsImpl
-keep class com.android.systemui.statusbar.car.CarStatusBar
-keep class com.android.systemui.statusbar.phone.StatusBar
diff --git a/packages/SystemUI/res-keyguard/layout/fgs_footer.xml b/packages/SystemUI/res-keyguard/layout/fgs_footer.xml
index 5343411..59f87da 100644
--- a/packages/SystemUI/res-keyguard/layout/fgs_footer.xml
+++ b/packages/SystemUI/res-keyguard/layout/fgs_footer.xml
@@ -16,9 +16,8 @@
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="0dp"
+ android:layout_width="match_parent"
android:layout_height="@dimen/qs_security_footer_single_line_height"
- android:layout_weight="1"
android:gravity="center"
android:clickable="true"
android:visibility="gone">
diff --git a/packages/SystemUI/res-keyguard/values-af/strings.xml b/packages/SystemUI/res-keyguard/values-af/strings.xml
index f774251..f2ad66d 100644
--- a/packages/SystemUI/res-keyguard/values-af/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-af/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Wagwoord word vir bykomende sekuriteit vereis"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Toestel is deur administrateur gesluit"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Toestel is handmatig gesluit"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Nie herken nie"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nie herken nie"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Skakel "<b>"kameratoegang"</b>" in Instellings > Privaatheid aan om Gesigslot te gebruik"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-am/strings.xml b/packages/SystemUI/res-keyguard/values-am/strings.xml
index 465f25c..7f4f6fd 100644
--- a/packages/SystemUI/res-keyguard/values-am/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-am/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"የይለፍ ቃል ለተጨማሪ ደህንነት ያስፈልጋል"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"መሣሪያ በአስተዳዳሪ ተቆልፏል"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"መሣሪያ በተጠቃሚው ራሱ ተቆልፏል"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"አልታወቀም"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"አልታወቀም"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"በመልክ መክፈትን ለመጠቀም "<b>"የካሜራ መዳረሻ"</b>"ን በቅንብሮች እና ግላዊነት ውስጥ ያብሩ"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-ar/strings.xml b/packages/SystemUI/res-keyguard/values-ar/strings.xml
index 653e6d3..5d7ac0d 100644
--- a/packages/SystemUI/res-keyguard/values-ar/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ar/strings.xml
@@ -97,7 +97,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"يجب إدخال كلمة المرور لمزيد من الأمان"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"اختار المشرف قفل الجهاز"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"تم حظر الجهاز يدويًا"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"لم يتم التعرف عليها."</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"لم يتم التعرّف عليه."</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"لاستخدام ميزة \"فتح الجهاز بالتعرف على الوجه\"، عليك منح إذن "<b>"الوصول إلى الكاميرا"</b>" في الإعدادات > الخصوصية."</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-as/strings.xml b/packages/SystemUI/res-keyguard/values-as/strings.xml
index 82abbfd..a59d4c9 100644
--- a/packages/SystemUI/res-keyguard/values-as/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-as/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"অতিৰিক্ত সুৰক্ষাৰ বাবে পাছৱর্ড দিয়াটো বাধ্যতামূলক"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"প্ৰশাসকে ডিভাইচ লক কৰি ৰাখিছে"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ডিভাইচটো মেনুৱেলভাৱে লক কৰা হৈছিল"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"চিনাক্ত কৰিব পৰা নাই"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"চিনাক্ত কৰিব পৰা নাই"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"ফেচ আনলক সুবিধাটো ব্যৱহাৰ কৰিবলৈ ছেটিং > গোপনীয়তাত "<b>"কেমেৰাৰ এক্সেছ"</b>" অন কৰক"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-az/strings.xml b/packages/SystemUI/res-keyguard/values-az/strings.xml
index f908851..71fd47b 100644
--- a/packages/SystemUI/res-keyguard/values-az/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-az/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Əlavə təhlükəsizlik üçün parol tələb olunur"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Cihaz admin tərəfindən kilidlənib"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Cihaz əl ilə kilidləndi"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Tanınmır"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Tanınmır"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Üz ilə Kiliddən Açma funksiyasını istifadə etmək üçün Ayarlar > Məxfilik bölməsində "<b>"Kameraya girişi"</b>" aktiv edin"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
index bdf1648..c04a766 100644
--- a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
@@ -91,7 +91,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Treba da unesete lozinku radi dodatne bezbednosti"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Administrator je zaključao uređaj"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Uređaj je ručno zaključan"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Nije prepoznat"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nije prepoznat"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Da biste koristili otključavanje licem, uključite "<b>"pristup kameri"</b>" u odeljku Podešavanja > Privatnost"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-be/strings.xml b/packages/SystemUI/res-keyguard/values-be/strings.xml
index 8fc6a6b..eda5497f 100644
--- a/packages/SystemUI/res-keyguard/values-be/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-be/strings.xml
@@ -93,7 +93,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Для забеспячэння дадатковай бяспекі патрабуецца пароль"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Прылада заблакіравана адміністратарам"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Прылада была заблакіравана ўручную"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Не распазнана"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Не распазнана"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Каб выкарыстоўваць распазнаванне твару, уключыце "<b>"доступ да камеры"</b>" праз раздзел \"Налады > Прыватнасць\""</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-bg/strings.xml b/packages/SystemUI/res-keyguard/values-bg/strings.xml
index 62a9ec6..dcf0a05 100644
--- a/packages/SystemUI/res-keyguard/values-bg/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bg/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"За допълнителна сигурност се изисква парола"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Устройството е заключено от администратора"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Устройството бе заключено ръчно"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Не е разпознато"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Не е разпознато"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"За да използвате функцията „Отключване с лице“, включете "<b>"достъпа до камерата"</b>" от „Настройки > Поверителност“"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-bn/strings.xml b/packages/SystemUI/res-keyguard/values-bn/strings.xml
index 160442a..f96db50 100644
--- a/packages/SystemUI/res-keyguard/values-bn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bn/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"অতিরিক্ত সুরক্ষার জন্য পাসওয়ার্ড দেওয়া প্রয়োজন"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"প্রশাসক ডিভাইসটি লক করেছেন"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ডিভাইসটিকে ম্যানুয়ালি লক করা হয়েছে"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"শনাক্ত করা যায়নি"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"শনাক্ত করা যায়নি"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"\'ফেস আনলক\' ফিচার ব্যবহার করতে \'সেটিংস ও গোপনীয়তা\' বিকল্পে গিয়ে "<b>"ক্যামেরায় অ্যাক্সেস দিন"</b></string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-bs/strings.xml b/packages/SystemUI/res-keyguard/values-bs/strings.xml
index 99f796c..4a47157 100644
--- a/packages/SystemUI/res-keyguard/values-bs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bs/strings.xml
@@ -91,7 +91,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Lozinka je potrebna radi dodatne sigurnosti"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Uređaj je zaključao administrator"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Uređaj je ručno zaključan"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Nije prepoznato"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nije prepoznato"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Da koristite otključavanje licem, uključite "<b>"Pristup kameri"</b>" u meniju Postavke > Privatnost"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-ca/strings.xml b/packages/SystemUI/res-keyguard/values-ca/strings.xml
index fca5f12..9cc855a 100644
--- a/packages/SystemUI/res-keyguard/values-ca/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ca/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Cal introduir la contrasenya per disposar de més seguretat"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"L\'administrador ha bloquejat el dispositiu"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"El dispositiu s\'ha bloquejat manualment"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"No s\'ha reconegut"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"No s\'ha reconegut"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Per utilitzar Desbloqueig facial, activa "<b>"Accés a la càmera"</b>" a Configuració > Privadesa"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-cs/strings.xml b/packages/SystemUI/res-keyguard/values-cs/strings.xml
index 363601a..606bff5 100644
--- a/packages/SystemUI/res-keyguard/values-cs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-cs/strings.xml
@@ -93,7 +93,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Pro ještě lepší zabezpečení je vyžadováno heslo"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Zařízení je uzamknuto administrátorem"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Zařízení bylo ručně uzamčeno"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Nerozpoznáno"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nerozpoznáno"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Pokud chcete používat odemknutí obličejem, v Nastavení > Soukromí zapnetě "<b>"přístup k fotoaparátu"</b></string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-da/strings.xml b/packages/SystemUI/res-keyguard/values-da/strings.xml
index 38bcfb1..8f7b8d0 100644
--- a/packages/SystemUI/res-keyguard/values-da/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-da/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Der kræves en adgangskode som ekstra beskyttelse"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Enheden er blevet låst af administratoren"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Enheden blev låst manuelt"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Ikke genkendt"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Ikke genkendt"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Hvis du vil bruge ansigtslåsen, skal du aktivere "<b>"Kameraadgang"</b>" under Indstillinger > Privatliv"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-de/strings.xml b/packages/SystemUI/res-keyguard/values-de/strings.xml
index 5f12183..6391ed0 100644
--- a/packages/SystemUI/res-keyguard/values-de/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-de/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Zur Verbesserung der Sicherheit ist ein Passwort erforderlich"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Gerät vom Administrator gesperrt"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Gerät manuell gesperrt"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Nicht erkannt"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nicht erkannt"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Wenn du die Entsperrung per Gesichtserkennung verwenden möchtest, aktiviere in den Einstellungen unter „Datenschutz“ die Option "<b>"Kamerazugriff"</b></string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-el/strings.xml b/packages/SystemUI/res-keyguard/values-el/strings.xml
index 4783b3c..a5bbb9a 100644
--- a/packages/SystemUI/res-keyguard/values-el/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-el/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Απαιτείται κωδικός πρόσβασης για πρόσθετη ασφάλεια"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Η συσκευή κλειδώθηκε από τον διαχειριστή"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Η συσκευή κλειδώθηκε με μη αυτόματο τρόπο"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Δεν αναγνωρίστηκε"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Δεν αναγνωρίστηκε"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Για να χρησιμοποιήσετε τη λειτουργία Ξεκλείδωμα με το πρόσωπο, ενεργοποιήστε την επιλογή "<b>"Πρόσβαση στην κάμερα"</b>" από το μενού Ρυθμίσεις > Απόρρητο"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
index 702abca..abfe5be 100644
--- a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Password required for additional security"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Device locked by admin"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Device was locked manually"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Not recognised"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Not recognised"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"To use Face Unlock, turn on "<b>"Camera access"</b>" in Settings > Privacy"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
index 533d768..69bcf89 100644
--- a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Password required for additional security"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Device locked by admin"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Device was locked manually"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Not recognised"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Not recognised"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"To use Face Unlock, turn on "<b>"Camera access"</b>" in Settings > Privacy"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
index 702abca..abfe5be 100644
--- a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Password required for additional security"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Device locked by admin"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Device was locked manually"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Not recognised"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Not recognised"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"To use Face Unlock, turn on "<b>"Camera access"</b>" in Settings > Privacy"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
index 702abca..abfe5be 100644
--- a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Password required for additional security"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Device locked by admin"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Device was locked manually"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Not recognised"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Not recognised"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"To use Face Unlock, turn on "<b>"Camera access"</b>" in Settings > Privacy"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml b/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml
index 3cc356a..804b6ae 100644
--- a/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Password required for additional security"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Device locked by admin"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Device was locked manually"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Not recognized"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Not recognized"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"To use Face Unlock, turn on "<b>"Camera access"</b>" in Settings > Privacy"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
index b80978f..d9adc7c 100644
--- a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Se requiere la contraseña por razones de seguridad"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Dispositivo bloqueado por el administrador"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"El dispositivo se bloqueó de forma manual"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"No se reconoció"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"No se reconoció"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Para usar Desbloqueo facial, activa el "<b>"Acceso a la cámara"</b>" en Configuración y privacidad"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-es/strings.xml b/packages/SystemUI/res-keyguard/values-es/strings.xml
index a23b41a..3702be2 100644
--- a/packages/SystemUI/res-keyguard/values-es/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Debes introducir la contraseña como medida de seguridad adicional"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Dispositivo bloqueado por el administrador"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"El dispositivo se ha bloqueado manualmente"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"No se reconoce"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"No se reconoce"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Para usar Desbloqueo Facial, habilita el "<b>"acceso a la cámara"</b>" en Ajustes y privacidad"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-et/strings.xml b/packages/SystemUI/res-keyguard/values-et/strings.xml
index 5b1791f..9488054 100644
--- a/packages/SystemUI/res-keyguard/values-et/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-et/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Lisaturvalisuse huvides tuleb sisestada parool"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Administraator lukustas seadme"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Seade lukustati käsitsi"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Ei tuvastatud"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Ei tuvastatud"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Näoga avamise kasutamiseks lülitage menüüs Seaded > Privaatsus sisse "<b>"juurdepääs kaamerale"</b>"."</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-eu/strings.xml b/packages/SystemUI/res-keyguard/values-eu/strings.xml
index 5a4a9ef..41d467a 100644
--- a/packages/SystemUI/res-keyguard/values-eu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-eu/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Pasahitza behar da gailua babestuago izateko"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Administratzaileak blokeatu egin du gailua"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Eskuz blokeatu da gailua"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Ez da ezagutu"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Ez da ezagutu"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Aurpegi bidez desblokeatzeko aukera erabiltzeko, aktibatu "<b>"kamera atzitzeko baimena"</b>" Ezarpenak > Pribatutasuna atalean"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-fa/strings.xml b/packages/SystemUI/res-keyguard/values-fa/strings.xml
index a76c979..9d77608 100644
--- a/packages/SystemUI/res-keyguard/values-fa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fa/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"برای ایمنی بیشتر باید گذرواژه وارد شود"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"دستگاه توسط سرپرست سیستم قفل شده است"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"دستگاه بهصورت دستی قفل شده است"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"شناسایی نشد"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"شناسایی نشد"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"برای استفاده از «قفلگشایی با چهره»، "<b>"دسترسی به دوربین"</b>" را در «تنظیمات > حریمخصوصی» روشن کنید"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-fi/strings.xml b/packages/SystemUI/res-keyguard/values-fi/strings.xml
index 5cdcf97..2fbb8ab 100644
--- a/packages/SystemUI/res-keyguard/values-fi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fi/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Salasana vaaditaan suojauksen parantamiseksi."</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Järjestelmänvalvoja lukitsi laitteen."</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Laite lukittiin manuaalisesti"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Ei tunnistettu"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Ei tunnistettu"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Jos haluat käyttää kasvojentunnistusavausta, valitse Asetukset > Yksityisyys ja laita "<b>"Pääsy kameraan"</b>" päälle"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
index fadb4d9..da81aa3 100644
--- a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Le mot de passe est exigé pour plus de sécurité"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"L\'appareil a été verrouillé par l\'administrateur"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"L\'appareil a été verrouillé manuellement"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Doigt non reconnu"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Doigt non reconnu"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Pour utiliser le déverrouillage par reconnaissance faciale, activez l\'"<b>"accès à l\'appareil photo"</b>" dans Paramètres > Confidentialité"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-fr/strings.xml b/packages/SystemUI/res-keyguard/values-fr/strings.xml
index b7edf05..b34ae8c 100644
--- a/packages/SystemUI/res-keyguard/values-fr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Veuillez saisir le mot de passe pour renforcer la sécurité"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Appareil verrouillé par l\'administrateur"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Appareil verrouillé manuellement"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Non reconnu"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Non reconnu"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Pour utiliser Face Unlock, activez "<b>"Accès à l\'appareil photo"</b>" dans Paramètres > Confidentialité"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-gl/strings.xml b/packages/SystemUI/res-keyguard/values-gl/strings.xml
index 7c2320d..b1c14fe5 100644
--- a/packages/SystemUI/res-keyguard/values-gl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gl/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"É necesario o contrasinal para obter seguranza adicional"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"O administrador bloqueou o dispositivo"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"O dispositivo bloqueouse manualmente"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Non se recoñeceu"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Non se recoñeceu"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Para usar o desbloqueo facial, activa "<b>"Acceso á cámara"</b>" en Configuración > Privacidade"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-gu/strings.xml b/packages/SystemUI/res-keyguard/values-gu/strings.xml
index 4115d68..5dc4a1c 100644
--- a/packages/SystemUI/res-keyguard/values-gu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gu/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"વધારાની સુરક્ષા માટે પાસવર્ડ જરૂરી છે"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"વ્યવસ્થાપકે ઉપકરણ લૉક કરેલું છે"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ઉપકરણ મેન્યુઅલી લૉક કર્યું હતું"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"ઓળખાયેલ નથી"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ઓળખાયેલ નથી"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"ફેસ અનલૉક સુવિધાનો ઉપયોગ કરવા માટે, સેટિંગ > પ્રાઇવસીમાં જઈને "<b>"કૅમેરા ઍક્સેસ"</b>" ચાલુ કરો"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-hi/strings.xml b/packages/SystemUI/res-keyguard/values-hi/strings.xml
index ecc5050..69a9dc9 100644
--- a/packages/SystemUI/res-keyguard/values-hi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hi/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"अतिरिक्त सुरक्षा के लिए पासवर्ड ज़रूरी है"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"व्यवस्थापक ने डिवाइस को लॉक किया है"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"डिवाइस को मैन्युअल रूप से लॉक किया गया था"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"पहचान नहीं हो पाई"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"पहचान नहीं हो पाई"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"फ़ेस अनलॉक की सुविधा का इस्तेमाल करने के लिए, सेटिंग और निजता में जाकर, "<b>"कैमरे का ऐक्सेस"</b>" चालू करें"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-hr/strings.xml b/packages/SystemUI/res-keyguard/values-hr/strings.xml
index 5d02bba..de660d8 100644
--- a/packages/SystemUI/res-keyguard/values-hr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hr/strings.xml
@@ -91,7 +91,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Unesite zaporku radi dodatne sigurnosti"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Administrator je zaključao uređaj"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Uređaj je ručno zaključan"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Nije prepoznat"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nije prepoznato"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Da biste koristili otključavanje licem, uključite opciju "<b>"Pristup kameri"</b>" u odjeljku Postavke > Privatnost"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-hu/strings.xml b/packages/SystemUI/res-keyguard/values-hu/strings.xml
index 77d57c4..8854740 100644
--- a/packages/SystemUI/res-keyguard/values-hu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hu/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"A nagyobb biztonság érdekében jelszó szükséges"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"A rendszergazda zárolta az eszközt"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Az eszközt manuálisan lezárták"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Nem ismerhető fel"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nem ismerhető fel"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Az Arcalapú feloldás funkció használatához kapcsolja be a "<b>"Hozzáférés a kamerához"</b>" beállítást a Beállítások > Adatvédelem szakaszban."</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-hy/strings.xml b/packages/SystemUI/res-keyguard/values-hy/strings.xml
index fb1901a..94fdedd 100644
--- a/packages/SystemUI/res-keyguard/values-hy/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hy/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Անվտանգության նկատառումներից ելնելով անհրաժեշտ է մուտքագրել գաղտնաբառը"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Սարքը կողպված է ադմինիստրատորի կողմից"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Սարքը կողպվել է ձեռքով"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Չհաջողվեց ճանաչել"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Չհաջողվեց ճանաչել"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Դեմքով ապակողպումն օգտագործելու համար անցեք Կարգավորումներ > Գաղտնիություն և տրամադրեք "<b>"տեսախցիկն օգտագործելու թույլտվություն"</b>"։"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-in/strings.xml b/packages/SystemUI/res-keyguard/values-in/strings.xml
index e4e4d1c..b16031a 100644
--- a/packages/SystemUI/res-keyguard/values-in/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-in/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Sandi diperlukan untuk keamanan tambahan"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Perangkat dikunci oleh admin"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Perangkat dikunci secara manual"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Tidak dikenali"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Tidak dikenali"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Untuk menggunakan Face Unlock, aktifkan "<b>"Akses kamera"</b>" di Setelan > Privasi"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-is/strings.xml b/packages/SystemUI/res-keyguard/values-is/strings.xml
index ff6bbee..8f6b18b 100644
--- a/packages/SystemUI/res-keyguard/values-is/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-is/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Aðgangsorðs er krafist af öryggisástæðum"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Kerfisstjóri læsti tæki"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Tækinu var læst handvirkt"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Þekktist ekki"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Þekktist ekki"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Þú verður að kveikja á "<b>"aðgangi að myndavél"</b>" í „Stillingar > persónuvernd“ til að nota andlitskenni"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml
index 7ce2545..06db7b7 100644
--- a/packages/SystemUI/res-keyguard/values-it/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-it/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Password obbligatoria per maggiore sicurezza"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Dispositivo bloccato dall\'amministratore"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Il dispositivo è stato bloccato manualmente"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Non riconosciuto"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Non riconosciuto"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Per utilizzare lo sblocco con il volto, attiva "<b>"l\'accesso alla fotocamera"</b>" in Impostazioni > Privacy"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-iw/strings.xml b/packages/SystemUI/res-keyguard/values-iw/strings.xml
index 2551e22..ce43b15 100644
--- a/packages/SystemUI/res-keyguard/values-iw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-iw/strings.xml
@@ -93,7 +93,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"יש להזין סיסמה כדי להגביר את רמת האבטחה"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"המנהל של המכשיר נהל אותו"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"המכשיר ננעל באופן ידני"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"לא זוהתה"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"לא זוהתה"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"כדי להשתמש בתכונה \'פתיחה ע\"י זיהוי הפנים\', יש להפעיל את ה"<b>"גישה למצלמה"</b>" בהגדרות > פרטיות"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-ja/strings.xml b/packages/SystemUI/res-keyguard/values-ja/strings.xml
index fca4549..07b3c87 100644
--- a/packages/SystemUI/res-keyguard/values-ja/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ja/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"追加の確認のためパスワードが必要です"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"デバイスは管理者によりロックされています"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"デバイスは手動でロックされました"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"認識されませんでした"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"認識されませんでした"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"顔認証を使用するには、[設定] > [プライバシー] で"<b>"カメラへのアクセス"</b>"を有効にしてください"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-ka/strings.xml b/packages/SystemUI/res-keyguard/values-ka/strings.xml
index c366abe..f2341c6 100644
--- a/packages/SystemUI/res-keyguard/values-ka/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ka/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"დამატებითი უსაფრთხოებისთვის საჭიროა პაროლის შეყვანა"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"მოწყობილობა ჩაკეტილია ადმინისტრატორის მიერ"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"მოწყობილობა ხელით ჩაიკეტა"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"არ არის ამოცნობილი"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"არ არის ამოცნობილი"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"იმისთვის, რომ სახით განბლოკვით ისარგებლოთ, ჩართეთ "<b>"კამერაზე წვდომა"</b>" პარამეტრებსა და კონფიდენციალურობაში"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-kk/strings.xml b/packages/SystemUI/res-keyguard/values-kk/strings.xml
index 779fa44..20bba0f 100644
--- a/packages/SystemUI/res-keyguard/values-kk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kk/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Қауіпсіздікті күшейту үшін құпия сөзді енгізу қажет"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Құрылғыны әкімші құлыптаған"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Құрылғы қолмен құлыпталды"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Танылмады"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Танылмады"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Face Unlock функциясын пайдалану үшін \"Параметрлер > Құпиялылық\" бөлімінен "<b>"Камераны пайдалану рұқсатын"</b>" қосыңыз."</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-km/strings.xml b/packages/SystemUI/res-keyguard/values-km/strings.xml
index 1a1f808..236c318 100644
--- a/packages/SystemUI/res-keyguard/values-km/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-km/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"តម្រូវឲ្យបញ្ចូលពាក្យសម្ងាត់ ដើម្បីទទួលបានសុវត្ថិភាពបន្ថែម"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ឧបករណ៍ត្រូវបានចាក់សោដោយអ្នកគ្រប់គ្រង"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ឧបករណ៍ត្រូវបានចាក់សោដោយអ្នកប្រើផ្ទាល់"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"មិនអាចសម្គាល់បានទេ"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"មិនអាចសម្គាល់បានទេ"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"ដើម្បីប្រើមុខងារដោះសោតាមទម្រង់មុខ សូមបើក"<b>"ការចូលប្រើកាមេរ៉ា"</b>"នៅក្នុងការកំណត់ > ឯកជនភាព"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-kn/strings.xml b/packages/SystemUI/res-keyguard/values-kn/strings.xml
index 0eb48c5..716cbf6 100644
--- a/packages/SystemUI/res-keyguard/values-kn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kn/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"ಹೆಚ್ಚುವರಿ ಭದ್ರತೆಗಾಗಿ ಪಾಸ್ವರ್ಡ್ ಅಗತ್ಯವಿದೆ"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ನಿರ್ವಾಹಕರು ಸಾಧನವನ್ನು ಲಾಕ್ ಮಾಡಿದ್ದಾರೆ"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ಸಾಧನವನ್ನು ಹಸ್ತಚಾಲಿತವಾಗಿ ಲಾಕ್ ಮಾಡಲಾಗಿದೆ"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"ಗುರುತಿಸಲಾಗಿಲ್ಲ"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ಗುರುತಿಸಲಾಗಿಲ್ಲ"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"ಫೇಸ್ ಅನ್ಲಾಕ್ ಬಳಸಲು, ಸೆಟ್ಟಿಂಗ್ಗಳು > ಗೌಪ್ಯತೆ ಎಂಬಲ್ಲಿ "<b>"ಕ್ಯಾಮರಾ ಪ್ರವೇಶವನ್ನು"</b>" ಆನ್ ಮಾಡಿ"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-ko/strings.xml b/packages/SystemUI/res-keyguard/values-ko/strings.xml
index 168752c..e698017 100644
--- a/packages/SystemUI/res-keyguard/values-ko/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ko/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"보안 강화를 위해 비밀번호가 필요합니다."</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"관리자가 기기를 잠갔습니다."</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"기기가 수동으로 잠금 설정되었습니다."</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"인식할 수 없음"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"인식할 수 없음"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"얼굴 인식 잠금 해제를 사용하려면 설정 > 개인 정보 보호에서 "<b>"카메라 액세스"</b>"를 사용 설정하세요."</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-ky/strings.xml b/packages/SystemUI/res-keyguard/values-ky/strings.xml
index 14bee97..1df29e1b 100644
--- a/packages/SystemUI/res-keyguard/values-ky/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ky/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Коопсуздукту бекемдөө үчүн сырсөз талап кылынат"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Түзмөктү администратор кулпулап койгон"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Түзмөк кол менен кулпуланды"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Таанылган жок"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Таанылган жок"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Жүзүнөн таанып ачуу функциясын колдонуу үчүн Жөндөөлөр > Купуялык бөлүмүнө өтүп, "<b>"Камераны колдонууну"</b>" күйгүзүңүз"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-lo/strings.xml b/packages/SystemUI/res-keyguard/values-lo/strings.xml
index 732ac1f..a01cd7c 100644
--- a/packages/SystemUI/res-keyguard/values-lo/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lo/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"ຈຳເປັນຕ້ອງມີລະຫັດຜ່ານເພື່ອຄວາມປອດໄພເພີ່ມເຕີມ"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ອຸປະກອນຖືກລັອກໂດຍຜູ້ເບິ່ງແຍງລະບົບ"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ອຸປະກອນຖືກສັ່ງໃຫ້ລັອກ"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"ບໍ່ຮູ້ຈັກ"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ບໍ່ຮູ້ຈັກ"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"ເພື່ອໃຊ້ການປົດລັອກດ້ວຍໜ້າ, ກະລຸນາເປີດໃຊ້ "<b>"ສິດເຂົ້າເຖິງກ້ອງຖ່າຍຮູບ"</b>" ໃນການຕັ້ງຄ່າ > ຄວາມເປັນສ່ວນຕົວ"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-lt/strings.xml b/packages/SystemUI/res-keyguard/values-lt/strings.xml
index 1379529..64e600e 100644
--- a/packages/SystemUI/res-keyguard/values-lt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lt/strings.xml
@@ -93,7 +93,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Norint užtikrinti papildomą saugą būtinas slaptažodis"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Įrenginį užrakino administratorius"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Įrenginys užrakintas neautomatiškai"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Neatpažinta"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Neatpažinta"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Jei norite naudoti atrakinimą pagal veidą, įjunkite parinktį "<b>"Prieiga prie fotoaparato"</b>" skiltyje „Nustatymai“ > „Privatumas“"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-lv/strings.xml b/packages/SystemUI/res-keyguard/values-lv/strings.xml
index e0c237a..9cd30a1 100644
--- a/packages/SystemUI/res-keyguard/values-lv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lv/strings.xml
@@ -91,7 +91,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Papildu drošībai ir jāievada parole."</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Administrators bloķēja ierīci."</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Ierīce tika bloķēta manuāli."</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Nav atpazīts"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nav atpazīts"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Lai izmantotu autorizāciju pēc sejas, sadaļā Iestatījumi > Konfidencialitāte ieslēdziet opciju "<b>"Piekļuve kamerai"</b>"."</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-mk/strings.xml b/packages/SystemUI/res-keyguard/values-mk/strings.xml
index d68517b..c5cad18 100644
--- a/packages/SystemUI/res-keyguard/values-mk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mk/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Потребна е лозинка за дополнителна безбедност"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Уредот е заклучен од администраторот"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Уредот е заклучен рачно"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Непознат"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Непознат"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"За да користите „Отклучување со лик“, вклучете "<b>"Пристап до камерата"</b>" во „Поставки > Приватност“"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-ml/strings.xml b/packages/SystemUI/res-keyguard/values-ml/strings.xml
index 6bd0ebe..2b0efc8 100644
--- a/packages/SystemUI/res-keyguard/values-ml/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ml/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"അധിക സുരക്ഷയ്ക്ക് പാസ്വേഡ് ആവശ്യമാണ്"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ഉപകരണം അഡ്മിൻ ലോക്കുചെയ്തു"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ഉപകരണം നേരിട്ട് ലോക്കുചെയ്തു"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"തിരിച്ചറിയുന്നില്ല"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"തിരിച്ചറിയുന്നില്ല"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"ഫെയ്സ് അൺലോക്ക് ഉപയോഗിക്കാൻ, ക്രമീകരണം > സ്വകാര്യത എന്നതിൽ "<b>"ക്യാമറാ ആക്സസ്"</b>" ഓണാക്കുക"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-mn/strings.xml b/packages/SystemUI/res-keyguard/values-mn/strings.xml
index 0e4e261..82fbaf1 100644
--- a/packages/SystemUI/res-keyguard/values-mn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mn/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Аюулгүй байдлын үүднээс нууц үг оруулах шаардлагатай"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Админ төхөөрөмжийг түгжсэн"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Төхөөрөмжийг гараар түгжсэн"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Таньж чадсангүй"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Таньж чадсангүй"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Царайгаар түгжээ тайлахыг ашиглахын тулд Тохиргоо > Нууцлал хэсэгт "<b>" Камерын хандалтыг "</b>" асаана уу"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-mr/strings.xml b/packages/SystemUI/res-keyguard/values-mr/strings.xml
index a7bc880..012c83b 100644
--- a/packages/SystemUI/res-keyguard/values-mr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mr/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"अतिरिक्त सुरक्षिततेसाठी पासवर्ड आवश्यक आहे"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"प्रशासकाद्वारे लॉक केलेले डिव्हाइस"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"डिव्हाइस मॅन्युअली लॉक केले होते"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"ओळखले नाही"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ओळखले नाही"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"फेस अनलॉक वापरण्यासाठी, सेटिंग्ज > गोपनीयता येथे "<b>"कॅमेरा अॅक्सेस"</b>" सुरू करा"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-ms/strings.xml b/packages/SystemUI/res-keyguard/values-ms/strings.xml
index a2e26a8..29672c1 100644
--- a/packages/SystemUI/res-keyguard/values-ms/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ms/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Kata laluan diperlukan untuk keselamatan tambahan"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Peranti dikunci oleh pentadbir"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Peranti telah dikunci secara manual"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Tidak dikenali"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Tidak dikenali"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Untuk menggunakan Buka Kunci Wajah, hidupkan "<b>"akses Kamera"</b>" dalam Tetapan > Privasi"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-my/strings.xml b/packages/SystemUI/res-keyguard/values-my/strings.xml
index a47f597..91dcb9c 100644
--- a/packages/SystemUI/res-keyguard/values-my/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-my/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"ပိုမို၍ လုံခြုံမှု ရှိစေရန် စကားဝှက် လိုအပ်ပါသည်"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"စက်ပစ္စည်းကို စီမံခန့်ခွဲသူက လော့ခ်ချထားပါသည်"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"စက်ပစ္စည်းကို ကိုယ်တိုင်ကိုယ်ကျ လော့ခ်ချထားခဲ့သည်"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"မသိ"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"မသိ"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"မျက်နှာပြ လော့ခ်ဖွင့်ခြင်းကို သုံးရန် "<b>"ကင်မရာ သုံးခွင့်"</b>" ကို ‘ဆက်တင်များ > ကန့်သတ်ဆက်တင်’ တွင်ဖွင့်ပါ"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-nb/strings.xml b/packages/SystemUI/res-keyguard/values-nb/strings.xml
index 1f3bded..b312706 100644
--- a/packages/SystemUI/res-keyguard/values-nb/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nb/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Du må skrive inn passordet for ekstra sikkerhet"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Enheten er låst av administratoren"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Enheten ble låst manuelt"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Ikke gjenkjent"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Ikke gjenkjent"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"For å bruke ansiktslås, slå på "<b>"Kameratilgang"</b>" i Innstillinger > Personvern"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml
index 762e0df..39548de 100644
--- a/packages/SystemUI/res-keyguard/values-ne/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"अतिरिक्त सुरक्षाको लागि पासवर्ड आवश्यक छ"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"प्रशासकले यन्त्रलाई लक गर्नुभएको छ"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"यन्त्रलाई म्यानुअल तरिकाले लक गरिएको थियो"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"पहिचान भएन"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"पहिचान भएन"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"फेस अनलक प्रयोग गर्न \"सेटिङ तथा गोपनीयता\" मा गई "<b>"क्यामेरा प्रयोग गर्ने अनुमति"</b>" दिनुहोस्"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-nl/strings.xml b/packages/SystemUI/res-keyguard/values-nl/strings.xml
index 6ed0960..e97fde4 100644
--- a/packages/SystemUI/res-keyguard/values-nl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nl/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Wachtwoord vereist voor extra beveiliging"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Apparaat vergrendeld door beheerder"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Apparaat is handmatig vergrendeld"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Niet herkend"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Niet herkend"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Als je Ontgrendelen via gezichtsherkenning wilt gebruiken, zet je "<b>"Cameratoegang"</b>" aan via Instellingen > Privacy"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-or/strings.xml b/packages/SystemUI/res-keyguard/values-or/strings.xml
index ef2a739..edf5d99 100644
--- a/packages/SystemUI/res-keyguard/values-or/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-or/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"ଅତିରିକ୍ତ ସୁରକ୍ଷା ପାଇଁ ପାସ୍ୱର୍ଡ ଆବଶ୍ୟକ"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ଡିଭାଇସ୍ ଆଡମିନଙ୍କ ଦ୍ୱାରା ଲକ୍ କରାଯାଇଛି"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ଡିଭାଇସ୍ ମାନୁଆଲ ଭାବେ ଲକ୍ କରାଗଲା"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"ଚିହ୍ନଟ ହେଲାନାହିଁ"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ଚିହ୍ନଟ ହେଲାନାହିଁ"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"ଫେସ ଅନଲକ ବ୍ୟବହାର କରିବା ପାଇଁ, ସେଟିଂସ ଏବଂ ଗୋପନୀୟତାରେ "<b>"କ୍ୟାମେରା ଆକ୍ସେସ"</b>"କୁ ଚାଲୁ କରନ୍ତୁ"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-pa/strings.xml b/packages/SystemUI/res-keyguard/values-pa/strings.xml
index 36c0558..858682c 100644
--- a/packages/SystemUI/res-keyguard/values-pa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pa/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"ਵਧੀਕ ਸੁਰੱਖਿਆ ਲਈ ਪਾਸਵਰਡ ਦੀ ਲੋੜ ਹੈ"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਡੀਵਾਈਸ ਨੂੰ ਲਾਕ ਕੀਤਾ ਗਿਆ"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ਡੀਵਾਈਸ ਨੂੰ ਹੱਥੀਂ ਲਾਕ ਕੀਤਾ ਗਿਆ"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"ਪਛਾਣ ਨਹੀਂ ਹੋਈ"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ਪਛਾਣ ਨਹੀਂ ਹੋਈ"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"ਫ਼ੇਸ ਅਣਲਾਕ ਨੂੰ ਵਰਤਣ ਲਈ, ਸੈਟਿੰਗਾਂ > ਪਰਦੇਦਾਰੀ ਵਿੱਚ ਜਾ ਕੇ "<b>"ਕੈਮਰਾ ਪਹੁੰਚ"</b>" ਨੂੰ ਚਾਲੂ ਕਰੋ"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-pl/strings.xml b/packages/SystemUI/res-keyguard/values-pl/strings.xml
index 5f4152c..f1a53e0 100644
--- a/packages/SystemUI/res-keyguard/values-pl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pl/strings.xml
@@ -93,7 +93,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Dla większego bezpieczeństwa musisz podać hasło"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Urządzenie zablokowane przez administratora"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Urządzenie zostało zablokowane ręcznie"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Nie rozpoznano"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nie rozpoznano"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Aby używać rozpoznawania twarzy, włącz "<b>"dostęp do aparatu"</b>" w Ustawieniach i prywatności"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
index 05f90aa..aecc5f2 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"A senha é necessária para aumentar a segurança"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Dispositivo bloqueado pelo administrador"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"O dispositivo foi bloqueado manualmente"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Não reconhecido"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Não reconhecido"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Para usar o Desbloqueio facial, ative o "<b>"acesso à câmera"</b>" em Configurações > Privacidade"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
index 42d2d9a..c3486bb 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Para segurança adicional, é necessária uma palavra-passe"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Dispositivo bloqueado pelo gestor"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"O dispositivo foi bloqueado manualmente"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Não reconhecido."</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Não reconhecido."</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Para utilizar o Desbloqueio facial, ative o "<b>"Acesso à câmara"</b>" em Definições > Privacidade"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-pt/strings.xml b/packages/SystemUI/res-keyguard/values-pt/strings.xml
index 05f90aa..aecc5f2 100644
--- a/packages/SystemUI/res-keyguard/values-pt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"A senha é necessária para aumentar a segurança"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Dispositivo bloqueado pelo administrador"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"O dispositivo foi bloqueado manualmente"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Não reconhecido"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Não reconhecido"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Para usar o Desbloqueio facial, ative o "<b>"acesso à câmera"</b>" em Configurações > Privacidade"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-ro/strings.xml b/packages/SystemUI/res-keyguard/values-ro/strings.xml
index 3ba168c..04fe6be 100644
--- a/packages/SystemUI/res-keyguard/values-ro/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ro/strings.xml
@@ -91,7 +91,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Parola este necesară pentru securitate suplimentară"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Dispozitiv blocat de administrator"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Dispozitivul a fost blocat manual"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Nu este recunoscută"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nu este recunoscut"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Pentru a folosi Deblocarea facială, activați "<b>"Accesul la cameră"</b>" în Setări și confidențialitate"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-ru/strings.xml b/packages/SystemUI/res-keyguard/values-ru/strings.xml
index 1dc6ee2..364c8b7 100644
--- a/packages/SystemUI/res-keyguard/values-ru/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ru/strings.xml
@@ -93,7 +93,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"В качестве дополнительной меры безопасности введите пароль"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Устройство заблокировано администратором"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Устройство было заблокировано вручную"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Не распознано"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Не распознано"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Чтобы использовать фейсконтроль, разрешите "<b>"доступ к камере"</b>". Для этого перейдите в настройки и нажмите \"Конфиденциальность\"."</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-si/strings.xml b/packages/SystemUI/res-keyguard/values-si/strings.xml
index f4b08f2..5e934cc 100644
--- a/packages/SystemUI/res-keyguard/values-si/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-si/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"අමතර ආරක්ෂාව සඳහා මුරපදය අවශ්යයි"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ඔබගේ පරිපාලක විසින් උපාංගය අගුළු දමා ඇත"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"උපාංගය හස්තීයව අගුලු දමන ලදී"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"හඳුනා නොගන්නා ලදී"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"හඳුනා නොගන්නා ලදී"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"මුහුණෙන් අගුලු හැරීම භාවිත කිරීමට, සැකසීම් > පෞද්ගලිකත්වය තුළ "<b>"කැමරා ප්රවේශය"</b>" ක්රියාත්මක කරන්න"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-sk/strings.xml b/packages/SystemUI/res-keyguard/values-sk/strings.xml
index 8faa85b..187683f 100644
--- a/packages/SystemUI/res-keyguard/values-sk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sk/strings.xml
@@ -93,7 +93,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Na ďalšie zabezpečenie musíte zadať heslo"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Zariadenie zamkol správca"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Zariadenie bolo uzamknuté ručne"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Nerozpoznané"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nerozpoznané"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Ak chcete používať odomknutie tvárou, v sekcii Nastavenia > Ochrana súkromia zapnite "<b>"prístup ku kamere"</b></string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-sl/strings.xml b/packages/SystemUI/res-keyguard/values-sl/strings.xml
index b9b74d5..17c590f 100644
--- a/packages/SystemUI/res-keyguard/values-sl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sl/strings.xml
@@ -93,7 +93,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Zaradi dodatne varnosti morate vnesti geslo"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Napravo je zaklenil skrbnik"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Naprava je bila ročno zaklenjena"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Ni prepoznano"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Ni prepoznano"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Če želite uporabljati odklepanje z obrazom, v meniju »Nastavitve« > »Zasebnost« vklopite možnost "<b>"Dostop do fotoaparata"</b>"."</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-sq/strings.xml b/packages/SystemUI/res-keyguard/values-sq/strings.xml
index d46ac78..16adc13 100644
--- a/packages/SystemUI/res-keyguard/values-sq/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sq/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Kërkohet fjalëkalimi për më shumë siguri"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Pajisja është e kyçur nga administratori"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Pajisja është kyçur manualisht"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Nuk njihet"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nuk njihet"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Për të përdorur \"Shkyçjen me fytyrë\", aktivizo "<b>"Qasjen te kamera"</b>" te \"Cilësimet\" > \"Privatësia\""</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-sr/strings.xml b/packages/SystemUI/res-keyguard/values-sr/strings.xml
index 675b934..2fb2939 100644
--- a/packages/SystemUI/res-keyguard/values-sr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sr/strings.xml
@@ -91,7 +91,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Треба да унесете лозинку ради додатне безбедности"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Администратор је закључао уређај"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Уређај је ручно закључан"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Није препознат"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Није препознат"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Да бисте користили откључавање лицем, укључите "<b>"приступ камери"</b>" у одељку Подешавања > Приватност"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-sv/strings.xml b/packages/SystemUI/res-keyguard/values-sv/strings.xml
index 09b177a..166be1b 100644
--- a/packages/SystemUI/res-keyguard/values-sv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sv/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Du måste ange lösenord för ytterligare säkerhet"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Administratören har låst enheten"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Enheten har låsts manuellt"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Identifierades inte"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Identifierades inte"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Om du vill använda ansiktslås aktiverar du "<b>"Kameraåtkomst"</b>" i Inställningar > Integritet"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-sw/strings.xml b/packages/SystemUI/res-keyguard/values-sw/strings.xml
index b44b65d..193bb60 100644
--- a/packages/SystemUI/res-keyguard/values-sw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sw/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Nenosiri linahitajika ili kuongeza usalama."</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Msimamizi amefunga kifaa"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Umefunga kifaa mwenyewe"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Haitambuliwi"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Haitambuliwi"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Ili utumie kipengele cha kufungua kwa uso, washa kipengele cha "<b>"ufikiaji wa Kamera"</b>" katika Mipangilio na Faragha"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-ta/strings.xml b/packages/SystemUI/res-keyguard/values-ta/strings.xml
index 1708377..cfa865a 100644
--- a/packages/SystemUI/res-keyguard/values-ta/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ta/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"கூடுதல் பாதுகாப்பிற்கு, கடவுச்சொல்லை உள்ளிட வேண்டும்"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"நிர்வாகி சாதனத்தைப் பூட்டியுள்ளார்"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"பயனர் சாதனத்தைப் பூட்டியுள்ளார்"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"அடையாளங்காணபடவில்லை"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"அடையாளங்காணபடவில்லை"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"முகம் காட்டித் திறத்தல் அம்சத்தைப் பயன்படுத்த, அமைப்புகள் > தனியுரிமை என்பதற்குச் சென்று "<b>"கேமரா அணுகலை"</b>" இயக்கவும்"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-te/strings.xml b/packages/SystemUI/res-keyguard/values-te/strings.xml
index 2a1f62f..dd42d77 100644
--- a/packages/SystemUI/res-keyguard/values-te/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-te/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"అదనపు సెక్యూరిటీ కోసం పాస్వర్డ్ను ఎంటర్ చేయాలి"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"పరికరం నిర్వాహకుల ద్వారా లాక్ చేయబడింది"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"పరికరం మాన్యువల్గా లాక్ చేయబడింది"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"గుర్తించలేదు"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"గుర్తించలేదు"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"ఫేస్ అన్లాక్ను ఉపయోగించడానికి, సెట్టింగ్లు > గోప్యతలో "<b>"కెమెరా యాక్సెస్"</b>"ను ఆన్ చేయండి"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-th/strings.xml b/packages/SystemUI/res-keyguard/values-th/strings.xml
index 57a6a9f..10bdd0c 100644
--- a/packages/SystemUI/res-keyguard/values-th/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-th/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"ต้องป้อนรหัสผ่านเพื่อความปลอดภัยเพิ่มเติม"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ผู้ดูแลระบบล็อกอุปกรณ์"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"มีการล็อกอุปกรณ์ด้วยตัวเอง"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"ไม่รู้จัก"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ไม่รู้จัก"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"หากต้องการใช้ปลดล็อกด้วยใบหน้า ให้เปิด"<b>"การเข้าถึงกล้อง"</b>"ในการตั้งค่าและความเป็นส่วนตัว"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-tl/strings.xml b/packages/SystemUI/res-keyguard/values-tl/strings.xml
index cd2fc68..85fcb7a 100644
--- a/packages/SystemUI/res-keyguard/values-tl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-tl/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Kinakailangan ang password para sa karagdagang seguridad"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Na-lock ng admin ang device"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Manual na na-lock ang device"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Hindi nakilala"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Hindi nakilala"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Para magamit ang Pag-unlock Gamit ang Mukha, i-on ang "<b>"Access sa camera"</b>" sa Mga Setting > Privacy"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-tr/strings.xml b/packages/SystemUI/res-keyguard/values-tr/strings.xml
index 0435224..e9c3d5a 100644
--- a/packages/SystemUI/res-keyguard/values-tr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-tr/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Ek güvenlik için şifre gerekir"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Cihaz, yönetici tarafından kilitlendi"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Cihazın manuel olarak kilitlendi"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Tanınmadı"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Tanınmadı"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Yüz Tanıma Kilidi\'ni kullanmak için Ayarlar > Gizlilik bölümünden "<b>"Kamera erişimi"</b>"\'ni açın"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-uk/strings.xml b/packages/SystemUI/res-keyguard/values-uk/strings.xml
index 96b53bf..ae2131c 100644
--- a/packages/SystemUI/res-keyguard/values-uk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uk/strings.xml
@@ -93,7 +93,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Для додаткового захисту потрібно ввести пароль"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Адміністратор заблокував пристрій"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Пристрій заблоковано вручну"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Не розпізнано"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Не розпізнано"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Щоб використовувати фейсконтроль, увімкніть "<b>"Доступ до камери"</b>" в розділі \"Налаштування\" > \"Конфіденційність\""</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-ur/strings.xml b/packages/SystemUI/res-keyguard/values-ur/strings.xml
index 18fc02f..3e1245e 100644
--- a/packages/SystemUI/res-keyguard/values-ur/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ur/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"اضافی سیکیورٹی کیلئے پاس ورڈ درکار ہے"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"آلہ منتظم کی جانب سے مقفل ہے"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"آلہ کو دستی طور پر مقفل کیا گیا تھا"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"تسلیم شدہ نہیں ہے"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"تسلیم شدہ نہیں ہے"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"فیس اَنلاک کا استعمال کرنے کے لیے، ترتیبات اور رازداری میں "<b>"کیمرے تک رسائی"</b>" کو آن کریں"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-uz/strings.xml b/packages/SystemUI/res-keyguard/values-uz/strings.xml
index 733347b..e116919 100644
--- a/packages/SystemUI/res-keyguard/values-uz/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uz/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Qo‘shimcha xavfsizlik chorasi sifatida parol talab qilinadi"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Qurilma administrator tomonidan bloklangan"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Qurilma qo‘lda qulflangan"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Aniqlanmadi"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Aniqlanmadi"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Yuz bilan ochish uchun Sozlamalar va maxfiylik orqali "<b>"kameraga kirishga ruxsat bering"</b></string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-vi/strings.xml b/packages/SystemUI/res-keyguard/values-vi/strings.xml
index 1a853ea..15e35c4 100644
--- a/packages/SystemUI/res-keyguard/values-vi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-vi/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Yêu cầu mật khẩu để bảo mật thêm"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Thiết bị đã bị quản trị viên khóa"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Thiết bị đã bị khóa theo cách thủ công"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Không nhận dạng được"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Không nhận dạng được"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Để dùng tính năng Mở khoá bằng khuôn mặt, hãy bật tuỳ chọn "<b>"Truy cập máy ảnh"</b>" trong phần Cài đặt > Quyền riêng tư"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
index 81ad96a..0deee177 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"需要输入密码以进一步确保安全"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"管理员已锁定设备"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"此设备已手动锁定"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"无法识别"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"无法识别"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"如需使用人脸解锁功能,请在“设置”>“隐私权”中开启"<b>"摄像头使用权限"</b></string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
index eca1028..145bd2b 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"請務必輸入密碼,以進一步確保安全"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"裝置已由管理員鎖定"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"使用者已手動將裝置上鎖"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"未能識別"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"未能識別"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"如要使用「面孔解鎖」,請在 [設定] > [私隱] 開啟"<b>"相機存取權"</b></string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
index 50ac79d..f34f78e 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"請輸入密碼,以進一步確保資訊安全"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"管理員已鎖定裝置"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"裝置已手動鎖定"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"無法識別"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"無法識別"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"如要使用人臉解鎖功能,請前往「設定」>「隱私權」開啟"<b>"攝影機存取權"</b></string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values-zu/strings.xml b/packages/SystemUI/res-keyguard/values-zu/strings.xml
index ab413bf..76e0580 100644
--- a/packages/SystemUI/res-keyguard/values-zu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zu/strings.xml
@@ -89,7 +89,6 @@
<string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Iphasiwedi idingelwa ukuvikela okungeziwe"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Idivayisi ikhiywe ngumlawuli"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Idivayisi ikhiywe ngokwenza"</string>
- <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Akwaziwa"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Akwaziwa"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Ukuze usebenzise Ukuvula ngobuso, vula "<b>"Ukufinyelela kwekhamera"</b>" kokuthi Amasethingi > Ubumfihlo"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
diff --git a/packages/SystemUI/res-keyguard/values/config.xml b/packages/SystemUI/res-keyguard/values/config.xml
index e824443..a25ab51 100644
--- a/packages/SystemUI/res-keyguard/values/config.xml
+++ b/packages/SystemUI/res-keyguard/values/config.xml
@@ -28,5 +28,6 @@
<!-- Will display the bouncer on one side of the display, and the current user icon and
user switcher on the other side -->
<bool name="config_enableBouncerUserSwitcher">false</bool>
-
+ <!-- Time to be considered a consecutive fingerprint failure in ms -->
+ <integer name="fp_consecutive_failure_time_ms">3500</integer>
</resources>
diff --git a/packages/SystemUI/res/color-night/qs_detail_progress_track.xml b/packages/SystemUI/res/color-night/qs_detail_progress_track.xml
deleted file mode 100644
index c56382e..0000000
--- a/packages/SystemUI/res/color-night/qs_detail_progress_track.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <!-- I really don't want to define this, but the View that uses this asset uses both the
- light and dark accent colors. -->
- <item android:alpha="0.6" android:drawable="@*android:color/accent_device_default_light" />
-</selector>
diff --git a/packages/SystemUI/res/color/qs_detail_progress_track.xml b/packages/SystemUI/res/color/qs_detail_progress_track.xml
deleted file mode 100644
index d86119f..0000000
--- a/packages/SystemUI/res/color/qs_detail_progress_track.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <!-- I really don't want to define this, but the View that uses this asset uses both the
- light and dark accent colors. -->
- <item android:alpha="0.6" android:drawable="@*android:color/accent_device_default_dark" />
-</selector>
diff --git a/packages/SystemUI/res/drawable/ic_account_circle.xml b/packages/SystemUI/res/drawable/ic_account_circle.xml
new file mode 100644
index 0000000..5ca99f3
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_account_circle.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M5.85,17.1Q7.125,16.125 8.7,15.562Q10.275,15 12,15Q13.725,15 15.3,15.562Q16.875,16.125 18.15,17.1Q19.025,16.075 19.513,14.775Q20,13.475 20,12Q20,8.675 17.663,6.337Q15.325,4 12,4Q8.675,4 6.338,6.337Q4,8.675 4,12Q4,13.475 4.488,14.775Q4.975,16.075 5.85,17.1ZM12,13Q10.525,13 9.512,11.988Q8.5,10.975 8.5,9.5Q8.5,8.025 9.512,7.012Q10.525,6 12,6Q13.475,6 14.488,7.012Q15.5,8.025 15.5,9.5Q15.5,10.975 14.488,11.988Q13.475,13 12,13ZM12,22Q9.925,22 8.1,21.212Q6.275,20.425 4.925,19.075Q3.575,17.725 2.788,15.9Q2,14.075 2,12Q2,9.925 2.788,8.1Q3.575,6.275 4.925,4.925Q6.275,3.575 8.1,2.787Q9.925,2 12,2Q14.075,2 15.9,2.787Q17.725,3.575 19.075,4.925Q20.425,6.275 21.212,8.1Q22,9.925 22,12Q22,14.075 21.212,15.9Q20.425,17.725 19.075,19.075Q17.725,20.425 15.9,21.212Q14.075,22 12,22ZM12,20Q13.325,20 14.5,19.613Q15.675,19.225 16.65,18.5Q15.675,17.775 14.5,17.387Q13.325,17 12,17Q10.675,17 9.5,17.387Q8.325,17.775 7.35,18.5Q8.325,19.225 9.5,19.613Q10.675,20 12,20ZM12,11Q12.65,11 13.075,10.575Q13.5,10.15 13.5,9.5Q13.5,8.85 13.075,8.425Q12.65,8 12,8Q11.35,8 10.925,8.425Q10.5,8.85 10.5,9.5Q10.5,10.15 10.925,10.575Q11.35,11 12,11ZM12,9.5Q12,9.5 12,9.5Q12,9.5 12,9.5Q12,9.5 12,9.5Q12,9.5 12,9.5Q12,9.5 12,9.5Q12,9.5 12,9.5Q12,9.5 12,9.5Q12,9.5 12,9.5ZM12,18.5Q12,18.5 12,18.5Q12,18.5 12,18.5Q12,18.5 12,18.5Q12,18.5 12,18.5Q12,18.5 12,18.5Q12,18.5 12,18.5Q12,18.5 12,18.5Q12,18.5 12,18.5Z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_account_circle_filled.xml b/packages/SystemUI/res/drawable/ic_account_circle_filled.xml
new file mode 100644
index 0000000..47c553b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_account_circle_filled.xml
@@ -0,0 +1,27 @@
+<!--
+ ~ 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM18.36,16.83c-1.43,-1.74 -4.9,-2.33 -6.36,-2.33s-4.93,0.59 -6.36,2.33A7.95,7.95 0,0 1,4 12c0,-4.41 3.59,-8 8,-8s8,3.59 8,8c0,1.82 -0.62,3.49 -1.64,4.83z"/>
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M12,6c-1.94,0 -3.5,1.56 -3.5,3.5S10.06,13 12,13s3.5,-1.56 3.5,-3.5S13.94,6 12,6z"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/qs_detail_switch.xml b/packages/SystemUI/res/drawable/ic_add_supervised_user.xml
similarity index 62%
copy from packages/SystemUI/res/layout/qs_detail_switch.xml
copy to packages/SystemUI/res/drawable/ic_add_supervised_user.xml
index abb2497..627743e 100644
--- a/packages/SystemUI/res/layout/qs_detail_switch.xml
+++ b/packages/SystemUI/res/drawable/ic_add_supervised_user.xml
@@ -1,5 +1,5 @@
<!--
- ~ Copyright (C) 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.
@@ -13,11 +13,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
-<Switch
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/toggle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:clickable="false"
- android:textAppearance="@style/TextAppearance.QS.DetailHeader" />
\ No newline at end of file
+<layer-list
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <item android:drawable="@*android:drawable/ic_add_supervised_user" />
+</layer-list>
diff --git a/packages/SystemUI/res/drawable/ic_manage_users.xml b/packages/SystemUI/res/drawable/ic_manage_users.xml
new file mode 100644
index 0000000..3a0805d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_manage_users.xml
@@ -0,0 +1,23 @@
+<!--
+ ~ 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path android:fillColor="@android:color/white"
+ android:pathData="M10,12Q8.35,12 7.175,10.825Q6,9.65 6,8Q6,6.35 7.175,5.175Q8.35,4 10,4Q11.65,4 12.825,5.175Q14,6.35 14,8Q14,9.65 12.825,10.825Q11.65,12 10,12ZM2,20V17.2Q2,16.375 2.425,15.65Q2.85,14.925 3.6,14.55Q4.875,13.9 6.475,13.45Q8.075,13 10,13Q10.2,13 10.35,13Q10.5,13 10.65,13.05Q10.45,13.5 10.312,13.988Q10.175,14.475 10.1,15H10Q8.225,15 6.812,15.45Q5.4,15.9 4.5,16.35Q4.275,16.475 4.138,16.7Q4,16.925 4,17.2V18H10.3Q10.45,18.525 10.7,19.038Q10.95,19.55 11.25,20ZM16,21L15.7,19.5Q15.4,19.375 15.137,19.238Q14.875,19.1 14.6,18.9L13.15,19.35L12.15,17.65L13.3,16.65Q13.25,16.3 13.25,16Q13.25,15.7 13.3,15.35L12.15,14.35L13.15,12.65L14.6,13.1Q14.875,12.9 15.137,12.762Q15.4,12.625 15.7,12.5L16,11H18L18.3,12.5Q18.6,12.625 18.863,12.775Q19.125,12.925 19.4,13.15L20.85,12.65L21.85,14.4L20.7,15.4Q20.75,15.7 20.75,16.025Q20.75,16.35 20.7,16.65L21.85,17.65L20.85,19.35L19.4,18.9Q19.125,19.1 18.863,19.238Q18.6,19.375 18.3,19.5L18,21ZM17,18Q17.825,18 18.413,17.413Q19,16.825 19,16Q19,15.175 18.413,14.587Q17.825,14 17,14Q16.175,14 15.588,14.587Q15,15.175 15,16Q15,16.825 15.588,17.413Q16.175,18 17,18ZM10,10Q10.825,10 11.413,9.412Q12,8.825 12,8Q12,7.175 11.413,6.588Q10.825,6 10,6Q9.175,6 8.588,6.588Q8,7.175 8,8Q8,8.825 8.588,9.412Q9.175,10 10,10ZM10,8Q10,8 10,8Q10,8 10,8Q10,8 10,8Q10,8 10,8Q10,8 10,8Q10,8 10,8Q10,8 10,8Q10,8 10,8ZM10,15Q10,15 10,15Q10,15 10,15Q10,15 10,15Q10,15 10,15Q10,15 10,15Q10,15 10,15Z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/qs_detail_background.xml b/packages/SystemUI/res/drawable/qs_detail_background.xml
deleted file mode 100644
index c23649d..0000000
--- a/packages/SystemUI/res/drawable/qs_detail_background.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<!--
-Copyright (C) 2014 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.
--->
-<transition xmlns:android="http://schemas.android.com/apk/res/android">
- <item>
- <inset>
- <shape>
- <solid android:color="@android:color/transparent"/>
- <corners android:radius="@dimen/qs_footer_action_corner_radius" />
- </shape>
- </inset>
- </item>
- <item>
- <inset>
- <shape>
- <solid android:color="?android:attr/colorBackgroundFloating"/>
- <corners android:radius="@dimen/qs_footer_action_corner_radius" />
- </shape>
- </inset>
- </item>
-</transition>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_detail.xml b/packages/SystemUI/res/layout/qs_detail.xml
deleted file mode 100644
index 78655c0..0000000
--- a/packages/SystemUI/res/layout/qs_detail.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2014 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.
--->
-<!-- Extends LinearLayout -->
-<com.android.systemui.qs.QSDetail
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@drawable/qs_detail_background"
- android:layout_marginTop="@dimen/qs_detail_margin_top"
- android:clickable="true"
- android:orientation="vertical"
- android:paddingBottom="8dp"
- android:visibility="invisible"
- android:elevation="4dp"
- android:importantForAccessibility="no" >
-
- <include
- android:id="@+id/qs_detail_header"
- layout="@layout/qs_detail_header"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- />
-
- <com.android.systemui.statusbar.AlphaOptimizedImageView
- android:id="@+id/qs_detail_header_progress"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:alpha="0"
- android:background="@color/qs_detail_progress_track"
- android:src="@drawable/indeterminate_anim"
- android:scaleType="fitXY"
- />
-
- <ScrollView
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:fillViewport="true">
-
- <FrameLayout
- android:id="@android:id/content"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
- </ScrollView>
-
- <include layout="@layout/qs_detail_buttons" />
-
-</com.android.systemui.qs.QSDetail>
diff --git a/packages/SystemUI/res/layout/qs_detail_buttons.xml b/packages/SystemUI/res/layout/qs_detail_buttons.xml
deleted file mode 100644
index 75f43f9..0000000
--- a/packages/SystemUI/res/layout/qs_detail_buttons.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2016 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"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingEnd="8dp"
- android:gravity="end">
-
- <TextView
- android:id="@android:id/button2"
- style="@style/QSBorderlessButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginEnd="8dp"
- android:minHeight="48dp"
- android:minWidth="132dp"
- android:textAppearance="@style/TextAppearance.QS.DetailButton"
- android:focusable="true" />
-
- <TextView
- android:id="@android:id/button1"
- style="@style/QSBorderlessButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:minHeight="48dp"
- android:minWidth="88dp"
- android:textAppearance="@style/TextAppearance.QS.DetailButton"
- android:focusable="true"/>
-
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout/qs_detail_header.xml b/packages/SystemUI/res/layout/qs_detail_header.xml
deleted file mode 100644
index d1ab054..0000000
--- a/packages/SystemUI/res/layout/qs_detail_header.xml
+++ /dev/null
@@ -1,65 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2014 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.
--->
-<com.android.keyguard.AlphaOptimizedLinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingLeft="@dimen/qs_detail_header_padding"
- android:paddingTop="@dimen/qs_detail_header_padding"
- android:paddingBottom="@dimen/qs_detail_items_padding_top"
- android:paddingEnd="@dimen/qs_panel_padding"
- android:background="@drawable/btn_borderless_rect"
- android:orientation="vertical"
- android:gravity="center">
-
- <com.android.systemui.ResizingSpace
- android:layout_width="match_parent"
- android:layout_height="@dimen/qs_detail_header_margin_top" />
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
-
- <TextView
- android:id="@android:id/title"
- android:paddingStart="@dimen/qs_detail_header_text_padding"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:textDirection="locale"
- android:textAppearance="@style/TextAppearance.QS.DetailHeader" />
-
- <ImageView
- android:id="@+id/settings"
- android:layout_width="@dimen/qs_detail_image_width"
- android:layout_height="@dimen/qs_detail_image_height"
- android:background="?android:attr/selectableItemBackground"
- android:padding="@dimen/qs_detail_image_padding"
- android:src="@drawable/ic_settings"
- android:visibility="gone"/>
-
- <ViewStub
- android:id="@+id/toggle_stub"
- android:inflatedId="@+id/toggle"
- android:layout="@layout/qs_detail_switch"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
-
- </LinearLayout>
-
-</com.android.keyguard.AlphaOptimizedLinearLayout>
diff --git a/packages/SystemUI/res/layout/qs_detail_item.xml b/packages/SystemUI/res/layout/qs_detail_item.xml
deleted file mode 100644
index 0844bb4..0000000
--- a/packages/SystemUI/res/layout/qs_detail_item.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2014 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"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="@dimen/qs_detail_item_height"
- android:background="@drawable/btn_borderless_rect"
- android:clickable="true"
- android:focusable="true"
- android:gravity="center_vertical"
- android:orientation="horizontal" >
-
- <ImageView
- android:id="@android:id/icon"
- android:layout_width="@dimen/qs_detail_item_icon_width"
- android:layout_height="@dimen/qs_detail_item_icon_size"
- android:layout_marginStart="@dimen/qs_detail_item_icon_marginStart"
- android:layout_marginEnd="@dimen/qs_detail_item_icon_marginEnd"
- android:tint="?android:attr/textColorPrimary"/>
-
- <LinearLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginStart="12dp"
- android:layout_weight="1"
- android:orientation="vertical" >
-
- <TextView
- android:id="@android:id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textDirection="locale"
- android:ellipsize="end"
- android:textAppearance="@style/TextAppearance.QS.DetailItemPrimary" />
-
- <TextView
- android:id="@android:id/summary"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textDirection="locale"
- android:layout_marginTop="2dp"
- android:textAppearance="@style/TextAppearance.QS.DetailItemSecondary" />
- </LinearLayout>
-
- <ImageView
- android:id="@android:id/icon2"
- style="@style/QSBorderlessButton"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:clickable="true"
- android:focusable="true"
- android:scaleType="center"
- android:contentDescription="@*android:string/media_route_controller_disconnect"
- android:tint="?android:attr/textColorPrimary" />
-
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout/qs_detail_items.xml b/packages/SystemUI/res/layout/qs_detail_items.xml
deleted file mode 100644
index 60cba67..0000000
--- a/packages/SystemUI/res/layout/qs_detail_items.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2014 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.
--->
-<!-- extends FrameLayout -->
-<com.android.systemui.qs.QSDetailItems
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:sysui="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingStart="@dimen/qs_detail_padding_start"
- android:paddingEnd="16dp">
-
- <com.android.systemui.qs.AutoSizingList
- android:id="@android:id/list"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- sysui:itemHeight="@dimen/qs_detail_item_height"
- style="@style/AutoSizingList"/>
-
- <LinearLayout
- android:id="@android:id/empty"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:gravity="center"
- android:orientation="vertical">
-
- <ImageView
- android:id="@android:id/icon"
- android:layout_width="56dp"
- android:layout_height="56dp"
- android:tint="?android:attr/textColorSecondary" />
-
- <TextView
- android:id="@android:id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="20dp"
- android:textAppearance="@style/TextAppearance.QS.DetailEmpty"/>
- </LinearLayout>
-</com.android.systemui.qs.QSDetailItems>
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 85b33cc..2040051 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -47,10 +47,6 @@
<include layout="@layout/quick_status_bar_expanded_header" />
- <include
- android:id="@+id/qs_detail"
- layout="@layout/qs_detail" />
-
<ViewStub
android:id="@+id/container_stub"
android:inflatedId="@+id/qs_footer_actions"
diff --git a/packages/SystemUI/res/layout/qs_user_detail_item.xml b/packages/SystemUI/res/layout/qs_user_detail_item.xml
index 3a0df28..0c847ed 100644
--- a/packages/SystemUI/res/layout/qs_user_detail_item.xml
+++ b/packages/SystemUI/res/layout/qs_user_detail_item.xml
@@ -52,7 +52,7 @@
android:gravity="center_horizontal" />
<ImageView
android:id="@+id/restricted_padlock"
- android:layout_width="@dimen/qs_detail_item_secondary_text_size"
+ android:layout_width="@dimen/qs_tile_text_size"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:src="@drawable/ic_info"
diff --git a/packages/SystemUI/res/layout/rounded_corners_bottom.xml b/packages/SystemUI/res/layout/rounded_corners_bottom.xml
index b2857ab..bb6d4bd 100644
--- a/packages/SystemUI/res/layout/rounded_corners_bottom.xml
+++ b/packages/SystemUI/res/layout/rounded_corners_bottom.xml
@@ -25,6 +25,7 @@
android:layout_height="12dp"
android:layout_gravity="left|bottom"
android:tint="#ff000000"
+ android:visibility="gone"
android:src="@drawable/rounded_corner_bottom"/>
<ImageView
@@ -32,6 +33,7 @@
android:layout_width="12dp"
android:layout_height="12dp"
android:tint="#ff000000"
+ android:visibility="gone"
android:layout_gravity="right|bottom"
android:src="@drawable/rounded_corner_bottom"/>
diff --git a/packages/SystemUI/res/layout/rounded_corners_top.xml b/packages/SystemUI/res/layout/rounded_corners_top.xml
index 9937c21..46648c8 100644
--- a/packages/SystemUI/res/layout/rounded_corners_top.xml
+++ b/packages/SystemUI/res/layout/rounded_corners_top.xml
@@ -25,6 +25,7 @@
android:layout_height="12dp"
android:layout_gravity="left|top"
android:tint="#ff000000"
+ android:visibility="gone"
android:src="@drawable/rounded_corner_top"/>
<ImageView
@@ -32,6 +33,7 @@
android:layout_width="12dp"
android:layout_height="12dp"
android:tint="#ff000000"
+ android:visibility="gone"
android:layout_gravity="right|top"
android:src="@drawable/rounded_corner_top"/>
diff --git a/packages/SystemUI/res/layout/qs_detail_switch.xml b/packages/SystemUI/res/layout/screen_decor_hwc_layer.xml
similarity index 69%
rename from packages/SystemUI/res/layout/qs_detail_switch.xml
rename to packages/SystemUI/res/layout/screen_decor_hwc_layer.xml
index abb2497..1c17e75 100644
--- a/packages/SystemUI/res/layout/qs_detail_switch.xml
+++ b/packages/SystemUI/res/layout/screen_decor_hwc_layer.xml
@@ -1,5 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 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.
@@ -13,11 +14,8 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
-<Switch
+<com.android.systemui.RegionInterceptingFrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/toggle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:clickable="false"
- android:textAppearance="@style/TextAppearance.QS.DetailHeader" />
\ No newline at end of file
+ android:id="@+id/screen_decor_hwc_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
diff --git a/packages/SystemUI/res/layout/system_icons.xml b/packages/SystemUI/res/layout/system_icons.xml
index 4f4bae4..816dfd3 100644
--- a/packages/SystemUI/res/layout/system_icons.xml
+++ b/packages/SystemUI/res/layout/system_icons.xml
@@ -19,6 +19,7 @@
android:id="@+id/system_icons"
android:layout_width="wrap_content"
android:layout_height="match_parent"
+ android:layout_gravity="center_vertical|end"
android:gravity="center_vertical">
<com.android.systemui.statusbar.phone.StatusIconContainer android:id="@+id/statusIcons"
diff --git a/packages/SystemUI/res/layout/tuner_zen_mode_panel.xml b/packages/SystemUI/res/layout/tuner_zen_mode_panel.xml
deleted file mode 100644
index efe63d7..0000000
--- a/packages/SystemUI/res/layout/tuner_zen_mode_panel.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2016 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.
--->
-<!-- extends LinearLayout -->
-<com.android.systemui.tuner.TunerZenModePanel
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/tuner_zen_mode_panel"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:clipChildren="false"
- android:visibility="gone"
- android:orientation="vertical" >
-
- <View
- android:id="@+id/zen_embedded_divider"
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:layout_marginBottom="12dp"
- android:layout_marginTop="8dp"
- android:background="@color/qs_tile_divider" />
-
- <include
- android:layout_width="match_parent"
- android:layout_height="48dp"
- android:layout_marginStart="16dp"
- android:id="@+id/tuner_zen_switch"
- layout="@layout/qs_detail_header" />
-
- <include layout="@layout/zen_mode_panel" />
-
- <include
- android:id="@+id/tuner_zen_buttons"
- layout="@layout/qs_detail_buttons" />
-
-</com.android.systemui.tuner.TunerZenModePanel>
diff --git a/packages/SystemUI/res/layout/user_switcher_fullscreen.xml b/packages/SystemUI/res/layout/user_switcher_fullscreen.xml
index 7b95cf3c..2d883bc 100644
--- a/packages/SystemUI/res/layout/user_switcher_fullscreen.xml
+++ b/packages/SystemUI/res/layout/user_switcher_fullscreen.xml
@@ -21,6 +21,7 @@
android:id="@+id/user_switcher_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:layout_marginBottom="40dp"
android:layout_marginEnd="60dp"
android:layout_marginStart="60dp">
diff --git a/packages/SystemUI/res/layout/user_switcher_fullscreen_popup_item.xml b/packages/SystemUI/res/layout/user_switcher_fullscreen_popup_item.xml
index 8d02429..401c4bd 100644
--- a/packages/SystemUI/res/layout/user_switcher_fullscreen_popup_item.xml
+++ b/packages/SystemUI/res/layout/user_switcher_fullscreen_popup_item.xml
@@ -29,17 +29,19 @@
<ImageView
android:id="@+id/icon"
+ android:scaleType="centerInside"
android:layout_gravity="center"
android:layout_width="20dp"
android:layout_height="20dp"
android:contentDescription="@null"
+ android:tint="@color/user_switcher_fullscreen_popup_item_tint"
android:layout_marginEnd="10dp" />
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textColor="@*android:color/text_color_primary_device_default_dark"
+ android:textColor="@color/user_switcher_fullscreen_popup_item_tint"
android:textSize="14sp"
android:layout_gravity="start" />
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/zen_mode_panel.xml b/packages/SystemUI/res/layout/zen_mode_panel.xml
deleted file mode 100644
index 5862413..0000000
--- a/packages/SystemUI/res/layout/zen_mode_panel.xml
+++ /dev/null
@@ -1,170 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2014 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.
--->
-<!-- extends LinearLayout -->
-<com.android.systemui.volume.ZenModePanel xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/zen_mode_panel"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:clipChildren="false" >
-
- <LinearLayout
- android:id="@+id/edit_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="?android:attr/colorPrimary"
- android:clipChildren="false"
- android:orientation="vertical">
-
- <com.android.systemui.volume.SegmentedButtons
- android:id="@+id/zen_buttons"
- android:background="@drawable/segmented_buttons_background"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="16dp"
- android:layout_marginEnd="16dp"
- android:layout_marginBottom="8dp" />
-
- <RelativeLayout
- android:id="@+id/zen_introduction"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="16dp"
- android:layout_marginEnd="16dp"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:background="@drawable/zen_introduction_message_background"
- android:theme="@*android:style/ThemeOverlay.DeviceDefault.Accent.Light">
-
- <ImageView
- android:id="@+id/zen_introduction_confirm"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:layout_marginEnd="8dp"
- android:layout_alignParentEnd="true"
- android:background="@drawable/btn_borderless_rect"
- android:clickable="true"
- android:contentDescription="@string/accessibility_desc_close"
- android:scaleType="center"
- android:src="@drawable/ic_close_white_rounded" />
-
- <TextView
- android:id="@+id/zen_introduction_message"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="12dp"
- android:layout_marginStart="24dp"
- android:textDirection="locale"
- android:lineSpacingMultiplier="1.20029"
- android:layout_toStartOf="@id/zen_introduction_confirm"
- android:textAppearance="@style/TextAppearance.QS.Introduction" />
-
- <TextView
- android:id="@+id/zen_introduction_customize"
- style="@style/QSBorderlessButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentEnd="true"
- android:layout_marginEnd="12dp"
- android:layout_below="@id/zen_introduction_message"
- android:clickable="true"
- android:focusable="true"
- android:text="@string/zen_priority_customize_button"
- android:textAppearance="@style/TextAppearance.QS.DetailButton.White" />
-
- <View
- android:layout_width="0dp"
- android:layout_height="16dp"
- android:layout_below="@id/zen_introduction_message"
- android:layout_alignParentEnd="true" />
-
- </RelativeLayout>
-
- <com.android.settingslib.notification.ZenRadioLayout
- android:id="@+id/zen_conditions"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- android:layout_marginEnd="4dp"
- android:layout_marginStart="4dp"
- android:paddingBottom="@dimen/zen_mode_condition_detail_bottom_padding"
- android:orientation="horizontal" >
- <RadioGroup
- android:id="@+id/zen_radio_buttons"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
- <LinearLayout
- android:id="@+id/zen_radio_buttons_content"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical"/>
- </com.android.settingslib.notification.ZenRadioLayout>
-
- <TextView
- android:id="@+id/zen_alarm_warning"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="18dp"
- android:layout_marginEnd="16dp"
- android:textDirection="locale"
- android:lineSpacingMultiplier="1.20029"
- android:textAppearance="@style/TextAppearance.QS.Warning" />
- </LinearLayout>
-
- <LinearLayout
- android:id="@android:id/empty"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:background="?android:attr/colorPrimary"
- android:gravity="center"
- android:orientation="vertical">
-
- <ImageView
- android:id="@android:id/icon"
- android:layout_width="56dp"
- android:layout_height="56dp"
- android:alpha="?android:attr/disabledAlpha"
- android:tint="?android:attr/colorForeground" />
-
- <TextView
- android:id="@android:id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="20dp"
- android:textAppearance="@style/TextAppearance.QS.DetailEmpty"/>
- </LinearLayout>
-
- <LinearLayout
- android:id="@+id/auto_rule"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="?android:attr/colorPrimary"
- android:layout_marginStart="16dp"
- android:layout_marginEnd="16dp"
- android:layout_marginTop="16dp"
- android:layout_marginBottom="8dp"
- android:orientation="vertical">
-
- <TextView
- android:id="@android:id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textAppearance="@style/TextAppearance.QS.DetailItemPrimary"/>
-
- </LinearLayout>
-
-</com.android.systemui.volume.ZenModePanel>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 309921c..42955caf 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Laat toe"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB-ontfouting word nie toegelaat nie"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Die gebruiker wat tans by hierdie toestel aangemeld is, kan nie USB-ontfouting aanskakel nie. Skakel na die primêre gebruiker toe oor om hierdie kenmerk te gebruik."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Wil jy die stelseltaal na <xliff:g id="LANGUAGE">%1$s</xliff:g> verander?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"\'n Ander toestel het versoek om die stelseltaal te verander"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Verander taal"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Hou huidige taal"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Laat draadlose ontfouting op hierdie netwerk toe?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Netwerknaam (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi-adres (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Laat altyd toe op hierdie netwerk"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Helderheid"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Kleuromkering"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Kleurregstelling"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Meer instellings"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Gebruikerinstellings"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Klaar"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Maak toe"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Jy sal nie jou volgende wekker <xliff:g id="WHEN">%1$s</xliff:g> hoor nie"</string>
<string name="alarm_template" msgid="2234991538018805736">"om <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"op <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Kitsinstellings, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Warmkol"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Werkprofiel"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Pret vir party mense, maar nie vir almal nie"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Aangemeld as <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"kies gebruiker"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Geen internet nie"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Maak besonderhede oop."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Maak <xliff:g id="ID_1">%s</xliff:g>-instellings oop."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Wysig volgorde van instellings."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Aan/af-kieslys"</string>
@@ -884,13 +877,20 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktiewe programme</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aktiewe program</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktiewe programme"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Gestop"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Kopieer"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Gekopieer"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Van <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Maak kopieer-UI toe"</string>
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Wysig gekopieerde teks"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Wysig gekopieerde prent"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Stuur na toestel in die omtrek"</string>
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 812776b..03ae0e4 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"ፍቀድ"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"የዩኤስቢ እርማት አይፈቀድም"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"አሁን ወደዚህ መሣሪያ የገባው ተጠቃሚ የዩኤስቢ እርማትን ማብራት አይችልም። ይህን ባህሪ ለመጠቀም ወደ ዋና ተጠቃሚ ይቀይሩ።"</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"የስርዓት ቋንቋውን ወደ <xliff:g id="LANGUAGE">%1$s</xliff:g> መቀየር ይፈልጋሉ?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"በሌላ መሳሪያ የተጠየቀ የስርዓት ቋንቋ ለውጥ"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"ቋንቋ ቀይር"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"አሁን ያለውን ቋንቋ አቆይ"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"በዚህ አውታረ መረብ ላይ ገመድ-አልባ debugging ይፈቀድ?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"የአውታረ መረብ ስም (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nየWi‑Fi አድራሻ (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"ሁልጊዜ በዚህ አውታረ መረብ ላይ ፍቀድ"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ብሩህነት"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"ተቃራኒ ቀለም"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"የቀለም ማስተካከያ"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"ተጨማሪ ቅንብሮች"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"የተጠቃሚ ቅንብሮች"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"ተከናውኗል"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"ዝጋ"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"የእርስዎን ቀጣይ ማንቂያ <xliff:g id="WHEN">%1$s</xliff:g> አይሰሙም"</string>
<string name="alarm_template" msgid="2234991538018805736">"በ<xliff:g id="WHEN">%1$s</xliff:g> ላይ"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"በ<xliff:g id="WHEN">%1$s</xliff:g> ላይ"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"ፈጣን ቅንብሮች፣ <xliff:g id="TITLE">%s</xliff:g>።"</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"መገናኛ ነጥብ"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"የስራ መገለጫ"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"ለአንዳንዶች አስደሳች ቢሆንም ለሁሉም አይደለም"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"እንደ <xliff:g id="ID_1">%s</xliff:g> ሆነው ገብተዋል"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"ተጠቃሚ ይምረጡ"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"ምንም በይነመረብ የለም"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"ዝርዝሮችን ክፈት።"</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"የ<xliff:g id="ID_1">%s</xliff:g> ቅንብሮችን ክፈት።"</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"የቅንብሮድ ቅደም-ተከተል አርትዕ።"</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"የኃይል ምናሌ"</string>
@@ -884,13 +877,20 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> ገቢር መተግበሪያዎች</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> ገቢር መተግበሪያዎች</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"ገቢር መተግበሪያዎች"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"መቆሚያ"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"ቆሟል"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"ቅዳ"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"ተቀድቷል"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"ከ<xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"ዩአይ ቅዳን አሰናብት"</string>
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"የተቀዳ ጽሁፍ አርትዕ ያድርጉ"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"የተቀዳ ምስል አርትዕ ያድርጉ"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"በአቅራቢያ ወዳለ መሳሪያ ይላኩ"</string>
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index ebc43fe..38dcb89 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"سماح"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"لا يُسمح بتصحيح أخطاء USB"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"لا يمكن للمستخدم الذي يسجّل دخوله حاليًا إلى هذا الجهاز تفعيل تصحيح الأخطاء USB. لاستخدام هذه الميزة، يمكنك التبديل إلى المستخدم الأساسي."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"هل تريد تغيير لغة النظام إلى <xliff:g id="LANGUAGE">%1$s</xliff:g>؟"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"طلب جهاز آخر تغيير لغة النظام."</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"تغيير اللغة"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"الإبقاء على اللغة الحالية"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"هل تريد السماح باستخدام ميزة \"تصحيح الأخطاء اللاسلكي\" على هذه الشبكة؟"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"اسم الشبكة (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nعنوان شبكة Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"السماح باستخدام هذه الميزة على هذه الشبكة دائمًا"</string>
@@ -244,7 +240,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"السطوع"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"قلب الألوان"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"تصحيح الألوان"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"المزيد من الإعدادات"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"إعدادات المستخدم"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"تم"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"إغلاق"</string>
@@ -476,7 +471,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"لن تسمع المنبّه القادم في <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"في <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"يوم <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"الإعدادات السريعة، <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"نقطة اتصال"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"الملف الشخصي للعمل"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"متعة للبعض وليس للجميع"</string>
@@ -663,7 +657,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"تم تسجيل الدخول باعتبارك <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"اختيار مستخدم"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"لا يتوفر اتصال إنترنت."</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"فتح التفاصيل."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"فتح إعدادات <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"تعديل ترتيب الإعدادات."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"قائمة زر التشغيل"</string>
@@ -912,13 +905,23 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> تطبيق نشط</item>
<item quantity="one">تطبيق واحد (<xliff:g id="COUNT_0">%s</xliff:g>) نشط</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"# تطبيق نشط"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"إيقاف"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"متوقّف"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"نسخ"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"تم النسخ."</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"من <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"إغلاق واجهة مستخدم النسخ"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 087d67e..8d8a0fb 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"অনুমতি দিয়ক"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"ইউএছবি ডিবাগিঙৰ অনুমতি নাই"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"এই ডিভাইচটোত বর্তমান ছাইন ইন হৈ থকা ব্যৱহাৰকাৰীজনে ইউএছবি ডিবাগিং অন কৰিব নোৱাৰে। এই সুবিধাটো ব্যৱহাৰ কৰিবলৈ হ\'লে মুখ্য ব্যৱহাৰকাৰী হিচাপে ছাইন ইন কৰক।"</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"আপুনি ছিষ্টেমৰ ভাষা <xliff:g id="LANGUAGE">%1$s</xliff:g>লৈ সলনি কৰিবলৈ বিচাৰেনে?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"অন্য এটা ডিভাইচে ছিষ্টেমৰ ভাষা সলনি কৰাৰ অনুৰোধ কৰিছে"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"ভাষা সলনি কৰক"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"বৰ্তমানৰ ভাষাটো ৰাখক"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"এই নেটৱৰ্কত ৱায়াৰলেচ ডি\'বাগিংৰ অনুমতি দিবনে?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"নেটৱৰ্কৰ নাম (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nৱাই-ফাইৰ ঠিকনা (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"এই নেটৱৰ্কত সদায় অনুমতি দিয়ক"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"উজ্জ্বলতা"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"ৰং বিপৰীতকৰণ"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"ৰং শুধৰণী"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"অধিক ছেটিং"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ব্যৱহাৰকাৰীৰ ছেটিং"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"সম্পন্ন কৰা হ’ল"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"বন্ধ কৰক"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"আপুনি আপোনাৰ পিছৰটো এলাৰ্ম <xliff:g id="WHEN">%1$s</xliff:g> বজাত শুনা নাপাব"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> বজাত"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> বজাত"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"ক্ষিপ্ৰ ছেটিং, <xliff:g id="TITLE">%s</xliff:g>।"</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"হটস্পট"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"কৰ্মস্থানৰ প্ৰ\'ফাইল"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"কিছুমানৰ বাবে আমোদজনক হয় কিন্তু সকলোৰে বাবে নহয়"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> হিচাপে ছাইন ইন হ’ল"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"ব্যৱহাৰকাৰী বাছনি কৰক"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"ইণ্টাৰনেট সংযোগ নাই"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"বিৱৰণসমূহ খোলক।"</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g>ৰ ছেটিং খোলক।"</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"ছেটিঙৰ ক্ৰম সম্পাদনা কৰক।"</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"পাৱাৰ মেনু"</string>
@@ -884,13 +877,20 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> টা সক্ৰিয় এপ্</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> টা সক্ৰিয় এপ্</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"সক্ৰিয় এপ্"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"বন্ধ কৰক"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"বন্ধ হ’ল"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"প্ৰতিলিপি কৰক"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"প্ৰতিলিপি কৰা হ’ল"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g>ৰ পৰা"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"প্ৰতিলিপি কৰা UI অগ্ৰাহ্য কৰক"</string>
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"প্ৰতিলিপি কৰা পাঠ সম্পাদনা কৰক"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"প্ৰতিলিপি কৰা প্ৰতিচ্ছবি সম্পাদনা কৰক"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"নিকটৱৰ্তী ডিভাইচলৈ পঠাওক"</string>
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 013c489..1fc28a8 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"İcazə verin"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB ilə sazlama qadağandır"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Hazırda bu cihaza daxil olmuş istifadəçi USB sazlama prosesini aktiv edə bilməz. Bu funksiyadan istifadə etmək üçün əsas istifadəçi hesaba daxil olmalıdır."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Sistem dili <xliff:g id="LANGUAGE">%1$s</xliff:g> dilinə dəyişdirilsin?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Sistem dilinin dəyişdirilməsi başqa cihaz tərəfindən tələb olunur"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Dili dəyişin"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Cari dili saxlayın"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Bu şəbəkədə WiFi sazlamasına icazə verilsin?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Şəbəkə Adı (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi Ünvanı (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Bu şəbəkədə həmişə icazə verilsin"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Parlaqlıq"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Rəng inversiyası"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Rəng korreksiyası"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Digər ayarlar"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"İstifadəçi ayarları"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Hazır"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Bağlayın"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> zaman növbəti xəbərdarlığınızı eşitməyəcəksiniz"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Sürətli Ayarlar, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Hotspot"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"İş profili"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Hamı üçün deyil, bəziləri üçün əyləncəli"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> kimi daxil olunub"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"istifadəçi seçin"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"İnternet yoxdur"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Detalları açın."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g> ayarlarını açın."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Ayarların sıralanmasını redaktə edin."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Qidalanma düyməsi menyusu"</string>
@@ -884,13 +877,23 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktiv tətbiq</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aktiv tətbiq</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktiv tətbiqlər"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Dayandırın"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Dayandırılıb"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Kopyalayın"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopyalandı"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Mənbə: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"UI kopyalanmasını qapadın"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index f84560d..555b477 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Dozvoli"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Otklanjanje grešaka na USB-u nije dozvoljeno"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Korisnik koji je trenutno prijavljen na ovaj uređaj ne može da uključi otklanjanje grešaka na USB-u. Da biste koristili ovu funkciju, prebacite na primarnog korisnika."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Da li želite da promenite jezik sistema na <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Drugi uređaj je zatražio promenu jezika sistema"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Promeni jezik"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Zadrži aktuelni jezik"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Želite da dozvolite bežično otklanjanje grešaka na ovoj mreži?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Naziv mreže (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi adresa (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Uvek dozvoli na ovoj mreži"</string>
@@ -241,7 +237,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Osvetljenost"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inverzija boja"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Korekcija boja"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Još podešavanja"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Korisnička podešavanja"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Gotovo"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Zatvori"</string>
@@ -467,7 +462,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Nećete čuti sledeći alarm u <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"u <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"u <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Brza podešavanja, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Hotspot"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Poslovni profil"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Zabava za neke, ali ne za sve"</string>
@@ -648,7 +642,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Prijavljeni ste kao <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"odabrali korisnika"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Nema interneta"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Otvori detalje."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Otvori podešavanja za <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Izmeni redosled podešavanja."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Meni dugmeta za uključivanje"</string>
@@ -891,13 +884,23 @@
<item quantity="few"><xliff:g id="COUNT_1">%s</xliff:g> aktivne aplikacije</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktivnih aplikacija</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktivne aplikacije"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Zaustavi"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Zaustavljeno"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Kopiraj"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopirano je"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Iz: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Odbaci kopiranje korisničkog interfejsa"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index a3d4652..7446007 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Дазволіць"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Адладка па USB забаронена"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Карыстальнік, які зараз увайшоў у гэту прыладу, не можа ўключыць адладку па USB. Каб выкарыстоўваць гэту функцыю, пераключыцеся на асноўнага карыстальніка."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Змяніць мову сістэмы на наступную: \"<xliff:g id="LANGUAGE">%1$s</xliff:g>\"?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Іншая прылада запытала змяненне мовы сістэмы"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Змяніць мову"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Захаваць бягучую мову"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Дазволіць адладку па Wi-Fi у гэтай сетцы?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Назва сеткі (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nАдрас Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Заўсёды дазваляць у гэтай сетцы"</string>
@@ -242,7 +238,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Яркасць"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Інверсія колераў"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Карэкцыя колераў"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Дадатковыя налады"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Налады карыстальніка"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Гатова"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Закрыць"</string>
@@ -470,7 +465,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Вы не пачуеце наступны будзільнік <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"у <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"у <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Хуткія налады, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Хот-спот"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Працоўны профіль"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Цікава для некаторых, але не для ўсіх"</string>
@@ -653,7 +647,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Вы ўвайшлі як <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"выбраць карыстальніка"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Няма падключэння да інтэрнэту"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Паказаць падрабязную інфармацыю."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Адкрыць налады <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Змяніць парадак налад."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Меню кнопкі сілкавання"</string>
@@ -898,13 +891,23 @@
<item quantity="many"><xliff:g id="COUNT_1">%s</xliff:g> актыўных праграм</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> актыўнай праграмы</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Актыўныя праграмы"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Спыніць"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Спынена"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Капіраваць"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Скапіравана"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"З праграмы \"<xliff:g id="APPNAME">%1$s</xliff:g>\""</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Закрыць інтэрфейс капіравання"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 6245e47..f7a1ad6 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Разрешаване"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Отстраняването на грешки през USB не е разрешено"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Потребителят, който понастоящем е влязъл в това устройство, не може да включи функцията за отстраняване на грешки през USB. За да я използвате, превключете към основния потребител."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Искате ли да промените езика на системата на <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Друго устройство е заявило промяна на езика на системата"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Промяна на езика"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Текущ език: Запазване"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Разрешаване на безжичното отстраняване на грешки?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Име на мрежата (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nАдрес на Wi‑Fi мрежата (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Винаги да се разрешава в тази мрежа"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Яркост"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Инвертиране на цветовете"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Корекция на цветове"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Още настройки"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Потребителски настройки"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Готово"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Затваряне"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Няма да чуете следващия си будилник в <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"в <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"в/ъв <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Бързи настройки (<xliff:g id="TITLE">%s</xliff:g>)."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Точка за достъп"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Потребителски профил в Work"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Забавно – но не за всички"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Влезли сте като <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"изберете потребител"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Няма връзка с интернет"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Отвaряне на страницата с подробности."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Отваряне на настройките за <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Редактиране на подредбата на настройките."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Меню за включване/изключване"</string>
@@ -884,13 +877,23 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> активни приложения</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> активно приложение</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Активни приложения"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Спиране"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Спряно"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Копиране"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Копирано"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"От <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Отхвърляне на ПИ за копиране"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 1d7e96d..36a5bc4 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"অনুমতি দিন"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB ডিবাগিং অনুমোদিত নয়"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"ব্যবহারকারী এখন এই ডিভাইসে সাইন-ইন করেছেন তাই USB ডিবাগিং চালু করা যাবে না। এই বৈশিষ্ট্যটি ব্যবহার করতে, প্রাথমিক ব্যবহারকারীতে পাল্টে নিন।"</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"আপনি কি সিস্টেমের ভাষা পরিবর্তন করে <xliff:g id="LANGUAGE">%1$s</xliff:g> করতে চান?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"অন্য ডিভাইসের দ্বারা সিস্টেমের ভাষা পরিবর্তনের অনুরোধ করা হয়েছে"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"ভাষা পরিবর্তন করুন"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"বর্তমান ভাষা রাখুন"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"এই নেটওয়ার্কে ওয়্যারলেস ডিবাগিংয়ের অনুমতি দেবেন?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"নেটওয়ার্কের নাম (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nওয়াই-ফাই অ্যাড্রেস (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"এই নেটওয়ার্কে সবসময় অনুমতি দিন"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"উজ্জ্বলতা"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"কালার ইনভার্সন"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"রঙ সংশোধন"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"আরও সেটিংস"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ব্যবহারকারী সেটিংস"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"সম্পন্ন হয়েছে"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"বন্ধ করুন"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"আপনি আপনার পরবর্তী <xliff:g id="WHEN">%1$s</xliff:g> অ্যালার্ম শুনতে পাবেন না"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> -তে"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"দ্রুত সেটিংস, <xliff:g id="TITLE">%s</xliff:g>৷"</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"হটস্পট"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"কাজের প্রোফাইল"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"কিছু ব্যক্তির জন্য মজাদার কিন্তু সকলের জন্য নয়"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> হিসেবে প্রবেশ করে রয়েছেন"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"ব্যবহারকারী বেছে নিন"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"ইন্টারনেট কানেকশন নেই"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"বিশদ বিবরণ খুলুন৷"</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g> সেটিংস খুলুন৷"</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"ক্রম বা সেটিংস সম্পাদনা করুন৷"</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"পাওয়ার মেনু"</string>
@@ -884,13 +877,20 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g>টি অ্যাক্টিভ অ্যাপ</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g>টি অ্যাক্টিভ অ্যাপ</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"অ্যাক্টিভ অ্যাপ"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"বন্ধ করুন"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"থামানো হয়েছে"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"কপি করুন"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"কপি করা হয়েছে"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> থেকে"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"কপি করা UI বাতিল করুন"</string>
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"কপি করা টেক্সট এডিট করুন"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"কপি করা ছবি এডিট করুন"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"আশেপাশের ডিভাইসে পাঠান"</string>
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 74575c2..1545c43 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Dozvoli"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Otklanjanje grešaka putem USB-a nije dozvoljeno"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Korisnik koji je trenutno prijavljen na ovaj uređaj ne može uključiti opciju za otklanjanje grešaka putem USB-a. Da koristite tu funkciju, prebacite se na primarnog korisnika."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Želite li promijeniti jezik sistema u <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Promjenu jezika sistema je zatražio drugi uređaj"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Promijeni jezik"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Zadrži trenutni jezik"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Dozvoliti bežično otklanjanje grešaka na ovoj mreži?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Naziv mreže (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAdresa WiFi mreže (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Uvijek dozvoli na ovoj mreži"</string>
@@ -241,7 +237,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Osvjetljenje"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inverzija boja"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Ispravka boje"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Više postavki"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Korisničke postavke"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Gotovo"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Zatvori"</string>
@@ -467,7 +462,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Nećete čuti sljedeći alarm u <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"u <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"u <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Brze postavke, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Pristupna tačka"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Profil za posao"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Zabava za neke, ali ne za sve"</string>
@@ -648,7 +642,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Prijavljeni ste kao <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"odaberete korisnika"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Nema internetske veze"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Otvori detalje."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Otvori postavke za: <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Urediti raspored postavki."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Meni napajanja"</string>
@@ -891,13 +884,20 @@
<item quantity="few"><xliff:g id="COUNT_1">%s</xliff:g> aktivne aplikacije</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktivnih aplikacija</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktivne aplikacije"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Zaustavi"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Zaustavljeno"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Kopiraj"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopirano"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Iz aplikacije <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Odbaci kopirani korisnički interfejs"</string>
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Uredi kopirani tekst"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Uredi kopiranu sliku"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Pošalji na uređaj u blizini"</string>
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 46500b7..621f5f9 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Permet"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"No es permet la depuració per USB"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"L\'usuari que té iniciada la sessió al dispositiu en aquest moment no pot activar la depuració per USB. Per utilitzar aquesta funció, cal canviar a l\'usuari principal."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Vols canviar l\'idioma del sistema a <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Un altre dispositiu ha sol·licitat canviar l\'idioma del sistema"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Canvia l\'idioma"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Mantén l\'idioma actual"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Vols permetre la depuració sense fil en aquesta xarxa?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Nom de la xarxa (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAdreça Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Permet sempre en aquesta xarxa"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brillantor"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversió de colors"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Correcció de color"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Més opcions"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Configuració d\'usuari"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Fet"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Tanca"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> no sentiràs la pròxima alarma"</string>
<string name="alarm_template" msgid="2234991538018805736">"Hora: <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"Dia: <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Configuració ràpida, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Punt d\'accés Wi-Fi"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Perfil de treball"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Diversió per a uns quants, però no per a tothom"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"S\'ha iniciat la sessió com a <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"triar un usuari"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Sense connexió a Internet"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Obre la informació detallada."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Obre la configuració per a <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Edita l\'ordre de la configuració."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menú d\'engegada"</string>
@@ -884,13 +877,23 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aplicacions actives</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aplicació activa</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aplicacions actives"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Atura"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Aturada"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Copia"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"S\'ha copiat"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"De: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Ignora la IU de còpia"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 41ae7f7..ba97688 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Povolit"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Ladění přes USB není povoleno"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Uživatel aktuálně přihlášený k tomuto zařízení nemůže zapnout ladění přes USB. Chcete-li tuto funkci použít, přepněte na primárního uživatele."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Změnit systémový jazyk na <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Jiné zařízení požádalo o změnu systémového jazyka"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Změnit jazyk"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Zachovat stávající jazyk"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Povolit v této síti bezdrátové ladění?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Název sítě (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAdresa Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"V této síti vždy povolit"</string>
@@ -242,7 +238,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Jas"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Převrácení barev"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Korekce barev"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Další nastavení"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Uživatelské nastavení"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Hotovo"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Zavřít"</string>
@@ -470,7 +465,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Svůj další budík <xliff:g id="WHEN">%1$s</xliff:g> neuslyšíte"</string>
<string name="alarm_template" msgid="2234991538018805736">"v <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Rychlé nastavení <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Hotspot"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Pracovní profil"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Zábava, která není pro každého"</string>
@@ -653,7 +647,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Jste přihlášeni jako <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"zvolit uživatele"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Nejste připojeni k internetu"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Otevřít podrobnosti."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Otevřít nastavení aplikace <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Upravit pořadí nastavení."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Nabídka vypínače"</string>
@@ -898,13 +891,23 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktivních aplikací</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aktivních aplikací</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktivní aplikace"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Konec"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Zastaveno"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Kopírovat"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Zkopírováno"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Z aplikace <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Zavřít uživatelské rozhraní kopírování"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index c1c4088..bbcb9bc 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Tillad"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB-fejlretning er ikke tilladt"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Den bruger, der i øjeblikket er logget ind på denne enhed, kan ikke aktivere USB-fejlretning. Skift til den primære bruger for at bruge denne funktion."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Vil du ændre systemsproget til <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"En anden enhed har anmodet om en ændring af systemsproget"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Skift sprog"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Behold nuværende sprog"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Vil du tillade trådløs fejlretning på dette netværk?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Netværksnavn (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi-adresse (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Tillad altid på dette netværk"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Lysstyrke"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Ombytning af farver"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Farvekorrigering"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Flere indstillinger"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Brugerindstillinger"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Udfør"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Luk"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Du vil ikke kunne høre din næste alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"kl. <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"på <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Kvikmenu <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Hotspot"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Arbejdsprofil"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Sjovt for nogle, men ikke for alle"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Logget ind som <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"vælge bruger"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Intet internet"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Åbn oplysninger."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Åbn <xliff:g id="ID_1">%s</xliff:g>-indstillinger."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Rediger rækkefølgen af indstillinger."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu for afbryderknappen"</string>
@@ -884,13 +877,23 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> aktiv app</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktive apps</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktive apps"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Stoppet"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Kopiér"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopieret"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Fra <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Luk brugerfladen for kopi"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 6aa260c..2b9f725 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -236,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Helligkeit"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Farbumkehr"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Farbkorrektur"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Weitere Einstellungen"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Nutzereinstellungen"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Fertig"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Schließen"</string>
@@ -460,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Lautloser Weckruf <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"um <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"am <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Schnelleinstellungen (<xliff:g id="TITLE">%s</xliff:g>)"</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Hotspot"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Arbeitsprofil"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Für einige ein Vergnügen, aber nicht für alle"</string>
@@ -639,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Angemeldet als <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"Auswählen des Nutzers"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Kein Internet"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Details öffnen."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Einstellungen für <xliff:g id="ID_1">%s</xliff:g> öffnen."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Reihenfolge der Einstellungen bearbeiten."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Ein-/Aus-Menü"</string>
@@ -880,13 +877,23 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktive Apps</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aktive App</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktive Apps"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Beenden"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Beendet"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Kopieren"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopiert"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Von <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Kopieren-Benutzeroberfläche schließen"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 0a727e3..6096749 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Να επιτρέπεται"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Δεν επιτρέπεται ο εντοπισμός σφαλμάτων USB"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Ο χρήστης που είναι συνδεδεμένος αυτήν τη στιγμή σε αυτήν τη συσκευή δεν μπορεί να ενεργοποιήσει τον εντοπισμό σφαλμάτων USB. Για να χρησιμοποιήσετε αυτήν τη λειτουργία, κάντε εναλλαγή στον κύριο χρήστη."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Θέλετε να αλλάξετε τη γλώσσα συστήματος σε <xliff:g id="LANGUAGE">%1$s</xliff:g>;"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Ζητήθηκε αλλαγή της γλώσσας συστήματος από άλλη συσκευή"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Αλλαγή γλώσσας"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Διατήρ. τρέχουσας γλώσσας"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Να επιτρέπεται ασύρματος εντοπ. σφαλ. στο δίκτυο;"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Όνομα δικτύου (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nΔιεύθυνση Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Να επιτρέπεται πάντα σε αυτό το δίκτυο"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Φωτεινότητα"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Αντιστροφή χρωμάτων"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Διόρθωση χρωμάτων"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Περισσότερες ρυθμίσεις"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Ρυθμίσεις χρήστη"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Τέλος"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Κλείσιμο"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Δεν θα ακούσετε το επόμενο ξυπνητήρι σας <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"στις <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"στις <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Γρήγορες ρυθμίσεις, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Σημείο πρόσβασης Wi-Fi"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Προφίλ εργασίας"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Διασκέδαση για ορισμένους, αλλά όχι για όλους"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Σύνδεση ως <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"επιλογή χρήστη"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Δεν υπάρχει σύνδεση στο διαδίκτυο"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Άνοιγμα λεπτομερειών."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Άνοιγμα ρυθμίσεων <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Επεξεργασία σειράς ρυθμίσεων."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Μενού λειτουργίας"</string>
@@ -884,13 +877,23 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> ενεργές εφαρμογές</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> ενεργή εφαρμογή</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Ενεργές εφαρμογές"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Διακοπή"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Διακόπηκε"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Αντιγραφή"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Αντιγράφηκε"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Από <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Παράβλεψη διεπαφής χρήστη αντιγραφής"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index cbbb8a7..f6dc314 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -236,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brightness"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Colour inversion"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Colour correction"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"More settings"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"User settings"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Done"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Close"</string>
@@ -460,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"You won\'t hear your next alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"at <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"on <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Quick Settings, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Hotspot"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Work profile"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Fun for some but not for all"</string>
@@ -639,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Signed in as <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"choose user"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"No Internet"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Open details."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Open <xliff:g id="ID_1">%s</xliff:g> settings."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Edit order of settings."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Power menu"</string>
@@ -880,6 +877,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> active apps</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> active app</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Active apps"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Stopped"</string>
@@ -887,4 +886,11 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copied"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"From <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Dismiss copy UI"</string>
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit copied text"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit copied image"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send to nearby device"</string>
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index cccfdd7..0b4e009 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -236,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brightness"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Colour inversion"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Colour correction"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"More settings"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"User settings"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Done"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Close"</string>
@@ -460,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"You won\'t hear your next alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"at <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"on <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Quick Settings, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Hotspot"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Work profile"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Fun for some but not for all"</string>
@@ -639,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Signed in as <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"choose user"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"No Internet"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Open details."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Open <xliff:g id="ID_1">%s</xliff:g> settings."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Edit order of settings."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Power menu"</string>
@@ -880,6 +877,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> active apps</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> active app</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Active apps"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Stopped"</string>
@@ -887,4 +886,11 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copied"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"From <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Dismiss copy UI"</string>
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit copied text"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit copied image"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send to nearby device"</string>
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index cbbb8a7..f6dc314 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -236,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brightness"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Colour inversion"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Colour correction"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"More settings"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"User settings"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Done"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Close"</string>
@@ -460,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"You won\'t hear your next alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"at <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"on <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Quick Settings, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Hotspot"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Work profile"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Fun for some but not for all"</string>
@@ -639,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Signed in as <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"choose user"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"No Internet"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Open details."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Open <xliff:g id="ID_1">%s</xliff:g> settings."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Edit order of settings."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Power menu"</string>
@@ -880,6 +877,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> active apps</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> active app</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Active apps"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Stopped"</string>
@@ -887,4 +886,11 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copied"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"From <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Dismiss copy UI"</string>
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit copied text"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit copied image"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send to nearby device"</string>
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index cbbb8a7..f6dc314 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -236,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brightness"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Colour inversion"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Colour correction"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"More settings"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"User settings"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Done"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Close"</string>
@@ -460,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"You won\'t hear your next alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"at <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"on <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Quick Settings, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Hotspot"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Work profile"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Fun for some but not for all"</string>
@@ -639,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Signed in as <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"choose user"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"No Internet"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Open details."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Open <xliff:g id="ID_1">%s</xliff:g> settings."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Edit order of settings."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Power menu"</string>
@@ -880,6 +877,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> active apps</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> active app</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Active apps"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Stopped"</string>
@@ -887,4 +886,11 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copied"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"From <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Dismiss copy UI"</string>
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit copied text"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit copied image"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send to nearby device"</string>
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 9e87af7..18d87f3 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -236,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brightness"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Color inversion"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Color correction"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"More settings"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"User settings"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Done"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Close"</string>
@@ -460,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"You won\'t hear your next alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"at <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"on <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Quick Settings, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Hotspot"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Work profile"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Fun for some but not for all"</string>
@@ -639,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Signed in as <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"choose user"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"No internet"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Open details."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Open <xliff:g id="ID_1">%s</xliff:g> settings."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Edit order of settings."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Power menu"</string>
@@ -880,6 +877,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> active apps</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> active app</item>
</plurals>
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"New information"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Active apps"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Stopped"</string>
@@ -887,4 +885,9 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copied"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"From <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Dismiss copy UI"</string>
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit copied text"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit copied image"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send to nearby device"</string>
+ <string name="add" msgid="81036585205287996">"Add"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Manage users"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index be7926b..3f1cc42 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Permitir"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"No tienes permitida la depuración por USB"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"El usuario al que accediste en este dispositivo no puede activar la depuración por USB. Para usar esta función, debes cambiar al usuario principal."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"¿Quiere cambiar el idioma del sistema a <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Cambio de idioma del sistema solicitado por otro dispositivo"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Cambiar idioma"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Mantener el idioma actual"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"¿Quieres permitir la depuración inalámbrica en esta red?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Nombre de red (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nDirección Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Permitir siempre en esta red"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brillo"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversión de color"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Corrección de colores"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Más configuraciones"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Configuración del usuario"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Listo"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Cerrar"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"No oirás la próxima alarma a la(s) <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"a la(s) <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"el <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Configuración rápida: <xliff:g id="TITLE">%s</xliff:g>"</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Hotspot"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Perfil de trabajo"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Diversión para algunos, pero no para todos"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Accediste como <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"elegir usuario"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Sin Internet"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Abrir página de detalles"</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Abrir configuración de <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Editar orden de configuración"</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menú de encendido"</string>
@@ -876,21 +869,31 @@
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para cambiar de red, desconéctate de Ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Para mejorar la experiencia con el dispositivo, las apps y los servicios pueden seguir buscando redes Wi-Fi en cualquier momento, incluso cuando la conexión Wi-Fi esté desactivada. Puedes cambiar este parámetro en la configuración de búsqueda de Wi-Fi. "<annotation id="link">"Cambiar"</annotation></string>
<string name="turn_off_airplane_mode" msgid="8425587763226548579">"Desactivar el modo de avión"</string>
- <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> quiere agregar el siguiente azulejo a la Configuración rápida"</string>
- <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Agregar azulejo"</string>
- <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"No agregar azulejo"</string>
+ <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> quiere agregar la siguiente tarjeta a la Configuración rápida"</string>
+ <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Agregar tarjeta"</string>
+ <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"No agregar tarjeta"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Seleccionar usuario"</string>
<plurals name="fgs_manager_footer_label" formatted="false" msgid="9091110396713032871">
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> apps activas</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> app activa</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Apps activas"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Detener"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Detenida"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Copiar"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Se copió"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"De <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Descartar la copia de la IU"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 5aa0caa..b84ed65 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Permitir"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Depuración USB no permitida"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"El usuario con el que se ha iniciado sesión en este dispositivo no puede activar la depuración USB. Para utilizar esta función, inicia sesión con la cuenta de usuario principal."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"¿Quieres cambiar el idioma del sistema a <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Otro dispositivo ha solicitado un cambio en el idioma del sistema"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Cambiar idioma"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Seguir en este idioma"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"¿Permitir la depuración inalámbrica en esta red?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Nombre de la red (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nDirección Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Permitir siempre en esta red"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brillo"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Invertir colores"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Corrección de color"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Más ajustes"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Ajustes de usuario"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Hecho"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Cerrar"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"No oirás la próxima alarma (<xliff:g id="WHEN">%1$s</xliff:g>)"</string>
<string name="alarm_template" msgid="2234991538018805736">"a las <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Ajustes rápidos, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Compartir Internet"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Perfil de trabajo"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Diversión solo para algunos"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Has iniciado sesión como <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"elegir un usuario"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Sin Internet"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Abrir detalles."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Abrir ajustes de <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Cambiar el orden de los ajustes."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menú de encendido"</string>
@@ -884,13 +877,23 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aplicaciones activas</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aplicación activa</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aplicaciones activas"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Detener"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Detenida"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Copiar"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copiado"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Cerrar la interfaz de copia"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 36e09a2..91250c3 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Luba"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB-silumine pole lubatud"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Sellesse seadmesse praegu sisse logitud kasutaja ei saa USB-silumist sisse lülitada. Selle funktsiooni kasutamiseks vahetage peamisele kasutajale."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Kas soovite süsteemi keeleks määrata järgmise: <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Teine seade taotles süsteemi keele muutmist"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Muuda keelt"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Kasuta praegust keelt"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Kas lubada selles võrgus juhtmevaba silumine?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Võrgu nimi (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWiFi-võrgu aadress (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Luba selles võrgus alati"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Heledus"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Värvide ümberpööramine"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Värviparandus"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Rohkem seadeid"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Kasutaja seaded"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Valmis"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Sule"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Te ei kuule järgmist äratust kell <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"kell <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"kell <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Kiirseaded, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Kuumkoht"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Tööprofiil"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Kõik ei pruugi sellest rõõmu tunda"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Sisse logitud kasutajana <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"valige kasutaja"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Interneti-ühendus puudub"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Ava üksikasjad."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Ava teenuse <xliff:g id="ID_1">%s</xliff:g> seaded."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Muuda seadete järjestust."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Toitemenüü"</string>
@@ -884,13 +877,23 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktiivset rakendust</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aktiivne rakendus</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktiivsed rakendused"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Peata"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Peatatud"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Kopeeri"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopeeritud"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Rakendusest <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Koopiast loobumise kasutajaliides"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 07d9cef..b531794 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -236,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Distira"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Kolore-alderantzikatzea"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Koloreen zuzenketa"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Ezarpen gehiago"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Erabiltzaile-ezarpenak"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Eginda"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Itxi"</string>
@@ -460,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Ez duzu entzungo hurrengo alarma (<xliff:g id="WHEN">%1$s</xliff:g>)"</string>
<string name="alarm_template" msgid="2234991538018805736">"ordua: <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"data: <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Ezarpen bizkorrak: <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Wifi-gunea"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Work profila"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Dibertsioa batzuentzat, baina ez guztientzat"</string>
@@ -639,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> gisa hasi duzu saioa"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"erabiltzailea aukeratzeko"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Ez dago Interneteko konexiorik"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Ireki xehetasunak."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Ireki <xliff:g id="ID_1">%s</xliff:g> ezarpenak."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Editatu ezarpenen ordena."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Itzaltzeko menua"</string>
@@ -880,13 +877,23 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aplikazio aktibo</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aplikazio aktibo</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktibo dauden aplikazioak"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Gelditu"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Geldituta"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Kopiatu"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopiatu da"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Jatorria: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Kopiatutako UIa baztertzeko botoia"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 9545c31..642a826 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"اجازه دادن"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"اشکالزدایی USB مجاز نیست"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"کاربری که درحال حاضر در این دستگاه وارد سیستم شده است نمیتواند اشکالزدایی USB را روشن کند. برای استفاده از این قابلیت، به کاربر اصلی تغییر وضعیت دهید."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"آیا میخواهید زبان سیستم به <xliff:g id="LANGUAGE">%1$s</xliff:g> تغییر کند؟"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"دستگاه دیگری درخواست کرده است زبان سیستم تغییر کند"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"تغییر زبان"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"حفظ زبان فعلی"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"اشکالزدایی بیسیم در این شبکه مجاز شود؟"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"نام شبکه (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nنشانی Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"همیشه در این شبکه مجاز شود"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"روشنایی"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"وارونگی رنگ"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"تصحیح رنگ"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"تنظیمات بیشتر"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"تنظیمات کاربر"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"تمام"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"بستن"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"در ساعت <xliff:g id="WHEN">%1$s</xliff:g>، دیگر صدای زنگ ساعت را نمیشنوید"</string>
<string name="alarm_template" msgid="2234991538018805736">"در <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"در <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"تنظیمات سریع، <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"نقطه اتصال"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"نمایه کاری"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"برای بعضی افراد سرگرمکننده است اما نه برای همه"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"بهعنوان <xliff:g id="ID_1">%s</xliff:g> به سیستم وارد شدهاید"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"انتخاب کاربر"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"عدم اتصال به اینترنت"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"باز کردن جزئیات."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"باز کردن تنظیمات <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"ویرایش ترتیب تنظیمات."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"منوی روشن/خاموش"</string>
@@ -884,13 +877,23 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> برنامه فعال</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> برنامه فعال</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"برنامههای فعال"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"توقف"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"متوقف شد"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"کپی کردن"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"کپی شد"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"از <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"رد کردن رابط کاربری کپی کردن"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index f398871..a9c11bc 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Salli"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB-vianetsintää ei sallita"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Laitteelle tällä hetkellä kirjautunut käyttäjä ei voi ottaa USB-vianetsintää käyttöön. Vaihda käyttäjäksi ensisijainen käyttäjä, jotta voit käyttää tätä ominaisuutta."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Haluatko, että järjestelmän kieli on jatkossa <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Toiselta laitteelta pyydetty järjestelmän kielen vaihtamista"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Vaihda kieltä"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Pidä nykyinen kieli"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Sallitaanko langaton virheenkorjaus tässä verkossa?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Verkon nimi (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi-Fin osoite (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Salli aina tässä verkossa"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Kirkkaus"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Käänteiset värit"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Värinkorjaus"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Lisäasetukset"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Käyttäjäasetukset"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Valmis"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Sulje"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Et kuule seuraavaa hälytystäsi (<xliff:g id="WHEN">%1$s</xliff:g>)."</string>
<string name="alarm_template" msgid="2234991538018805736">"kello <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"ajankohtana <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Pika-asetukset, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Hotspot"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Työprofiili"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Ei sovellu kaikkien käyttöön"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Kirjautunut tilillä <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"valitse käyttäjä"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Ei internetyhteyttä"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Avaa tiedot."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Avaa kohteen <xliff:g id="ID_1">%s</xliff:g> asetukset."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Muokkaa asetusten järjestystä."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Virtavalikko"</string>
@@ -884,13 +877,23 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktiivista sovellusta</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aktiivinen sovellus</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktiiviset sovellukset"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Lopeta"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Pysäytetty"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Kopioi"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopioitu"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Lähde: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Hylkää kopioitu UI"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 89ede7e..3ee8efa 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Autoriser"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Débogage USB non autorisé"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"L\'utilisateur actuellement connecté sur cet appareil ne peut pas activer le débogage USB. Pour utiliser cette fonctionnalité, l\'utilisateur principal doit se connecter."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Voulez-vous changer la langue du système pour : <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Un autre appareil demande de changer la langue du système"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Changer la langue"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Garder la langue actuelle"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Autoriser le débogage sans fil sur ce réseau?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Nom du réseau (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAdresse Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Toujours autoriser sur ce réseau"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Luminosité"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversion des couleurs"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Correction des couleurs"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Plus de paramètres"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Paramètres utilisateur"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Terminé"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Fermer"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Vous n\'entendrez pas votre prochaine alarme à <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"à <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"le <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Configuration rapide – <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Point d\'accès sans fil"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Profil professionnel"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Divertissant pour certains, mais pas pour tous"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Connecté comme <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"choisir un utilisateur"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Aucune connexion Internet"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Ouvrir les détails."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Ouvrir les paramètres <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Modifier l\'ordre des paramètres."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu de l\'interrupteur"</string>
@@ -884,13 +877,23 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> application active</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> applications actives</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Applications actives"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Arrêter"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Arrêtée"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Copier"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copié"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"À partir de <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Ignorer la copie de l\'IU"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 3e7bdd6..0af35ba 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Autoriser"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Débogage USB non autorisé"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"L\'utilisateur actuellement connecté sur cet appareil ne peut pas activer le débogage USB. Pour utiliser cette fonctionnalité, l\'utilisateur principal doit se connecter."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Voulez-vous définir la langue système sur <xliff:g id="LANGUAGE">%1$s</xliff:g> ?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Changement de langue système demandé par un autre appareil"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Changer de langue"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Garder la langue actuelle"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Autoriser le débogage sans fil sur ce réseau ?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Nom du réseau (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAdresse Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Toujours autoriser sur ce réseau"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Luminosité"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversion des couleurs"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Correction des couleurs"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Plus de paramètres"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Paramètres utilisateur"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"OK"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Fermer"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Vous n\'entendrez pas votre prochaine alarme <xliff:g id="WHEN">%1$s</xliff:g>."</string>
<string name="alarm_template" msgid="2234991538018805736">"à <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"le <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Réglages rapides – <xliff:g id="TITLE">%s</xliff:g>"</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Point d\'accès"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Profil professionnel"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Divertissant pour certains, mais pas pour tous"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Connecté en tant que <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"choisir un utilisateur"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Aucun accès à Internet"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Ouvrir les détails."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Ouvrir les paramètres <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Modifier l\'ordre des paramètres."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu Marche/Arrêt"</string>
@@ -884,13 +877,23 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> appli active</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> applis actives</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Applis actives"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Arrêter"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Arrêtée"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Copier"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copié"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"De <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Désactiver l\'interface de copie"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 9b7c20b..81efcb5 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Permitir"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Non se permite a depuración por USB"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"O usuario coa sesión iniciada actualmente neste dispositivo non pode activar a depuración por USB. Para utilizar esta función, cambia ao usuario principal."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Queres cambiar o idioma do sistema ao <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Outro dispositivo solicitou un cambio do idioma do sistema"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Cambiar idioma"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Manter idioma actual"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Queres permitir a depuración sen fíos nesta rede?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Nome de rede (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nEnderezo wifi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Permitir sempre nesta rede"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brillo"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversión da cor"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Corrección da cor"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Máis opcións"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Configuración de usuario"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Feito"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Pechar"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Non escoitarás a alarma seguinte <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"ás <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"o <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Configuración rápida: <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Zona wifi"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Perfil de traballo"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Diversión só para algúns"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Sesión iniciada como <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"escoller usuario"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Non hai conexión a Internet"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Abrir detalles."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Abrir configuración de <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Editar a orde das opcións de configuración."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menú de acendido"</string>
@@ -884,13 +877,23 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aplicacións activas</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aplicación activa</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aplicacións activas"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Deter"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Detida"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Copiar"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copiouse"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"De <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Ignorar interface de copia"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 565f9af..98510d5 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"મંજૂરી આપો"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB ડીબગિંગની મંજૂરી નથી"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"હાલમાં આ ઉપકરણમાં સાઇન ઇન થયેલ વપરાશકર્તા USB ડિબગીંગ ચાલુ કરી શકતા નથી. આ સુવિધાનો ઉપયોગ કરવા માટે પ્રાથમિક વપરાશકર્તા પર સ્વિચ કરો."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"શું તમે સિસ્ટમની ભાષા બદલીને <xliff:g id="LANGUAGE">%1$s</xliff:g> કરવા માગો છો?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"બીજા ડિવાઇસ દ્વારા સિસ્ટમની ભાષા બદલવાની વિનંતી કરવામાં આવી છે"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"ભાષા બદલો"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"વર્તમાન ભાષા રાખો"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"આ નેટવર્ક પર વાયરલેસ ડિબગીંગની મંજૂરી આપીએ?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"નેટવર્કનું નામ (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nવાઇ-ફાઇ ઍડ્રેસ (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"આ નેટવર્ક પર હંમેશા મંજૂરી આપો"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"તેજ"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"વિપરીત રંગમાં બદલવું"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"રંગ સુધારણા"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"વધુ સેટિંગ"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"વપરાશકર્તા સેટિંગ"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"થઈ ગયું"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"બંધ કરો"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"તમે <xliff:g id="WHEN">%1$s</xliff:g> એ તમારો આગલો એલાર્મ સાંભળશો નહીં"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> વાગ્યે"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> એ"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"ઝડપી સેટિંગ, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"હૉટસ્પૉટ"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"ઑફિસની પ્રોફાઇલ"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"કેટલાક માટે મજા પરંતુ બધા માટે નહીં"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> તરીકે સાઇન ઇન કર્યું"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"વપરાશકર્તા પસંદ કરો"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"કોઈ ઇન્ટરનેટ નથી"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"વિગતો ખોલો."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g> સેટિંગ ખોલો."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"સેટિંગના ક્રમમાં ફેરફાર કરો."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"પાવર મેનૂ"</string>
@@ -884,13 +877,23 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> સક્રિય ઍપ</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> સક્રિય ઍપ</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"સક્રિય ઍપ"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"રોકો"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"બંધ કરેલી છે"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"કૉપિ કરો"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"કૉપિ કરવામાં આવી"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g>માંથી"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"\'UI | યૂઝર ઇન્ટરફેસ (UI) કૉપિ કરો\'ને છોડી દો"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index f643c87..2631f55 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -236,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"स्क्रीन की रोशनी"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"रंग बदलने की सुविधा"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"रंग में सुधार करने की सुविधा"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"और सेटिंग"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"उपयोगकर्ता सेटिंग"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"हो गया"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"बंद करें"</string>
@@ -460,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"आपको <xliff:g id="WHEN">%1$s</xliff:g> पर अपना अगला अलार्म नहीं सुनाई देगा"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> बजे"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> पर"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"तेज़ सेटिंग, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"हॉटस्पॉट"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"वर्क प्रोफ़ाइल"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"कुछ के लिए मज़ेदार लेकिन सबके लिए नहीं"</string>
@@ -639,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> के रूप में प्रवेश किया हुआ है"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"उपयोगकर्ता चुनें"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"इंटरनेट कनेक्शन नहीं है"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"विवरण खोलें."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g> सेटिंग खोलें."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"सेटिंग के क्रम को बदलें"</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"पावर मेन्यू"</string>
@@ -880,13 +877,23 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> ऐप्लिकेशन चालू है</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> ऐप्लिकेशन चालू हैं</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"ये ऐप्लिकेशन चालू हैं"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"बंद करें"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"रुका हुआ है"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"कॉपी करें"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"कॉपी किया गया"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> से"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"कॉपी किया गया यूज़र इंटरफ़ेस (यूआई) खारिज करें"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 51b6131..da84b86 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Dopusti"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Otklanjanje pogrešaka putem USB-a nije dopušteno"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Korisnik koji je trenutačno prijavljen na ovaj uređaj ne može uključiti otklanjanje pogrešaka putem USB-a. Da biste upotrebljavali tu značajku, prijeđite na primarnog korisnika."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Želite li promijeniti jezik sustava u <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Drugi uređaj zatražio je promjenu jezika sustava"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Promijeni jezik"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Zadrži trenutačni jezik"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Dopustiti bežično otklanjanje pogrešaka na ovoj mreži?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Naziv mreže (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAdresa Wi‑Fija (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Uvijek dopusti na ovoj mreži"</string>
@@ -241,7 +237,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Svjetlina"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inverzija boja"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Korekcija boja"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Više postavki"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Korisničke postavke"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Gotovo"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Zatvori"</string>
@@ -467,7 +462,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Nećete čuti sljedeći alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"u <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"u <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Brze postavke, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Žarišna točka"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Poslovni profil"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Zabava za neke, ali ne za sve"</string>
@@ -648,7 +642,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Prijavljeni ste kao <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"odaberi korisnika"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Nema interneta"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Otvaranje pojedinosti."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Otvaranje postavki za <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Uređivanje redoslijeda postavki."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Izbornik tipke za uključivanje/isključivanje"</string>
@@ -891,13 +884,23 @@
<item quantity="few"><xliff:g id="COUNT_1">%s</xliff:g> aktivne aplikacije</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktivnih aplikacija</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktivne aplikacije"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Zaustavi"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Zaustavljeno"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Kopiraj"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopirano"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Iz aplikacije <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Odbaci kopiranje korisničkog sučelja"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index d6430f2..30a5be8 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Engedélyezés"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Az USB hibakeresése nem engedélyezett"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Az eszközre jelenleg bejelentkezett felhasználó nem engedélyezheti az USB-hibakeresést. A funkció használatához váltson az elsődleges felhasználóra."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Kívánja <xliff:g id="LANGUAGE">%1$s</xliff:g> nyelvre módosítani a rendszer nyelvét?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Egy másik eszköz a rendszer nyelvének módosítását kéri"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Nyelvmódosítás"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Aktuális nyelv megtartása"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Engedélyezi a vezeték nélküli hibakeresést ezen a hálózaton?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Hálózat neve (SSID):\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi-cím (BSSID):\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Mindig engedélyezze ezen a hálózaton"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Fényerő"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Színek invertálása"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Színjavítás"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"További beállítások"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Felhasználói beállítások"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Kész"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Bezárás"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Nem fogja hallani az ébresztést ekkor: <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"ekkor: <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"ezen a napon: <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Gyorsbeállítások – <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Hotspot"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Munkaprofil"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Egyeseknek tetszik, másoknak nem"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Bejelentkezve mint <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"felhasználó kiválasztása"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Nincs internetkapcsolat"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"A részletek megnyitása."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"A(z) <xliff:g id="ID_1">%s</xliff:g> beállításainak megnyitása."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Beállítások sorrendjének szerkesztése."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Bekapcsológombhoz tartozó menü"</string>
@@ -884,13 +877,20 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktív alkalmazás</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aktív alkalmazás</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktív alkalmazások"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Leállítás"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Leállítva"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Másolás"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Másolva"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Forrás: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Másolási UI elvetése"</string>
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Vágólapra másolt szöveg szerkesztése"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Vágólapra másolt kép szerkesztése"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Küldés közeli eszközre"</string>
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index daa48f7..443da54 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Թույլատրել"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB-ով վրիպազերծումը թույլատրված չէ"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Ընթացիկ հաշվի միջոցով չեք կարող միացնել USB-ով վրիպազերծումը: Այս գործառույթը միացնելու համար մուտք գործեք հիմնական օգտատիրոջ հաշիվ:"</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Դարձնե՞լ համակարգի լեզուն <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Մեկ այլ սարք համակարգի լեզվի փոփոխության հարցում է ուղարկել"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Փոխել լեզուն"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Թողնել ընթացիկ լեզուն"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Թույլատրե՞լ անլար վրիպազերծումն այս ցանցում"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Ցանցի անվանումը (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi-ի հասցեն (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Միշտ թույլատրել այս ցանցում"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Պայծառություն"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Գունաշրջում"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Գունաշտկում"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Հավելյալ կարգավորումներ"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Օգտատիրոջ կարգավորումներ"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Պատրաստ է"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Փակել"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Ժամը <xliff:g id="WHEN">%1$s</xliff:g>-ի զարթուցիչը չի զանգի"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>-ին"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>-ին"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Արագ կարգավորումներ, <xliff:g id="TITLE">%s</xliff:g>:"</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Թեժ կետ"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Աշխատանքային պրոֆիլ"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Զվարճանք մեկ՝ որոշակի մարդու համար"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Մուտք է գործել որպես <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"ընտրել օգտատեր"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Ինտերնետ կապ չկա"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Բացել մանրամասները:"</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Բացել <xliff:g id="ID_1">%s</xliff:g> կարգավորումները:"</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Խմբագրել կարգավորումների հերթականությունը:"</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Սնուցման կոճակի ընտրացանկ"</string>
@@ -884,13 +877,23 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> ակտիվ հավելված</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> ակտիվ հավելված</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Ակտիվ հավելվածներ"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Դադարեցնել"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Կանգնեցված է"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Պատճենել"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Պատճենվեց"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> հավելվածից"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Փակել պատճենների միջերեսը"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index dd1a2fa..c7339c7 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Izinkan"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Debug USB tidak diizinkan"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Pengguna yang sedang login ke perangkat ini tidak dapat mengaktifkan proses debug USB. Beralihlah ke pengguna utama untuk menggunakan fitur ini."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Ingin mengubah bahasa sistem menjadi <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Perubahan bahasa sistem diminta oleh perangkat lain"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Ubah bahasa"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Pertahankan bahasa"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Izinkan proses debug nirkabel di perangkat ini?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Nama Jaringan (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAlamat Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Selalu izinkan di jaringan ini"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Kecerahan"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversi warna"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Koreksi warna"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Setelan lainnya"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Setelan pengguna"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Selesai"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Tutup"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Anda tidak akan mendengar alarm berikutnya <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"pukul <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"pada <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Setelan Cepat, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Hotspot"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Profil kerja"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Tidak semua orang menganggapnya baik"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Login sebagai <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"memilih pengguna"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Tidak ada internet"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Buka detail."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Buka setelan <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Edit urutan setelan."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu daya"</string>
@@ -884,13 +877,23 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aplikasi aktif</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aplikasi aktif</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aplikasi aktif"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Berhenti"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Dihentikan"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Salin"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Disalin"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Dari <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Tutup UI salin"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 624dca7..eddd246 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Leyfa"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB-villuleit ekki leyfð"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Notandinn sem er skráður inn í þetta tæki núna getur ekki kveikt á USB-villuleit. Til þess að nota þennan eiginleika skaltu skipta yfir í aðalnotandann."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Viltu breyta tungumáli kerfis í <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Beiðni frá öðru tæki um að breyta tungumáli kerfis"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Breyta tungumáli"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Halda núverandi tungumáli"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Viltu leyfa þráðlausa villuleit á þessu neti?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Heiti netkerfis (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi vistfang (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Leyfa alltaf á þessu neti"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Birtustig"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Umsnúningur lita"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Litaleiðrétting"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Fleiri stillingar"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Notandastillingar"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Lokið"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Loka"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Ekki mun heyrast í vekjaranum <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Flýtistillingar, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Heitur reitur"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Vinnusnið"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Þetta er ekki allra"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Skráð(ur) inn sem <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"velja notanda"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Engin nettenging"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Opna upplýsingasíðu."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Opna <xliff:g id="ID_1">%s</xliff:g> stillingar."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Breyta röð stillinga."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Aflrofavalmynd"</string>
@@ -884,13 +877,23 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> virkt forrit</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> virk forrit</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Virk forrit"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stöðva"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Stöðvað"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Afrita"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Afritað"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Frá <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Loka afriti notendaviðmóts"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index b437bb1..6a07f79 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Consenti"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Debug USB non consentito"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"L\'utente che ha eseguito l\'accesso a questo dispositivo non può attivare il debug USB. Per utilizzare questa funzione, passa all\'utente principale."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Vuoi cambiare la lingua di sistema con la lingua <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Cambio della lingua di sistema richiesto da un altro dispositivo"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Cambia lingua"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Mantieni lingua attuale"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Consentire il debug wireless su questa rete?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Nome della rete (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nIndirizzo Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Consenti sempre su questa rete"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Luminosità"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversione dei colori"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Correzione del colore"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Altre impostazioni"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Impostazioni utente"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Fine"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Chiudi"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Non sentirai la tua prossima sveglia <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"alle <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Impostazioni rapide: <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Hotspot"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Profilo di lavoro"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Il divertimento riservato a pochi eletti"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Accesso eseguito come <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"selezionare l\'utente"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Nessuna connessione a Internet"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Apri i dettagli."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Apri le impostazioni <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Modifica l\'ordine delle impostazioni."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu del tasto di accensione"</string>
@@ -884,6 +877,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> app attiva</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> app attive</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"App attive"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Interrompi"</string>
<!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
@@ -893,4 +888,11 @@
<!-- no translation found for clipboard_edit_source (9156488177277788029) -->
<skip />
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Ignora copia UI"</string>
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Modifica testo copiato"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Modifica immagine copiata"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Invia a dispositivo nelle vicinanze"</string>
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index f6f094d..f959774 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"יש אישור"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"לא ניתן לבצע ניפוי באגים ב-USB"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"למשתמש המחובר לחשבון במכשיר הזה אין אפשרות להפעיל ניפוי באגים ב-USB. כדי להשתמש בתכונה הזו יש לעבור אל המשתמש הראשי."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"רוצה לשנות את שפת המערכת ל<xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"התקבלה בקשה ממכשיר אחר לשינוי שפת המערכת"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"שינוי שפה"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"השארת השפה הנוכחית"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"לאשר ניפוי באגים אלחוטי ברשת הזו?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"שם הרשת (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nכתובת Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"לאשר תמיד ברשת הזו"</string>
@@ -242,7 +238,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"בהירות"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"היפוך צבעים"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"תיקון צבע"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"הגדרות נוספות"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"הגדרות המשתמש"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"בוצע"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"סגירה"</string>
@@ -470,7 +465,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"לא ניתן יהיה לשמוע את ההתראה הבאה שלך <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"בשעה <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"ב-<xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"הגדרות מהירות, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"נקודת אינטרנט (hotspot)"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"פרופיל עבודה"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"מהנה בשביל חלק מהאנשים, אבל לא בשביל כולם"</string>
@@ -653,7 +647,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"בוצעה כניסה בתור <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"בחירת משתמש"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"אין אינטרנט"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"פתיחת פרטים."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"פתיחת הגדרות של <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"עריכת סדר ההגדרות."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"תפריט הפעלה"</string>
@@ -898,13 +891,23 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> אפליקציות פעילות</item>
<item quantity="one">אפליקציה פעילה אחת (<xliff:g id="COUNT_0">%s</xliff:g>)</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"אפליקציות פעילות"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"עצירה"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"הופסקה"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"העתקה"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"הועתק"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"המקור: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"ביטול של העתקת ממשק המשתמש"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 4a57a0b..05ddace 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"許可"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB デバッグは許可されていません"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"このデバイスに現在ログインしているユーザーでは、USB デバッグを ON にすることはできません。この機能を使用するには、メインユーザーに切り替えてください。"</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"システム言語を<xliff:g id="LANGUAGE">%1$s</xliff:g>に変更しますか?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"他のデバイスからシステム言語の変更が要求されました"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"言語を変更"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"現在の言語を変更しない"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"このネットワークでワイヤレス デバッグを許可しますか?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"ネットワーク名(SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi アドレス(BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"このネットワークで常に許可する"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"画面の明るさ"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"色反転"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"色補正"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"詳細設定"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ユーザー設定"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"完了"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"閉じる"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"次回のアラーム(<xliff:g id="WHEN">%1$s</xliff:g>)は鳴りません"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"クイック設定、<xliff:g id="TITLE">%s</xliff:g>。"</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"アクセスポイント"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"仕事用プロファイル"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"一部の方のみお楽しみいただける限定公開ツール"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> としてログインします"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"ユーザーを選択"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"インターネットに接続されていません"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"詳細情報を開きます。"</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g> の設定を開きます。"</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"設定の順序を編集します。"</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"電源ボタン メニュー"</string>
@@ -884,13 +877,20 @@
<item quantity="other">有効なアプリ: <xliff:g id="COUNT_1">%s</xliff:g> 個</item>
<item quantity="one">有効なアプリ: <xliff:g id="COUNT_0">%s</xliff:g> 個</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"有効なアプリ"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"停止"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"停止中"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"コピー"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"コピーしました"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> から"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"コピー UI を閉じる"</string>
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"コピーしたテキストを編集"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"コピーした画像を編集"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"付近のデバイスに送信"</string>
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index d02a946..cf77cac 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"დაშვება"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB ხარვეზების გამართვა ნებადართული არაა"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"ამ მოწყობილობაზე ამჟამად შესულ მომხმარებელს არ შეუძლია USB ხარვეზების გამართვის ფუნქციის ჩართვა. ამ ფუნქციის გამოსაყენებლად, მიუერთდით მთავარ მომხმარებელს."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"გსურთ, სისტემის ენა შეიცვალოს და გახდეს <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"სისტემის ენის შეცვლა მოითხოვა სხვა მოწყობილობამ"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"ენის შეცვლა"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"მიმდინარე ენის დატოვება"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"დაუშვებთ ამ ქსელში შეცდომების უსადენო გამართვას?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"ქსელის სახელი (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi მისამართი (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"ყოველთვის დაშვება ამ ქსელში"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"განათება"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"ფერთა ინვერსია"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"ფერთა კორექცია"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"დამატებითი პარამეტრები"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"მომხმარებლის პარამეტრები"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"დასრულდა"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"დახურვა"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"ვერ გაიგონებთ მომდევნო მაღვიძარას <xliff:g id="WHEN">%1$s</xliff:g>-ზე"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>-ზე"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>-ზე"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"სწრაფი პარამეტრები, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"წვდომის წერტილი"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"სამსახურის პროფილი"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"ზოგისთვის გასართობია, მაგრამ არა ყველასთვის"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"შესული ხართ, როგორც <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"მომხმარებლის არჩევა"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"ინტერნეტ-კავშირი არ არის"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"დეტალების გახსნა."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g> პარამეტრების გახსნა."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"პარამეტრების მიმდევრობის რედაქტირება."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"ჩართვის მენიუ"</string>
@@ -884,13 +877,20 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> აქტიური აპი</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> აქტიური აპი</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"აქტიური აპები"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"შეწყვეტა"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"შეწყვეტილია"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"კოპირება"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"კოპირებულია"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g>-დან"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"მომხმარებლის ინტერფეისის ასლის გაუქმება"</string>
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"კოპირებული ტექსტის რედაქტირება"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"კოპირებული სურათის რედაქტირება"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ახლომახლო მოწყობილობაზე გაგზავნა"</string>
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index c4332fc..32d2e51 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Рұқсат беру"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB арқылы түзетуге рұқсат етілмеген"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Бұл құрылғыға қазір кірген пайдаланушы USB арқылы түзетуді іске қосылмайды. Бұл мүмкіндікті пайдалану үшін негізгі пайдаланушыға ауысыңыз."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Жүйе тілін басқа тілге (<xliff:g id="LANGUAGE">%1$s</xliff:g>) ауыстырғыңыз келе ме?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Басқа құрылғыдан жүйе тілін өзгерту туралы сұрау жіберілді."</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Тілді өзгерту"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Қазіргі тіл тұра берсін"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Бұл желіде сымсыз түзетуге рұқсат етілсін бе?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Желі атауы (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi мекенжайы (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Осы желіде үнемі рұқсат ету"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Жарықтығы"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Түс инверсиясы"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Түсті түзету"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Қосымша параметрлер"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Пайдаланушы параметрлері"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Дайын"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Жабу"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Келесі <xliff:g id="WHEN">%1$s</xliff:g> дабылыңызды есітпейсіз"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Жылдам параметрлер, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Хотспот"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Жұмыс профилі"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Кейбіреулерге қызық, бірақ барлығына емес"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> ретінде кірдіңіз"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"пайдаланушыны таңдаңыз"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Интернетпен байланыс жоқ"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Мәліметтерді ашу."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g> параметрлерін ашу."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Параметрлер тәртібін өзгерту."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Қуат мәзірі"</string>
@@ -884,13 +877,23 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> белсенді қолданба</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> белсенді қолданба</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Белсенді қолданбалар"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Тоқтату"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Тоқтатылған"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Көшіру"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Көшірілді"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> қолданбасынан"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Көшіру интерфейсін жабу"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 7ac68e3..581d3e6 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"អនុញ្ញាត"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"មិនអនុញ្ញាតការកែកំហុសតាម USB ទេ"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"អ្នកប្រើដែលបច្ចុប្បន្នបានចូលគណនីនៅលើឧបករណ៍នេះមិនអាចបើកការកែកំហុស USB បានទេ។ ដើម្បីប្រើមុខងារនេះ សូមប្តូរទៅអ្នកប្រើចម្បង។"</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"តើអ្នកចង់ប្ដូរភាសាប្រព័ន្ធទៅភាសា<xliff:g id="LANGUAGE">%1$s</xliff:g>ដែរទេ?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"ការប្ដូរភាសាប្រព័ន្ធដែលបានស្នើសុំដោយឧបករណ៍ផ្សេងទៀត"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"ប្ដូរភាសា"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"រក្សាភាសាបច្ចុប្បន្ន"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"អនុញ្ញាតការជួសជុលដោយឥតខ្សែនៅលើបណ្ដាញនេះឬ?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"ឈ្មោះបណ្ដាញ (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nអាសយដ្ឋាន Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"អនុញ្ញាតនៅលើបណ្ដាញនេះជានិច្ច"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ពន្លឺ"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"ការបញ្ច្រាសពណ៌"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"ការកែតម្រូវពណ៌"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"ការកំណត់ច្រើនទៀត"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ការកំណត់អ្នកប្រើប្រាស់"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"រួចរាល់"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"បិទ"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"អ្នកនឹងមិនលឺម៉ោងរោទ៍ <xliff:g id="WHEN">%1$s</xliff:g> បន្ទាប់របស់អ្នកទេ"</string>
<string name="alarm_template" msgid="2234991538018805736">"នៅ <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"នៅ <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"ការកំណត់រហ័ស <xliff:g id="TITLE">%s</xliff:g>។"</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"ហតស្ប៉ត"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"ប្រវត្តិរូបការងារ"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"ល្អសម្រាប់អ្នកប្រើមួយចំនួន តែមិនសម្រាប់គ្រប់គ្នាទេ"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"បានចូលជា <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"ជ្រើសរើសអ្នកប្រើប្រាស់"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"គ្មានអ៊ីនធឺណិតទេ"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"បើកព័ត៌មានលម្អិត"</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"បើការកំណត់ <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"កែលំដាប់ការកំណត់"</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"ម៉ឺនុយថាមពល"</string>
@@ -884,13 +877,23 @@
<item quantity="other">កម្មវិធីសកម្ម <xliff:g id="COUNT_1">%s</xliff:g></item>
<item quantity="one">កម្មវិធីសកម្ម <xliff:g id="COUNT_0">%s</xliff:g></item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"កម្មវិធីសកម្ម"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ឈប់"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"បានឈប់"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"ចម្លង"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"បានចម្លង"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"ពី <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"ច្រានចោល UI ចម្លង"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index dbf4f16..f1428a0 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -236,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ಪ್ರಕಾಶಮಾನ"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"ಕಲರ್ ಇನ್ವರ್ಶನ್"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"ಬಣ್ಣದ ತಿದ್ದುಪಡಿ"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"ಹೆಚ್ಚಿನ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ಬಳಕೆದಾರರ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"ಮುಗಿದಿದೆ"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"ಮುಚ್ಚಿರಿ"</string>
@@ -460,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"ನಿಮ್ಮ ಮುಂದಿನ <xliff:g id="WHEN">%1$s</xliff:g> ಅಲಾರಮ್ ಅನ್ನು ನೀವು ಆಲಿಸುವುದಿಲ್ಲ"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> ರಲ್ಲಿ"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> ರಂದು"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್ಗಳು, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"ಹಾಟ್ಸ್ಪಾಟ್"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"ಕೆಲಸದ ಪ್ರೊಫೈಲ್"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"ಕೆಲವರಿಗೆ ಮೋಜು ಆಗಿದೆ ಎಲ್ಲರಿಗೆ ಇಲ್ಲ"</string>
@@ -639,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> ಅವರಂತೆ ಸೈನ್ ಇನ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"ಬಳಕೆದಾರರನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"ಇಂಟರ್ನೆಟ್ ಇಲ್ಲ"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"ವಿವರಗಳನ್ನು ತೆರೆಯಿರಿ."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g> ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ತೆರೆಯಿರಿ."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"ಸೆಟ್ಟಿಂಗ್ಗಳ ಕ್ರಮವನ್ನು ಎಡಿಟ್ ಮಾಡಿ."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"ಪವರ್ ಮೆನು"</string>
@@ -880,13 +877,20 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> ಸಕ್ರಿಯ ಆ್ಯಪ್ಗಳು</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> ಸಕ್ರಿಯ ಆ್ಯಪ್ಗಳು</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"ಸಕ್ರಿಯ ಆ್ಯಪ್ಗಳು"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ನಿಲ್ಲಿಸಿ"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"ನಿಲ್ಲಿಸಿದೆ"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"ನಕಲಿಸಿ"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"ನಕಲಿಸಲಾಗಿದೆ"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> ನಿಂದ"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"UI ನಕಲನ್ನು ವಜಾಗೊಳಿಸಿ"</string>
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"ನಕಲಿಸಿದ ಪಠ್ಯವನ್ನು ಎಡಿಟ್ ಮಾಡಿ"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"ನಕಲಿಸಿದ ಚಿತ್ರವನ್ನು ಎಡಿಟ್ ಮಾಡಿ"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ಸಮೀಪದಲ್ಲಿರುವ ಸಾಧನಕ್ಕೆ ಕಳುಹಿಸಿ"</string>
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index eed00ee..02246b4 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"허용"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB 디버깅이 허용되지 않음"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"현재 이 기기에 로그인한 사용자는 USB 디버깅을 사용 설정할 수 없습니다. 이 기능을 사용하려면 기본 사용자로 전환하세요."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"시스템 언어를 <xliff:g id="LANGUAGE">%1$s</xliff:g>로 변경하시겠습니까?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"다른 기기에서 시스템 언어 변경을 요청함"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"언어 변경"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"현재 언어 유지"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"이 네트워크에서 무선 디버깅을 허용하시겠습니까?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"네트워크 이름(SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi 주소(BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"이 네트워크에서 항상 허용"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"밝기"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"색상 반전"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"색상 보정"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"설정 더보기"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"사용자 설정"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"완료"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"닫기"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>에 다음 알람을 들을 수 없습니다."</string>
<string name="alarm_template" msgid="2234991538018805736">"시간: <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"일시: <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"빠른 설정하기, <xliff:g id="TITLE">%s</xliff:g>"</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"핫스팟"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"직장 프로필"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"마음에 들지 않을 수도 있음"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g>(으)로 로그인됨"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"사용자 선택"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"인터넷 연결 없음"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"세부정보 열기"</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g> 설정 열기"</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"설정 순서 수정"</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"전원 메뉴"</string>
@@ -884,13 +877,23 @@
<item quantity="other">활성 상태의 앱 <xliff:g id="COUNT_1">%s</xliff:g>개</item>
<item quantity="one">활성 상태의 앱 <xliff:g id="COUNT_0">%s</xliff:g>개</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"활성 상태의 앱"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"중지"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"중지됨"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"복사"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"복사됨"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"복사한 위치: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"UI 복사 닫기"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 343d52e..c8c56ca 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Уруксат берүү"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB мүчүлүштүктөрүн оңдоого уруксат жок"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Учурда бул аккаунтта USB аркылуу мүчүлүштүктөрдү аныктоо функциясын иштетүүгө болбойт. Негизги колдонуучунун аккаунтуна кириңиз."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Тутум тилин <xliff:g id="LANGUAGE">%1$s</xliff:g> тилине өзгөртөсүзбү?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Тутум тилин өзгөртүү сурамы башка түзмөктөн жөнөтүлдү"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Тилди өзгөртүү"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Учурдагы тилди калтыруу"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Ушул тармакта мүчүлүштүктөрдү Wi-Fi аркылуу аныктоого уруксат бересизби?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Тармактын аталышы (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi дареги (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Бул тармакта ар дайым уруксат берилсин"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Жарыктыгы"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Түстү инверсиялоо"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Түсүн тууралоо"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Дагы жөндөөлөр"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Колдонуучунун жөндөөлөрү"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Бүттү"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Жабуу"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> боло турган кийинки эскертмени укпайсыз"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> болгондо"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> болгондо"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Ыкчам жөндөөлөр, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Байланыш түйүнү"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Жумуш профили"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Баарына эле жага бербейт"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> аккаунту менен кирди"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"колдонуучуну тандоо"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Интернет жок"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Чоо-жайын ачуу."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g> жөндөөлөрүн ачуу."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Жөндөөлөрдүн иретин өзгөртүү."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Кубат баскычынын менюсу"</string>
@@ -884,13 +877,23 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> жигердүү колдонмо</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> жигердүү колдонмо</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Жигердүү колдонмолор"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Токтотуу"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Токтотулду"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Көчүрүү"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Көчүрүлдү"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> колдонмосунан"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Көчүрмөнү жабуу интерфейси"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml
index 8c5006d..062e33c 100644
--- a/packages/SystemUI/res/values-land/config.xml
+++ b/packages/SystemUI/res/values-land/config.xml
@@ -33,4 +33,10 @@
<!-- Max number of columns for power menu -->
<integer name="power_menu_max_columns">4</integer>
+
+ <!-- Max number of columns for power menu lite -->
+ <integer name="power_menu_lite_max_columns">4</integer>
+ <!-- Max number of rows for power menu lite -->
+ <integer name="power_menu_lite_max_rows">2</integer>
+
</resources>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index 9d24e9b..01eb09b 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -38,11 +38,6 @@
<dimen name="qs_footer_padding">14dp</dimen>
<dimen name="qs_security_footer_background_inset">12dp</dimen>
- <dimen name="battery_detail_graph_space_top">9dp</dimen>
- <dimen name="battery_detail_graph_space_bottom">9dp</dimen>
-
- <dimen name="qs_detail_header_margin_top">14dp</dimen>
-
<dimen name="volume_tool_tip_top_margin">12dp</dimen>
<dimen name="volume_row_slider_height">128dp</dimen>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 3bdd675..6b96c1a 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"ອະນຸຍາດ"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"ບໍ່ອະນຸຍາດໃຫ້ມີການແກ້ໄຂບັນຫາ USB"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"ຜູ້ໃຊ້ທີ່ກຳລັງເຂົ້າສູ່ລະບົບອຸປະກອນຢູ່ໃນຕອນນີ້ບໍ່ສາມາດເປີດໃຊ້ການດີບັກ USB ໄດ້. ເພື່ອໃຊ້ຄຸນສົມບັດນີ້, ໃຫ້ສະຫຼັບໄປໃຊ້ຜູ້ໃຊ້ຫຼັກ."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"ທ່ານຕ້ອງການປ່ຽນພາສາລະບົບເປັນ <xliff:g id="LANGUAGE">%1$s</xliff:g> ບໍ່?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"ມີການຮ້ອງຂໍໃຫ້ປ່ຽນພາສາລະບົບໂດຍອຸປະກອນອື່ນ"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"ປ່ຽນພາສາ"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"ໃຊ້ພາສາປັດຈຸບັນ"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"ອະນຸຍາດການດີບັກໄຮ້ສາຍຢູ່ເຄືອຂ່າຍນີ້ບໍ?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"ຊື່ເຄືອຂ່າຍ (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nທີ່ຢູ່ Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"ອະນຸຍາດຕະຫຼອດຢູ່ເຄືອຂ່າຍນີ້"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ຄວາມແຈ້ງ"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"ການປີ້ນສີ"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"ການແກ້ໄຂສີ"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"ການຕັ້ງຄ່າເພີ່ມເຕີມ"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ຕັ້ງຄ່າຜູ້ໃຊ້"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"ແລ້ວໆ"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"ປິດ"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"ທ່ານຈະບໍ່ໄດ້ຍິນສຽງໂມງປ <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"ເວລາ <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"ວັນ <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"ການຕັ້ງຄ່າດ່ວນ, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"ຮັອດສະປອດ"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກ"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"ມ່ວນຊື່ນສຳລັບບາງຄົນ ແຕ່ບໍ່ແມ່ນສຳລັບທຸກຄົນ"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"ເຂົ້າສູ່ລະບົບເປັນ <xliff:g id="ID_1">%s</xliff:g> ແລ້ວ"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"ເລືອກຜູ້ໃຊ້"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"ບໍ່ມີອິນເຕີເນັດ"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"ເປີດລາຍລະອຽດ."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"ເປີດການຕັ້ງຄ່າ <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"ແກ້ໄຂລຳດັບການຕັ້ງຄ່າ."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"ເມນູເປີດປິດ"</string>
@@ -884,13 +877,20 @@
<item quantity="other">ແອັບທີ່ນຳໃຊ້ຢູ່ <xliff:g id="COUNT_1">%s</xliff:g> ແອັບ</item>
<item quantity="one">ແອັບທີ່ນຳໃຊ້ຢູ່ <xliff:g id="COUNT_0">%s</xliff:g> ແອັບ</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"ແອັບທີ່ນຳໃຊ້ຢູ່"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ຢຸດ"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"ຢຸດແລ້ວ"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"ສຳເນົາ"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"ສຳເນົາແລ້ວ"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"ຈາກ <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"ປິດການສຳເນົາສ່ວນຕິດຕໍ່ຜູ້ໃຊ້ໄວ້"</string>
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"ແກ້ໄຂຂໍ້ຄວາມທີ່ສຳເນົາແລ້ວ"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"ແກ້ໄຂຮູບທີ່ສຳເນົາແລ້ວ"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ສົ່ງໄປຫາອຸປະກອນທີ່ຢູ່ໃກ້ຄຽງ"</string>
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index ebde4fc..5179ad9 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Leisti"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB derinimas neleidžiamas"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Šiuo metu prie įrenginio prisijungęs naudotojas negali įjungti USB derinimo. Kad galėtumėte naudoti šią funkciją, perjunkite į pagrindinį naudotoją."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Ar norite pakeisti sistemos kalbą į <xliff:g id="LANGUAGE">%1$s</xliff:g> k.?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Užklausą dėl sistemos kalbos pakeitimo pateikė kitas įrenginys"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Keisti kalbą"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Palikti dabartinę kalbą"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Leisti belaidžio ryšio derinimą prisijungus prie šio tinklo?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Tinklo pavadinimas (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\n„Wi‑Fi“ adresas (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Visada leisti naudojant šį tinklą"</string>
@@ -242,7 +238,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Šviesumas"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Spalvų inversija"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Spalvų taisymas"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Daugiau nustatymų"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Naudotojo nustatymai"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Atlikta"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Uždaryti"</string>
@@ -470,7 +465,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Negirdėsite kito signalo <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Spartieji nustatymai, „<xliff:g id="TITLE">%s</xliff:g>“."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Viešosios interneto prieigos taškas"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Darbo profilis"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Smagu, bet ne visada"</string>
@@ -653,7 +647,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Prisijungta kaip <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"pasirinktumėte naudotoją"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Nėra interneto ryšio"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Atidaryti išsamią informaciją."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Atidaryti „<xliff:g id="ID_1">%s</xliff:g>“ nustatymus."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Redaguoti nustatymų tvarką."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Įjungimo meniu"</string>
@@ -898,13 +891,20 @@
<item quantity="many"><xliff:g id="COUNT_1">%s</xliff:g> aktyvios programos</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktyvių programų</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktyvios programos"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Sustabdyti"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Sustabdyta"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Kopijuoti"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Nukopijuota"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Iš „<xliff:g id="APPNAME">%1$s</xliff:g>“"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Atsisakyti kopijavimo NS"</string>
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Redaguoti nukopijuotą tekstą"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Redaguoti nukopijuotą vaizdą"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Siųsti į įrenginį netoliese"</string>
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 56b0bcd..63b6b2e 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Atļaut"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB atkļūdošana nav atļauta"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Lietotājs, kurš pašlaik ir pierakstījies šajā ierīcē, nevar iespējot USB atkļūdošanu. Lai izmantotu šo funkciju, pārslēdzieties uz galveno lietotāju."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Vai vēlaties mainīt sistēmas valodu uz šādu: <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Sistēmas valodas maiņu pieprasīja cita ierīce."</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Mainīt valodu"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Paturēt pašreizējo valodu"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Vai atļaut bezvadu atkļūdošanu šajā tīklā?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Tīkla nosaukums (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi adrese (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Vienmēr atļaut šajā tīklā"</string>
@@ -241,7 +237,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Spilgtums"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Krāsu inversija"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Krāsu korekcija"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Vairāk iestatījumu"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Lietotāja iestatījumi"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Gatavs"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Aizvērt"</string>
@@ -467,7 +462,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Nākamais signāls (<xliff:g id="WHEN">%1$s</xliff:g>) netiks atskaņots."</string>
<string name="alarm_template" msgid="2234991538018805736">"plkst. <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Ātrie iestatījumi: <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Tīklājs"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Darba profils"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Jautri dažiem, bet ne visiem"</string>
@@ -648,7 +642,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Pierakstījies kā <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"izvēlēties lietotāju"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Nav piekļuves internetam"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Atvērt detalizēto informāciju."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Atvērt <xliff:g id="ID_1">%s</xliff:g> iestatījumus."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Rediģēt iestatījumu secību."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Barošanas izvēlne"</string>
@@ -891,13 +884,23 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> aktīva lietotne</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktīvas lietotnes</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktīvās lietotnes"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Apturēt"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Apturēta"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Kopēt"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Nokopēts"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"No lietotnes <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Noraidīt ar kopēšanu saistīto lietotāja saskarnes elementu"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 8e645a3..7642a9a 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Дозволи"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Отстранувањето грешки на USB не е дозволено"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Корисникот што моментално е најавен на уредов не може да вклучи отстранување грешки на USB. За да ја користите функцијава, префрлете се на примарниот корисник."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Дали сакате да го промените системскиот јазик на <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Побарана е промена на системскиот јазик од друг уред"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Промени го јазикот"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Зачувај го тековниот јазик"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Да се дозволи безжично отстранување грешки на мрежава?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Име на мрежата (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi адреса (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Секогаш дозволувај на оваа мрежа"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Осветленост"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Инверзија на боите"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Корекција на боите"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Повеќе поставки"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Поставки на корисникот"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Готово"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Затвори"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Нема да го слушнете следниот аларм <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"во <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"во <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Брзи поставки, <xliff:g id="TITLE">%s</xliff:g>"</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Точка на пристап"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Работен профил"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Забава за некои, но не за сите"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Најавени сте како <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"изберете корисник"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Нема интернет"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Отворете ги деталите."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Отворете ги поставките на <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Уредете го редоследот на поставките."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Мени на копчето за вклучување"</string>
@@ -884,13 +877,23 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> активна апликација</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> активни апликации</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Активни апликации"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Крај"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Запрено"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Копирај"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Копирано"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Од <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Отфрли го корисничкиот интерфејс за копирање"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index e79dd3e..1bde5a0 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -236,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"തെളിച്ചം"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"നിറം വിപരീതമാക്കൽ"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"നിറം ശരിയാക്കൽ"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"കൂടുതൽ ക്രമീകരണങ്ങൾ"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ഉപയോക്തൃ ക്രമീകരണം"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"പൂർത്തിയാക്കി"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"അടയ്ക്കുക"</string>
@@ -460,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>-നുള്ള നിങ്ങളുടെ അടുത്ത അലാറം കേൾക്കില്ല"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>-ന്"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>-ന്"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"ദ്രുത ക്രമീകരണം, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"ഹോട്ട്സ്പോട്ട്"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"ഔദ്യോഗിക പ്രൊഫൈൽ"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"ചിലർക്ക് വിനോദം, എന്നാൽ എല്ലാവർക്കുമില്ല"</string>
@@ -639,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> ആയി സൈൻ ഇൻ ചെയ്തു"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"ഉപയോക്താവിനെ തിരഞ്ഞെടുക്കുക"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"ഇന്റർനെറ്റ് ഇല്ല"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"വിശദാംശങ്ങൾ തുറക്കുക."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g> ക്രമീകരണം തുറക്കുക."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"ക്രമീകരണ ക്രമം എഡിറ്റുചെയ്യുക."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"പവർ മെനു"</string>
@@ -880,13 +877,20 @@
<item quantity="other">സജീവമായ <xliff:g id="COUNT_1">%s</xliff:g> ആപ്പുകൾ</item>
<item quantity="one">സജീവമായ <xliff:g id="COUNT_0">%s</xliff:g> ആപ്പ്</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"സജീവമായ ആപ്പുകൾ"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"നിർത്തുക"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"നിർത്തി"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"പകർത്തുക"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"പകർത്തി"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> എന്നതിൽ നിന്ന്"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"പകർപ്പ് UI ഡിസ്മിസ് ചെയ്യുക"</string>
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"പകർത്തിയ ടെക്സ്റ്റ് എഡിറ്റ് ചെയ്യുക"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"പകർത്തിയ ചിത്രം എഡിറ്റ് ചെയ്യുക"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"സമീപത്തുള്ള ഉപകരണത്തിലേക്ക് അയയ്ക്കുക"</string>
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index c17be82..c63bd3d 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Зөвшөөрөх"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB алдаа засалт хийх боломжгүй"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Энэ төхөөрөмжид нэвтэрсэн хэрэглэгч USB дебаг хийх онцлогийг асаах боломжгүй байна. Энэ онцлогийг ашиглахын тулд үндсэн хэрэглэгч рүү сэлгэнэ үү."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Та системийн хэлийг <xliff:g id="LANGUAGE">%1$s</xliff:g> хэл болгож өөрчлөхийг хүсэж байна уу?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Өөр төхөөрөмжөөс системийн хэлийг өөрчлөх хүсэлт тавьсан"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Хэл солих"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Одоогийн хэлээр байлгах"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Энэ сүлжээн дээр wireless debugging-г зөвшөөрөх үү?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Сүлжээний нэр (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi хаяг (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Энэ сүлжээн дээр үргэлж зөвшөөрөх"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Тодрол"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Өнгө урвуулах"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Өнгөний засвар"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Бусад тохиргоо"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Хэрэглэгчийн тохиргоо"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Дууссан"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Хаах"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>-т та дараагийн сэрүүлгээ сонсохгүй"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> цагт"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>-т"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Шуурхай тохиргоо, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Сүлжээний цэг"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Ажлын профайл"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Зарим хүнд хөгжилтэй байж болох ч бүх хүнд тийм биш"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g>-р нэвтэрсэн"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"хэрэглэгчийг сонгох"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Интернэт алга"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Дэлгэрэнгүй мэдээллийг нээнэ үү."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g> тохиргоог нээнэ үү."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Тохиргооны дарааллыг өөрчилнө үү."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Асаах/унтраах цэс"</string>
@@ -884,13 +877,20 @@
<item quantity="other">Идэвхтэй <xliff:g id="COUNT_1">%s</xliff:g> апп</item>
<item quantity="one">Идэвхтэй <xliff:g id="COUNT_0">%s</xliff:g> апп</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Идэвхтэй аппууд"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Зогсоох"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Зогсоосон"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Хуулах"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Хууллаа"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g>-с"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Хуулах UI-г хаах"</string>
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Хуулсан текстийг засах"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Хуулсан зургийг засах"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Ойролцоох төхөөрөмж рүү илгээх"</string>
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 36da8df..fca67d2 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -236,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"चमक"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"कलर इन्व्हर्जन"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"रंग सुधारणा"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"अधिक सेटिंग्ज"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"वापरकर्ता सेटिंग्ज"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"पूर्ण झाले"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"बंद करा"</string>
@@ -460,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"तुम्ही तुमचा <xliff:g id="WHEN">%1$s</xliff:g> वाजता होणारा पुढील अलार्म ऐकणार नाही"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> वाजता"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> रोजी"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"द्रुत सेटिंग्ज, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"हॉटस्पॉट"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"कार्य प्रोफाईल"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"सर्वांसाठी नाही तर काहींसाठी मजेदार असू शकते"</string>
@@ -639,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> म्हणून साइन इन केले"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"वापरकर्ता निवडा"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"इंटरनेट नाही"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"तपशील उघडा."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g> सेटिंग्ज उघडा."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"सेटिंग्जचा क्रम संपादित करा."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"पॉवर मेनू"</string>
@@ -880,13 +877,20 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> अॅक्टिव्ह ॲप्स</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> अॅक्टिव्ह ॲप</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"अॅक्टिव्ह ॲप्स"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"थांबवा"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"थांबवले"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"कॉपी करा"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"कॉपी केले"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> वरून"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"कॉपी केलेले UI डिसमिस करा"</string>
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"कॉपी केलेला मजकूर संपादित करा"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"कॉपी केलेली इमेज संपादित करा"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"जवळपासच्या डिव्हाइसवर पाठवा"</string>
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 13525e7..b87a79c 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Benarkan"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Penyahpepijatan USB tidak dibenarkan"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Pengguna yang log masuk ke peranti ini pada masa ini tidak boleh menghidupkan penyahpepijatan USB. Untuk menggunakan ciri ini, tukar kepada pengguna utama."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Adakah anda ingin menukar bahasa sistem kepada <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Permintaan pertukaran bahasa sistem oleh peranti lain"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Tukar bahasa"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Kekalkan bahasa semasa"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Benarkan penyahpepijatan wayarles pada rangkaian ini?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Nama Rangkaian (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAlamat Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Sentiasa benarkan pada rangkaian ini"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Kecerahan"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Penyongsangan warna"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Pembetulan warna"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Lagi tetapan"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Tetapan pengguna"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Selesai"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Tutup"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Anda tidak akan mendengar penggera yang seterusnya <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"pada <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"pada <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Tetapan Pantas, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Tempat liputan"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Profil kerja"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Menarik untuk sesetengah orang tetapi bukan untuk semua"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Dilog masuk sebagai <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"pilih pengguna"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Tiada Internet"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Buka butiran."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Buka tetapan <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Edit susunan tetapan."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu kuasa"</string>
@@ -884,13 +877,23 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> apl aktif</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> apl aktif</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Apl aktif"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Berhenti"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Dihentikan"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Salin"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Disalin"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Daripada <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Ketepikan penyalinan UI"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 837a550..0248d10 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"ခွင့်ပြုရန်"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB အမှားပြင်ဆင်ခြင်း ခွင့်မပြုပါ"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"ဤစက်ပစ္စည်းသို့ လက်ရှိဝင်ရောက်ထားသည့် အသုံးပြုသူသည် USB အမှားပြင်ဆင်ခြင်းကို ဖွင့်၍မရပါ။ ဤဝန်ဆောင်မှုကို အသုံးပြုရန် အဓိကအသုံးပြုသူအဖြစ်သို့ ပြောင်းပါ။"</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"စနစ်၏ ဘာသာစကားကို <xliff:g id="LANGUAGE">%1$s</xliff:g> သို့ ပြောင်းလိုသလား။"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"စက်နောက်တစ်ခုက စနစ်၏ ဘာသာစကားပြောင်းရန် တောင်းဆိုထားသည်"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"ဘာသာစကားပြောင်းရန်"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"လက်ရှိဘာသာစကားဆက်သုံးရန်"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"ဤကွန်ရက်တွင် ကြိုးမဲ့ အမှားရှာပြင်ခြင်းကို ခွင့်ပြုမလား။"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"ကွန်ရက်အမည် (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi လိပ်စာ (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"ဤကွန်ရက်ကို အမြဲခွင့်ပြုပါ"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"အလင်းတောက်ပမှု"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"အရောင်ပြောင်းပြန်ပြုလုပ်ရန်"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"အရောင် အမှန်ပြင်ခြင်း"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"နောက်ထပ် ဆက်တင်များ"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"အသုံးပြုသူ ဆက်တင်များ"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"ပြီးပါပြီ"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"ပိတ်ရန်"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> ၌သင့်နောက်ထပ် နှိုးစက်ကို ကြားမည်မဟုတ်ပါ"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> ၌"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> တွင်"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"အမြန်ချိန်ညှိခြင်း၊ <xliff:g id="TITLE">%s</xliff:g>။"</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"ဟော့စပေါ့"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"အလုပ် ပရိုဖိုင်"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"အချို့သူများ အတွက် ပျော်စရာ ဖြစ်ပေမဲ့ အားလုံး အတွက် မဟုတ်ပါ"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> အဖြစ် လက်မှတ်ထိုးဝင်ထားသည်။"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"အသုံးပြုသူရွေးရန်"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"အင်တာနက် မရှိပါ"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"အသေးစိတ်များကို ဖွင့်ပါ။"</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g> ဆက်တင်များကို ဖွင့်ပါ။"</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"ဆက်တင်များ၏ အစီအစဉ်ကို တည်းဖြတ်ပါ။"</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"ပါဝါမီနူး"</string>
@@ -884,13 +877,23 @@
<item quantity="other">ပွင့်နေသည့်အက်ပ် <xliff:g id="COUNT_1">%s</xliff:g> ခု</item>
<item quantity="one">ပွင့်နေသည့်အက်ပ် <xliff:g id="COUNT_0">%s</xliff:g> ခု</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"ပွင့်နေသည့်အက်ပ်များ"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ရပ်ရန်"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"ရပ်ထားသည်"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"မိတ္တူကူးရန်"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"ကူးပြီးပါပြီ"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> ထံမှ"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"UI မိတ္တူမကူးတော့ရန်"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 68af3d5..76cfef5 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Tillat"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB-feilsøking er ikke tillatt"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Brukeren som for øyeblikket er logget på denne enheten, kan ikke slå på USB-feilsøking. For å bruke denne funksjonen, bytt til hovedbrukeren."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Vil du bytte systemspråk til <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Bytte av systemspråk er forespurt av en annen enhet"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Bytt språk"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Behold gjeldende språk"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Vil du tillate trådløs feilsøking på dette nettverket?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Nettverksnavn (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi-adresse (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Tillat alltid på dette nettverket"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Lysstyrke"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Fargeinvertering"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Fargekorrigering"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Flere innstillinger"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Brukerinnstillinger"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Ferdig"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Lukk"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Du hører ikke neste innstilte alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"kl. <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Hurtiginnstillinger, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Wi-Fi-sone"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Work-profil"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Gøy for noen – ikke for alle"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Logget på som <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"velge en bruker"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Ingen internettilkobling"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Åpne informasjonen."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Åpne <xliff:g id="ID_1">%s</xliff:g>-innstillingene."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Endre rekkefølgen på innstillingene."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Av/på-meny"</string>
@@ -884,13 +877,23 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktive apper</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aktiv app</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktive apper"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stopp"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Stoppet"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Kopiér"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopiert"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Fra <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Lukk kopi-UI"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 2ca03b6..158a891 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -236,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"उज्यालपन"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"कलर इन्भर्सन"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"रङ सच्याउने कार्य"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"थप सेटिङहरू"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"प्रयोगकर्तासम्बन्धी सेटिङ"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"भयो"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"बन्द गर्नुहोस्"</string>
@@ -460,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"तपाईँले आफ्नो अर्को अलार्म <xliff:g id="WHEN">%1$s</xliff:g> सुन्नुहुने छैन"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> मा"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> मा"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"द्रुत सेटिङ, <xliff:g id="TITLE">%s</xliff:g>।"</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Hotspot"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"कार्य प्रोफाइल"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"केहीका लागि रमाइलो हुन्छ तर सबैका लागि होइन"</string>
@@ -639,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> को रूपमा साइन इन गरियो"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"प्रयोगकर्ता छान्नुहोस्"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"इन्टरनेट छैन"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"विवरणहरूलाई खोल्नुहोस्।"</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g> सम्बन्धी सेटिङहरूलाई खोल्नुहोस्।"</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"सेटिङहरूको क्रमलाई सम्पादन गर्नुहोस्।"</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"पावर मेनु"</string>
@@ -880,13 +877,20 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> वटा सक्रिय एप</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> सक्रिय एप</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"सक्रिय एपहरू"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"रोक्नुहोस्"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"रोकिएको छ"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"कपी गर्नुहोस्"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"कपी गरियो"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> बाट"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"कपी UI खारेज गर्नुहोस्"</string>
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"कपी गरिएको टेक्स्ट सम्पादन गर्नुहोस्"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"कपी गरिएको फोटो सम्पादन गर्नुहोस्"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"नजिकैको डिभाइसमा पठाउनुहोस्"</string>
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index a5a1b81..f85bbee 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Toestaan"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB-foutopsporing niet toegestaan"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"De gebruiker die momenteel is ingelogd op dit apparaat, kan USB-foutopsporing niet aanzetten. Als je deze functie wilt gebruiken, schakel je naar de primaire gebruiker."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Wil je de systeemtaal wijzigen naar het <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Wijziging van systeemtaal aangevraagd door een ander apparaat"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Taal wijzigen"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Huidige taal houden"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Draadloze foutopsporing toestaan in dit netwerk?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Netwerknaam (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWifi-adres (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Altijd toestaan in dit netwerk"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Helderheid"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Kleurinversie"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Kleurcorrectie"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Meer instellingen"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Gebruikersinstellingen"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Klaar"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Sluiten"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Je hoort je volgende wekker niet <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"om <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"op <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Snelle instellingen, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Hotspot"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Werkprofiel"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Leuk voor sommige gebruikers, maar niet voor iedereen"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Ingelogd als <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"gebruiker kiezen"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Geen internet"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Details openen."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g>-instellingen openen."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Volgorde van instellingen bewerken."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Aan/uit-menu"</string>
@@ -884,13 +877,23 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> actieve apps</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> actieve app</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Actieve apps"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stoppen"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Gestopt"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Kopiëren"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Gekopieerd"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Uit <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"UI voor kopiëren sluiten"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index f1698f4..dab199b 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USBରେ ଡିବଗ୍ କରାଯାଇପାରିବ ନାହିଁ"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"ସମ୍ପ୍ରତି ସାଇନ୍-ଇନ୍ କରିଥିବା ୟୁଜର୍ ଜଣକ ଏହି ଡିଭାଇସରେ USB ଡିବଗିଙ୍ଗ ଅନ୍ କରିପାରିବେ ନାହିଁ। ଏହି ବୈଶିଷ୍ଟ୍ୟ ବ୍ୟବହାର କରିବାକୁ, ପ୍ରାଥମିକ ୟୁଜର୍ରେ ସାଇନ୍-ଇନ୍ କରନ୍ତୁ।"</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"ଆପଣ ସିଷ୍ଟମ ଭାଷା <xliff:g id="LANGUAGE">%1$s</xliff:g>କୁ ପରିବର୍ତ୍ତନ କରିବା ପାଇଁ ଚାହାଁନ୍ତି?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"ଅନ୍ୟ ଏକ ଡିଭାଇସ ଦ୍ୱାରା ସିଷ୍ଟମ ଭାଷା ପରିବର୍ତ୍ତନ ପାଇଁ ଅନୁରୋଧ କରାଯାଇଛି"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"ଭାଷା ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"ବର୍ତ୍ତମାନର ଭାଷା ରଖନ୍ତୁ"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"ଏହି ନେଟୱାର୍କରେ ୱାୟାରଲେସ୍ ଡିବଗିଂ ପାଇଁ ଅନୁମତି ଦେବେ?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"ନେଟୱାର୍କ ନାମ (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nୱାଇଫାଇ ଠିକଣା (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"ସର୍ବଦା ଏହି ନେଟୱାର୍କରେ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ଉଜ୍ଜ୍ୱଳତା"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"ରଙ୍ଗ ଇନଭାର୍ସନ"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"ରଙ୍ଗ ସଂଶୋଧନ"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"ଅଧିକ ସେଟିଂସ୍"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ଉପଯୋଗକର୍ତ୍ତା ସେଟିଂସ୍"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"ହୋଇଗଲା"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"ବନ୍ଦ କରନ୍ତୁ"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>ବେଳେ ଆପଣ ନିଜର ପରବର୍ତ୍ତୀ ଆଲାର୍ମ ଶୁଣିପାରିବେ ନାହିଁ"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> ହେଲେ"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> ବେଳେ"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"କ୍ୱିକ୍ ସେଟିଂସ୍, <xliff:g id="TITLE">%s</xliff:g>।"</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"ହଟସ୍ପଟ୍"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"ୱର୍କ ପ୍ରୋଫାଇଲ୍"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"କେତେକଙ୍କ ପାଇଁ ମଜାଦାର, କିନ୍ତୁ ସମସ୍ତଙ୍କ ପାଇଁ ନୁହେଁ"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> ଭାବରେ ସାଇନ୍ ଇନ୍ କରିଛନ୍ତି"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"ଉପଯୋଗକର୍ତ୍ତା ବାଛନ୍ତୁ"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"କୌଣସି ଇଣ୍ଟରନେଟ୍ କନେକ୍ସନ୍ ନାହିଁ"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"ବିବରଣୀ ଖୋଲନ୍ତୁ"</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g> ସେଟିଙ୍ଗ ଖୋଲନ୍ତୁ।"</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"ସେଟିଙ୍ଗର କ୍ରମ ସଂଶୋଧନ କରନ୍ତୁ।"</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"ପାୱାର ମେନୁ"</string>
@@ -884,13 +877,20 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g>ଟି ସକ୍ରିୟ ଆପ</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g>ଟି ସକ୍ରିୟ ଆପ</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"ସକ୍ରିୟ ଆପଗୁଡ଼ିକ"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ବନ୍ଦ କରନ୍ତୁ"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"ବନ୍ଦ ହୋଇଛି"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"କପି କରନ୍ତୁ"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"କପି କରାଯାଇଛି"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g>ରୁ"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"କପି କରାଯାଇଥିବା UIକୁ ଖାରଜ କରନ୍ତୁ"</string>
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"କପି କରାଯାଇଥିବା ଟେକ୍ସଟକୁ ଏଡିଟ କରନ୍ତୁ"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"କପି କରାଯାଇଥିବା ଇମେଜକୁ ଏଡିଟ କରନ୍ତୁ"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ନିକଟସ୍ଥ ଡିଭାଇସକୁ ପଠାନ୍ତୁ"</string>
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 72811c4..20b5bf2 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"ਕਰਨ ਦਿਓ"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB ਡਿਬੱਗਿੰਗ ਦੀ ਆਗਿਆ ਨਹੀਂ"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"The user currently signed in to this device can\'t turn on USB debugging. To use this feature, switch to the primary user."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"ਕੀ ਤੁਸੀਂ ਸਿਸਟਮ ਦੀ ਭਾਸ਼ਾ ਬਦਲ ਕੇ <xliff:g id="LANGUAGE">%1$s</xliff:g> ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"ਕਿਸੇ ਹੋਰ ਡੀਵਾਈਸ ਵੱਲੋਂ ਸਿਸਟਮ ਦੀ ਭਾਸ਼ਾ ਬਦਲਣ ਦੀ ਬੇਨਤੀ ਕੀਤੀ ਗਈ"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"ਭਾਸ਼ਾ ਬਦਲੋ"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"ਮੌਜੂਦਾ ਭਾਸ਼ਾ ਰੱਖੋ"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"ਕੀ ਇਸ ਨੈੱਟਵਰਕ \'ਤੇ ਵਾਇਰਲੈੱਸ ਡੀਬੱਗਿੰਗ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"ਨੈੱਟਵਰਕ ਨਾਮ (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nਵਾਈ-ਫਾਈ ਪਤਾ (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"ਇਸ ਨੈੱਟਵਰਕ \'ਤੇ ਹਮੇਸ਼ਾਂ ਆਗਿਆ ਦਿਓ"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ਚਮਕ"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"ਰੰਗ ਪਲਟਨਾ"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"ਰੰਗ ਸੁਧਾਈ"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"ਹੋਰ ਸੈਟਿੰਗਾਂ"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ਵਰਤੋਂਕਾਰ ਸੈਟਿੰਗਾਂ"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"ਹੋ ਗਿਆ"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"ਬੰਦ ਕਰੋ"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"ਤੁਸੀਂ <xliff:g id="WHEN">%1$s</xliff:g> ਵਜੇ ਆਪਣਾ ਅਗਲਾ ਅਲਾਰਮ ਨਹੀਂ ਸੁਣੋਗੇ"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> ਵਜੇ"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> ਵਜੇ"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ, <xliff:g id="TITLE">%s</xliff:g>।"</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"ਹੌਟਸਪੌਟ"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"ਕੁਝ ਵਾਸਤੇ ਤਾਂ ਮਜ਼ੇਦਾਰ ਹੈ ਲੇਕਿਨ ਸਾਰਿਆਂ ਵਾਸਤੇ ਨਹੀਂ"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> ਵਜੋਂ ਸਾਈਨ ਇਨ ਕੀਤਾ"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"ਵਰਤੋਂਕਾਰ ਚੁਣੋ"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"ਇੰਟਰਨੈੱਟ ਨਹੀਂ।"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"ਵੇਰਵੇ ਖੋਲ੍ਹੋ।"</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g> ਸੈਟਿੰਗਾਂ ਖੋਲ੍ਹੋ।"</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"ਸੈਟਿੰਗਾਂ ਦੇ ਕ੍ਰਮ ਦਾ ਸੰਪਾਦਨ ਕਰੋ।"</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"ਪਾਵਰ ਮੀਨੂ"</string>
@@ -884,13 +877,23 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> ਕਿਰਿਆਸ਼ੀਲ ਐਪ</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> ਕਿਰਿਆਸ਼ੀਲ ਐਪਾਂ</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"ਕਿਰਿਆਸ਼ੀਲ ਐਪਾਂ"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ਬੰਦ ਕਰੋ"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"ਬੰਦ ਹੈ"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"ਕਾਪੀ ਕਰੋ"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"ਕਾਪੀ ਕੀਤੀ ਗਈ"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> ਤੋਂ"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"ਕਾਪੀ ਕੀਤੇ UI ਨੂੰ ਖਾਰਜ ਕਰੋ"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 783d154..4572922 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Zezwalaj"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Debugowanie USB jest niedozwolone"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Użytkownik obecnie zalogowany na tym urządzeniu nie może włączyć debugowania USB. Aby użyć tej funkcji, przełącz się na użytkownika głównego."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Czy chcesz zmienić język systemu na <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Inny użytkownik poprosił o zmianę języka systemu"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Zmień język"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Zachowaj bieżący język"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Zezwolić na debugowanie bezprzewodowe w tej sieci?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Nazwa sieci (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAdres Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Zawsze zezwalaj w tej sieci"</string>
@@ -242,7 +238,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Jasność"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Odwrócenie kolorów"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Korekcja kolorów"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Więcej ustawień"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Ustawienia użytkownika"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Gotowe"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Zamknij"</string>
@@ -470,7 +465,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Nie usłyszysz swojego następnego alarmu <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"o <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"w: <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Szybkie ustawienia, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Hotspot"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Profil służbowy"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Dobra zabawa, ale nie dla każdego"</string>
@@ -653,7 +647,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Zalogowany użytkownik: <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"wybrać użytkownika"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Brak internetu"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Otwórz szczegóły."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Otwórz ustawienia: <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Edytuj kolejność ustawień."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu zasilania"</string>
@@ -898,13 +891,23 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktywnej aplikacji</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aktywna aplikacja</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktywne aplikacje"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Zatrzymaj"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Zatrzymano"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Kopiuj"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Skopiowano"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Od: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Zamknij UI kopiowania"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 5af949b..1c902b0 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -37,7 +37,7 @@
<string name="usb_accessory_confirm_prompt" msgid="5728408382798643421">"Abrir o app <xliff:g id="APPLICATION">%1$s</xliff:g> para lidar com o <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="6756649383432542382">"Nenhum apl. instalado funciona com o USB. Saiba mais sobre o acessório em <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="1236358027511638648">"Acessório USB"</string>
- <string name="label_view" msgid="6815442985276363364">"Visualizar"</string>
+ <string name="label_view" msgid="6815442985276363364">"Ver"</string>
<string name="always_use_device" msgid="210535878779644679">"Sempre abrir o app <xliff:g id="APPLICATION">%1$s</xliff:g> quando <xliff:g id="USB_DEVICE">%2$s</xliff:g> for conectado"</string>
<string name="always_use_accessory" msgid="1977225429341838444">"Sempre abrir o app <xliff:g id="APPLICATION">%1$s</xliff:g> quando <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> for conectado"</string>
<string name="usb_debugging_title" msgid="8274884945238642726">"Permitir a depuração USB?"</string>
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Permitir"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Depuração USB não permitida"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"O usuário conectado a este dispositivo não pode ativar a depuração USB. Para usar esse recurso, mude para o usuário principal \"NAME\"."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Quer mudar o idioma do sistema para <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Mudança do idioma do sistema solicitada por outro dispositivo"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Alterar idioma"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Manter idioma atual"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Permitir a depuração por Wi-Fi nesta rede?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Nome da rede (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nEndereço do Wi-Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Sempre permitir nesta rede"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brilho"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversão de cores"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Correção de cor"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Mais configurações"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Config. do usuário"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Concluído"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Fechar"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Você não ouvirá o próximo alarme às <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"às <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Configurações rápidas, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Ponto de acesso"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Perfil de trabalho"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Diversão para alguns, mas não para todos"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Login efetuado como <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"escolher o usuário"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Sem Internet"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Abrir detalhes."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Abrir configurações de <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Editar ordem das configurações."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu liga/desliga"</string>
@@ -884,13 +877,23 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> app ativo</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> apps ativos</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Apps ativos"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Parar"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Parado"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Copiar"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copiado"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Do app <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Dispensar cópia da IU"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 48d4bde..1562abc 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -236,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brilho"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversão de cores"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Correção da cor"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Mais definições"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Definições do utilizador"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Concluído"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Fechar"</string>
@@ -460,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Não vai ouvir o próximo alarme às <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"às <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"em <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Definições rápidas, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Zona Wi-Fi"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Perfil de trabalho"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Diversão para alguns, mas não para todos"</string>
@@ -639,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Sessão iniciada como <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"escolher o utilizador"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Sem Internet"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Abrir os detalhes."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Abrir as definições de <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Editar a ordem das definições."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu ligar/desligar"</string>
@@ -880,13 +877,23 @@
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> app ativa</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> apps ativas</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Apps ativas"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Parar"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Parada"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Copiar"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copiado"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Da app <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Ignorar cópia de IU"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 5af949b..1c902b0 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -37,7 +37,7 @@
<string name="usb_accessory_confirm_prompt" msgid="5728408382798643421">"Abrir o app <xliff:g id="APPLICATION">%1$s</xliff:g> para lidar com o <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="6756649383432542382">"Nenhum apl. instalado funciona com o USB. Saiba mais sobre o acessório em <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="1236358027511638648">"Acessório USB"</string>
- <string name="label_view" msgid="6815442985276363364">"Visualizar"</string>
+ <string name="label_view" msgid="6815442985276363364">"Ver"</string>
<string name="always_use_device" msgid="210535878779644679">"Sempre abrir o app <xliff:g id="APPLICATION">%1$s</xliff:g> quando <xliff:g id="USB_DEVICE">%2$s</xliff:g> for conectado"</string>
<string name="always_use_accessory" msgid="1977225429341838444">"Sempre abrir o app <xliff:g id="APPLICATION">%1$s</xliff:g> quando <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> for conectado"</string>
<string name="usb_debugging_title" msgid="8274884945238642726">"Permitir a depuração USB?"</string>
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Permitir"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Depuração USB não permitida"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"O usuário conectado a este dispositivo não pode ativar a depuração USB. Para usar esse recurso, mude para o usuário principal \"NAME\"."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Quer mudar o idioma do sistema para <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Mudança do idioma do sistema solicitada por outro dispositivo"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Alterar idioma"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Manter idioma atual"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Permitir a depuração por Wi-Fi nesta rede?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Nome da rede (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nEndereço do Wi-Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Sempre permitir nesta rede"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brilho"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversão de cores"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Correção de cor"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Mais configurações"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Config. do usuário"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Concluído"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Fechar"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Você não ouvirá o próximo alarme às <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"às <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Configurações rápidas, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Ponto de acesso"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Perfil de trabalho"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Diversão para alguns, mas não para todos"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Login efetuado como <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"escolher o usuário"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Sem Internet"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Abrir detalhes."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Abrir configurações de <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Editar ordem das configurações."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu liga/desliga"</string>
@@ -884,13 +877,23 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> app ativo</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> apps ativos</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Apps ativos"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Parar"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Parado"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Copiar"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copiado"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Do app <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Dispensar cópia da IU"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index c94d0c0..d520d50 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Permiteți"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Remedierea erorilor prin USB nu este permisă"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Utilizatorul conectat momentan pe acest dispozitiv nu poate activa remedierea erorilor prin USB. Pentru a folosi această funcție, comutați la utilizatorul principal."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Schimbați limba de sistem la <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Alt dispozitiv solicită schimbarea limbii de sistem"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Schimbați limba"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Păstrați limba actuală"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Permiteți remedierea erorilor wireless în această rețea?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Numele rețelei (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAdresa Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Permiteți întotdeauna în această rețea"</string>
@@ -241,7 +237,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Luminozitate"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversarea culorilor"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Corecția culorii"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Mai multe setări"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Setări de utilizator"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Terminat"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Închideți"</string>
@@ -467,7 +462,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Nu veți auzi următoarea alarmă <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"la <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Setări rapide, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Hotspot"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Profil de serviciu"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Distractiv pentru unii, dar nu pentru toată lumea"</string>
@@ -648,7 +642,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Conectat(ă) ca <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"alege utilizatorul"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Fără conexiune la internet"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Deschideți detaliile."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Deschideți setările <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Editați ordinea setărilor."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Meniul de pornire"</string>
@@ -891,13 +884,20 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> de aplicații active</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aplicație activă</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aplicații active"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Opriți"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Oprită"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Copiați"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"S-a copiat"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Din <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Închideți copierea interfeței de utilizare"</string>
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Editați textul copiat"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editați imaginea copiată"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Trimiteți către un dispozitiv din apropiere"</string>
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index db651db..310a87e 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Разрешить"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Отладка по USB запрещена"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"В этом аккаунте нельзя включить отладку по USB. Перейдите в аккаунт основного пользователя."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Изменить системный язык на <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Получен запрос на изменение системного языка от другого устройства."</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Изменить язык"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Оставить текущий язык"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Разрешить отладку по Wi-Fi в этой сети?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Название сети (SSID):\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nMAC-адрес точки доступа (BSSID):\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Всегда разрешать отладку в этой сети"</string>
@@ -242,7 +238,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Яркость"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Инверсия цветов"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Коррекция цвета"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Настройки"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Пользовательские настройки"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Готово"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Закрыть"</string>
@@ -470,7 +465,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Следующий будильник: <xliff:g id="WHEN">%1$s</xliff:g>. Звук отключен."</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Быстрые настройки, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Точка доступа"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Рабочий профиль"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Внимание!"</string>
@@ -653,7 +647,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Выполнен вход под именем <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"выбрать пользователя"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Нет подключения к Интернету."</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Показать подробности."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Открыть настройки <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Изменить порядок быстрых настроек."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Меню кнопки питания"</string>
@@ -898,13 +891,23 @@
<item quantity="many"><xliff:g id="COUNT_1">%s</xliff:g> активных приложений</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> активного приложения</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Активные приложения"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Остановить"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Остановлено"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Копировать"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Скопировано."</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Из приложения \"<xliff:g id="APPNAME">%1$s</xliff:g>\""</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Закрыть меню копирования"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 56b2522..e730bb0 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"ඉඩ දෙන්න"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB නිදොස්කරණය වෙත අවසර නැහැ"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"දැනට මෙම උපාංගයට පුරා ඇති පරිශීලකයාට USB නිදොස්කරණය ක්රියාත්මක කළ නොහැක. මෙම විශේෂාංගය භාවිතා කිරීම සඳහා, මූලික පරිශීලකයා වෙත මාරු වෙන්න."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"ඔබට පද්ධති භාෂාව <xliff:g id="LANGUAGE">%1$s</xliff:g> භාෂාවට වෙනස් කිරීමට අවශ්යද?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"වෙනත් උපාංගයකින් පද්ධති භාෂාව වෙනස් කිරීම ඉල්ලා ඇත"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"භාෂාව වෙනස් කරන්න"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"වත්මන් භාෂාව තබා ගන්න"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"මෙම ජාලයේ නොරැහැන් නිදොස්කරණය ඉඩ දෙන්නද?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"ජාල නම (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi ලිපිනය (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"මෙම ජාලයේ සැමවිට ඉඩ දෙන්න"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"දීප්තිමත් බව"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"වර්ණ අපවර්තනය"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"වර්ණ නිවැරදි කිරීම"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"තව සැකසීම්"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"පරිශීලක සැකසීම්"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"නිමයි"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"වසන්න"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"ඔබට ඔබේ ඊළඟ එලාමය <xliff:g id="WHEN">%1$s</xliff:g> නොඇසෙනු ඇත"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> ට"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> දී"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"ඉක්මන් සැකසුම්, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"හොට්ස්පොට්"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"කාර්යාල පැතිකඩ"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"සමහරක් දේවල් වලට විනෝදයි, නමුත් සියල්ලටම නොවේ"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> ලෙස පුරන්න"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"පරිශීලක තෝරන්න"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"අන්තර්ජාලය නැත"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"විස්තර විවෘත කරන්න."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g> සැකසීම් විවෘත කරන්න."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"සැකසීම්වල අනුපිළිවෙළ සංංස්කරණය කරන්න."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"බල මෙනුව"</string>
@@ -884,13 +877,23 @@
<item quantity="one">සක්රිය යෙදුම් <xliff:g id="COUNT_1">%s</xliff:g></item>
<item quantity="other">සක්රිය යෙදුම් <xliff:g id="COUNT_1">%s</xliff:g></item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"සක්රිය යෙදුම්"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"නවත්වන්න"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"නවත්වන ලදි"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"පිටපත් කරන්න"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"පිටපත් කරන ලදි"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> සිට"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Dismiss copy UI"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 2e4db00..a3bbe44 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Povoliť"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Ladenie cez USB nie je povolené"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Používateľ, ktorý je práve prihlásený v tomto zariadení, nemôže zapnúť ladenie USB. Ak chcete použiť túto funkciu, prepnite na hlavného používateľa."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Chcete zmeniť jazyk systému na možnosť <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Zmenu jazyka systému vyžiadalo iné zariadenie"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Zmeniť jazyk"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Ponechať aktuálny jazyk"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Chcete povoliť bezdrôtové ladenie v tejto sieti?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Názov siete (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAdresa Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Vždy povoliť v tejto sieti"</string>
@@ -242,7 +238,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Jas"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inverzia farieb"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Úprava farieb"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Ďalšie nastavenia"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Používateľské nastavenia"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Hotovo"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Zavrieť"</string>
@@ -470,7 +465,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Váš budík o <xliff:g id="WHEN">%1$s</xliff:g> sa nespustí"</string>
<string name="alarm_template" msgid="2234991538018805736">"o <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Rýchle nastavenia, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Hotspot"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Pracovný profil"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Pri používaní tuneru postupujte opatrne"</string>
@@ -653,7 +647,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Prihlásený používateľ <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"vybrať používateľa"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Žiadny internet"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Otvoriť podrobnosti"</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Otvoriť nastavenia <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Upraviť poradie nastavení"</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Ponuka vypínača"</string>
@@ -898,13 +891,20 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktívnych aplikácií</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aktívna aplikácia</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktívne aplikácie"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Ukončiť"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Zastavená"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Kopírovať"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Skopírované"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Z aplikácie <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Používateľské rozhranie zahodenia kópie"</string>
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Upraviť skopírovaný text"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Upraviť skopírovaný obrázok"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Odoslať do zariadenia v okolí"</string>
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 43577f1..d657277 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -238,7 +238,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Svetlost"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inverzija barv"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Popravljanje barv"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Več nastavitev"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Uporabniške nastavitve"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Končano"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Zapri"</string>
@@ -466,7 +465,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Naslednjega alarma ob <xliff:g id="WHEN">%1$s</xliff:g> ne boste slišali"</string>
<string name="alarm_template" msgid="2234991538018805736">"ob <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"ob tem času: <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Hitre nastavitve, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Dostopna točka"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Delovni profil"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Zabavno za nekatere, a ne za vse"</string>
@@ -649,7 +647,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Prijavljeni ste kot <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"izbiro uporabnika"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Brez internetne povezave"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Odpri podrobnosti."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Odpri nastavitve za <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Uredi vrstni red nastavitev."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Meni za vklop/izklop"</string>
@@ -894,13 +891,20 @@
<item quantity="few"><xliff:g id="COUNT_1">%s</xliff:g> aktivne aplikacije</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktivnih aplikacij</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktivne aplikacije"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Ustavi"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Ustavljeno"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Kopiraj"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopirano"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Iz aplikacije <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Opusti kopiranje uporabniškega vmesnika"</string>
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Uredi kopirano besedilo"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Uredi kopirano sliko"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Pošlji v napravo v bližini"</string>
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 14cc511..f8ba65af 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Lejo"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Korrigjimi përmes USB-së nuk lejohet"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Përdoruesi i identifikuar aktualisht në këtë pajisje nuk mund ta aktivizojë korrigjimin përmes USB-së. Për ta përdorur këtë veçori, kalo te përdoruesi parësor."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Dëshiron ta ndryshosh gjuhën e sistemit në <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Një pajisje tjetër kërkoi ndryshimin e gjuhës së sistemit"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Ndrysho gjuhën"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Mbaj gjuhën aktuale"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Të lejohet korrigjimi përmes Wi-Fi në këtë rrjet?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Emri i rrjetit (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAdresa Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Lejo gjithmonë në këtë rrjet"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Ndriçimi"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Anasjellja e ngjyrës"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Korrigjimi i ngjyrës"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Cilësime të tjera"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Cilësimet e përdoruesit"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"U krye"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Mbyll"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Nuk do ta dëgjosh alarmin e radhës në <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"në <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"në <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Cilësimet e shpejta, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Zona e qasjes për internet"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Profili i punës"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Argëtim për disa, por jo për të gjithë!"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Identifikuar si <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"zgjidh përdoruesin"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Nuk ka internet"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Hap detajet."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Hap cilësimet e <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Modifiko rendin e cilësimeve."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menyja e energjisë"</string>
@@ -884,13 +877,23 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aplikacione aktive</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aplikacion aktiv</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aplikacionet aktive"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Ndalo"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Ndaluar"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Kopjo"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"U kopjua"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Nga <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Hiq kopjen e ndërfaqes së përdoruesit"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 8affbe4..5d89cf1 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Дозволи"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Отклањање грешака на USB-у није дозвољено"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Корисник који је тренутно пријављен на овај уређај не може да укључи отклањање грешака на USB-у. Да бисте користили ову функцију, пребаците на примарног корисника."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Да ли желите да промените језик система на <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Други уређај је затражио промену језика система"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Промени језик"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Задржи актуелни језик"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Желите да дозволите бежично отклањање грешака на овој мрежи?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Назив мреже (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi адреса (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Увек дозволи на овој мрежи"</string>
@@ -241,7 +237,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Осветљеност"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Инверзија боја"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Корекција боја"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Још подешавања"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Корисничка подешавања"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Готово"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Затвори"</string>
@@ -467,7 +462,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Нећете чути следећи аларм у <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"у <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"у <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Брза подешавања, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Хотспот"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Пословни профил"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Забава за неке, али не за све"</string>
@@ -648,7 +642,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Пријављени сте као <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"одабрали корисника"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Нема интернета"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Отвори детаље."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Отвори подешавања за <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Измени редослед подешавања."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Мени дугмета за укључивање"</string>
@@ -891,13 +884,23 @@
<item quantity="few"><xliff:g id="COUNT_1">%s</xliff:g> активне апликације</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> активних апликација</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Активне апликације"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Заустави"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Заустављено"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Копирај"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Копирано је"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Из: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Одбаци копирање корисничког интерфејса"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 1cd6668..b9a3ab1 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Tillåt"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB-felsökning är inte tillåtet"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Användaren som är inloggad på enheten för närvarande kan inte aktivera USB-felsökning. Byt till den primära användaren om du vill använda den här funktionen."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Vill du ändra systemspråket till <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Ändring av systemspråk har begärts av en annan enhet"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Ändra språk"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Behåll nuvarande språk"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Vill du tillåta trådlös felsökning i det här nätverket?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Nätverksnamn (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi-adress (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Tillåt alltid i det här nätverket"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Ljusstyrka"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Färginvertering"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Färgkorrigering"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Fler inställningar"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Användarinställningar"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Klart"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Stäng"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Nästa alarm, kl. <xliff:g id="WHEN">%1$s</xliff:g>, kommer inte att höras"</string>
<string name="alarm_template" msgid="2234991538018805736">"kl. <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"kl. <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Snabbinställningar, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Surfzon"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Jobbprofil"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Kul för vissa, inte för alla"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Inloggad som <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"välj användare"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Inget internet"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Visa information."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Öppna <xliff:g id="ID_1">%s</xliff:g>-inställningarna."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Ändra ordning på inställningarna."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Startmeny"</string>
@@ -884,13 +877,23 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktiva appar</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aktiv app</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktiva appar"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stoppa"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Stoppad"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Kopiera"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopierades"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Från <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Stäng användargränssnittet för kopiering"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 63819f1..803a2b5 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Ruhusu"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Utatuzi wa USB hauruhusiwi"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Mtumiaji aliyeingia katika akaunti kwa kutumia kifaa hiki kwa sasa hawezi kuwasha utatuzi wa USB. Ili utumie kipengele hiki, tumia akaunti ya mtumiaji wa msingi."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Ungependa kubadilisha lugha ya mfumo kuwa <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Mabadiliko ya lugha ya mfumo yameombwa na kifaa kingine"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Badilisha lugha"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Usibadilishe lugha ya sasa"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Ungependa kuruhusu utatuzi usiotumia waya kwenye mtandao huu?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Jina la Mtandao (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAnwani ya Wi-Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Ruhusu kila wakati kwenye mtandao huu"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Ung\'avu"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Ugeuzaji rangi"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Usahihishaji wa rangirangi"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Mipangilio zaidi"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Mipangilio ya mtumiaji"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Nimemaliza"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Funga"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Hutasikia kengele yako inayofuata ya saa <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"saa <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"siku ya <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Mipangilio ya Haraka, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Mtandaopepe"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Wasifu wa kazini"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Kinafurahisha kwa baadhi ya watu lakini si wote"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Umeingia katika akaunti ya <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"chagua mtumiaji"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Hakuna intaneti"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Fungua maelezo."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Fungua mipangilio ya <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Badilisha orodha ya mipangilio."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menyu ya kuzima/kuwasha"</string>
@@ -884,13 +877,23 @@
<item quantity="other">Programu <xliff:g id="COUNT_1">%s</xliff:g> zinatumika</item>
<item quantity="one">Programu <xliff:g id="COUNT_0">%s</xliff:g> inatumika</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Programu zinazotumika"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Simamisha"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Imesimamishwa"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Nakili"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Imenakiliwa"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Kutoka <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Ondoa kiolesura cha nakala"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sw410dp/dimens.xml b/packages/SystemUI/res/values-sw410dp/dimens.xml
index d33ee99..7da47e5 100644
--- a/packages/SystemUI/res/values-sw410dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw410dp/dimens.xml
@@ -20,8 +20,6 @@
<!-- These resources are around just to allow their values to be customized
for different hardware and product builds. -->
<resources>
- <dimen name="qs_detail_items_padding_top">16dp</dimen>
-
<!-- Global actions grid -->
<dimen name="global_actions_grid_vertical_padding">8dp</dimen>
<dimen name="global_actions_grid_horizontal_padding">4dp</dimen>
diff --git a/packages/SystemUI/res/values-sw600dp-land/config.xml b/packages/SystemUI/res/values-sw600dp-land/config.xml
index fe546f6..588638f 100644
--- a/packages/SystemUI/res/values-sw600dp-land/config.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/config.xml
@@ -33,4 +33,7 @@
<!-- Notifications are sized to match the width of two (of 4) qs tiles in landscape. -->
<bool name="config_skinnyNotifsInLandscape">false</bool>
+ <integer name="power_menu_lite_max_columns">3</integer>
+ <integer name="power_menu_lite_max_rows">2</integer>
+
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp-port/config.xml b/packages/SystemUI/res/values-sw600dp-port/config.xml
index 3c6a81e..857e162 100644
--- a/packages/SystemUI/res/values-sw600dp-port/config.xml
+++ b/packages/SystemUI/res/values-sw600dp-port/config.xml
@@ -23,4 +23,8 @@
<!-- The number of columns in the QuickSettings -->
<integer name="quick_settings_num_columns">3</integer>
+
+ <integer name="power_menu_lite_max_columns">2</integer>
+ <integer name="power_menu_lite_max_rows">3</integer>
+
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index a66ed15..8f6bde5 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -65,9 +65,6 @@
<dimen name="qs_security_footer_single_line_height">48dp</dimen>
<dimen name="qs_security_footer_background_inset">0dp</dimen>
- <!-- When split shade is used, this panel should be aligned to the top -->
- <dimen name="qs_detail_margin_top">0dp</dimen>
-
<!-- The width of large/content heavy dialogs (e.g. Internet, Media output, etc) -->
<dimen name="large_dialog_width">472dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-sw720dp-land/dimens.xml b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
index ae557c4..e897f75 100644
--- a/packages/SystemUI/res/values-sw720dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
@@ -20,4 +20,6 @@
<dimen name="controls_padding_horizontal">205dp</dimen>
<dimen name="split_shade_notifications_scrim_margin_bottom">16dp</dimen>
<dimen name="notification_panel_margin_bottom">56dp</dimen>
+
+ <dimen name="keyguard_split_shade_top_margin">72dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 5fe90d6..094559f 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -236,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ஒளிர்வு"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"கலர் இன்வெர்ஷன்"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"கலர் கரெக்ஷன்"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"அமைப்பில் மாற்று"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"பயனர் அமைப்புகள்"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"முடிந்தது"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"மூடுக"</string>
@@ -460,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"அடுத்த அலாரத்தை <xliff:g id="WHEN">%1$s</xliff:g> மணிக்கு கேட்க மாட்டீர்கள்"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> மணிக்கு"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> மணிக்கு"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"விரைவு அமைப்புகள், <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"ஹாட்ஸ்பாட்"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"பணிக் கணக்கு"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"சில வேடிக்கையாக இருந்தாலும் கவனம் தேவை"</string>
@@ -639,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> என்ற பெயரில் உள்நுழைந்துள்ளீர்கள்"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"பயனரைத் தேர்வுசெய்யவும்"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"இணைய இணைப்பு இல்லை"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"விவரங்களைத் திற."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g> அமைப்புகளைத் திற."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"அமைப்புகளின் வரிசை முறையைத் திருத்து."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"பவர் மெனு"</string>
@@ -880,13 +877,20 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> ஆப்ஸ் செயலில் உள்ளன</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> ஆப்ஸ் செயலில் உள்ளது</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"செயலிலுள்ள ஆப்ஸ்"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"நிறுத்து"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"இயங்கவில்லை"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"நகலெடு"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"நகலெடுக்கப்பட்டது"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> ஆப்ஸிலிருந்து"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"கிளிப்போர்டு மேலடுக்கை மூடுக"</string>
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"நகலெடுத்த வார்த்தைகளைத் திருத்து"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"நகலெடுத்த படத்தைத் திருத்து"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"அருகிலுள்ள சாதனத்திற்கு அனுப்பு"</string>
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index c087dc8..59e8ef4 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -236,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ప్రకాశం"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"కలర్ మార్పిడి"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"కలర్ కరెక్షన్"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"మరిన్ని సెట్టింగ్లు"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"యూజర్ సెట్టింగ్లు"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"పూర్తయింది"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"మూసివేయి"</string>
@@ -460,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"మీరు <xliff:g id="WHEN">%1$s</xliff:g> సెట్ చేసిన మీ తర్వాత అలారం మీకు వినిపించదు"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>కి"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>కి"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"శీఘ్ర సెట్టింగ్లు, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"హాట్స్పాట్"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"ఆఫీస్ ప్రొఫైల్"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"కొందరికి సరదాగా ఉంటుంది కానీ అందరికీ అలాగే ఉండదు"</string>
@@ -639,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> లాగా సైన్ ఇన్ చేశారు"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"యూజర్ను ఎంపిక చేయండి"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"ఇంటర్నెట్ లేదు"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"వివరాలను తెరవండి."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g> సెట్టింగ్లను తెరవండి."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"సెట్టింగ్ల క్రమాన్ని ఎడిట్ చేయండి."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"పవర్ మెనూ"</string>
@@ -880,13 +877,20 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> యాక్టివ్గా ఉన్న యాప్లు</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> యాక్టివ్గా ఉన్న యాప్</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"యాక్టివ్గా ఉన్న యాప్లు"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ఆపివేయండి"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"ఆపివేయబడింది"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"కాపీ చేయండి"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"కాపీ అయింది"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> నుండి"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"కాపీ UIని విస్మరించండి"</string>
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"కాపీ చేసిన టెక్స్ట్ను ఎడిట్ చేయండి"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"కాపీ చేసిన ఇమేజ్లను ఎడిట్ చేయండి"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"సమీపంలోని పరికరానికి పంపండి"</string>
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml
index 2eff692..a9e6d22 100644
--- a/packages/SystemUI/res/values-television/config.xml
+++ b/packages/SystemUI/res/values-television/config.xml
@@ -24,29 +24,6 @@
<string name="config_systemUIFactoryComponent" translatable="false">
com.android.systemui.tv.TvSystemUIFactory
</string>
- <!-- SystemUI Services: The classes of the stuff to start. -->
- <string-array name="config_systemUIServiceComponents" translatable="false">
- <item>com.android.systemui.util.NotificationChannels</item>
- <item>com.android.systemui.volume.VolumeUI</item>
- <item>com.android.systemui.privacy.television.TvOngoingPrivacyChip</item>
- <item>com.android.systemui.statusbar.tv.TvStatusBar</item>
- <item>com.android.systemui.statusbar.tv.notifications.TvNotificationPanel</item>
- <item>com.android.systemui.statusbar.tv.notifications.TvNotificationHandler</item>
- <item>com.android.systemui.statusbar.tv.VpnStatusObserver</item>
- <item>com.android.systemui.globalactions.GlobalActionsComponent</item>
- <item>com.android.systemui.usb.StorageNotification</item>
- <item>com.android.systemui.power.PowerUI</item>
- <item>com.android.systemui.media.RingtonePlayer</item>
- <item>com.android.systemui.keyboard.KeyboardUI</item>
- <item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
- <item>@string/config_systemUIVendorServiceComponent</item>
- <item>com.android.systemui.SliceBroadcastRelayHandler</item>
- <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
- <item>com.android.systemui.accessibility.WindowMagnification</item>
- <item>com.android.systemui.toast.ToastUI</item>
- <item>com.android.systemui.wmshell.WMShell</item>
- <item>com.android.systemui.media.systemsounds.HomeSoundEffectController</item>
- </string-array>
<!-- Svelte specific logic, see RecentsConfiguration.SVELTE_* constants. -->
<integer name="recents_svelte_level">3</integer>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index df48f0b..a207447 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"อนุญาต"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"ไม่อนุญาตให้แก้ไขข้อบกพร่องผ่าน USB"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"ผู้ใช้ที่ลงชื่อเข้าใช้อุปกรณ์อยู่ในขณะนี้ไม่สามารถเปิดการแก้ไขข้อบกพร่องผ่าน USB ได้ หากต้องการใช้ฟีเจอร์นี้ ให้เปลี่ยนไปเป็นผู้ใช้หลัก"</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"คุณต้องการเปลี่ยนภาษาของระบบเป็นภาษา<xliff:g id="LANGUAGE">%1$s</xliff:g>ใช่ไหม"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"คำขอเปลี่ยนภาษาของระบบโดยอุปกรณ์อื่น"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"เปลี่ยนภาษา"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"ใช้ภาษาปัจจุบันต่อไป"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"อนุญาตให้แก้ไขข้อบกพร่องผ่าน Wi-Fi ในเครือข่ายนี้ใช่ไหม"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"ชื่อเครือข่าย (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nที่อยู่ Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"อนุญาตเสมอในเครือข่ายนี้"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ความสว่าง"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"การกลับสี"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"การแก้สี"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"การตั้งค่าเพิ่มเติม"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"การตั้งค่าของผู้ใช้"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"เสร็จสิ้น"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"ปิด"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"คุณจะไม่ได้ยินเสียงปลุกครั้งถัดไปในเวลา <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"เวลา <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"ในวันที่ <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"การตั้งค่าด่วน <xliff:g id="TITLE">%s</xliff:g>"</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"ฮอตสปอต"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"โปรไฟล์งาน"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"เพลิดเพลินกับบางส่วนแต่ไม่ใช่ทั้งหมด"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"ลงชื่อเข้าใช้เป็น <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"เลือกผู้ใช้"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"ไม่มีอินเทอร์เน็ต"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"เปิดรายละเอียด"</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"เปิดการตั้งค่า <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"แก้ไขลำดับการตั้งค่า"</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"เมนูเปิด/ปิด"</string>
@@ -884,13 +877,23 @@
<item quantity="other">มี <xliff:g id="COUNT_1">%s</xliff:g> แอปที่ใช้งานอยู่</item>
<item quantity="one">มี <xliff:g id="COUNT_0">%s</xliff:g> แอปที่ใช้งานอยู่</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"แอปที่ใช้งานอยู่"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"หยุด"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"หยุดแล้ว"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"คัดลอก"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"คัดลอกแล้ว"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"จาก <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"ปิด UI การคัดลอก"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index cb96cbf..db9c788 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Payagan"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Hindi pinapayagan ang pagde-debug sa pamamagitan ng USB"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Hindi mao-on ng user na kasalukuyang naka-sign in sa device na ito ang pag-debug ng USB. Upang magamit ang feature na ito, lumipat sa pangunahing user."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Gusto mo bang gawing <xliff:g id="LANGUAGE">%1$s</xliff:g> ang wika ng system?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Hiniling ng ibang device na palitan ang wika ng system"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Palitan ang wika"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Huwag palitan ang wika"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Payagan ang wireless na pag-debug sa network na ito?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Pangalan ng Network (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAddress ng Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Palaging payagan sa network na ito"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brightness"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Pag-invert ng kulay"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Pagtatama ng kulay"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Higit pang setting"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Mga setting ng user"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Tapos na"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Isara"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Hindi mo maririnig ang iyong susunod na alarm ng <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"ng <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"sa <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Mga Maikling Setting, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Hotspot"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Profile sa trabaho"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Masaya para sa ilan ngunit hindi para sa lahat"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Naka-sign in bilang <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"pumili ng user"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Walang internet"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Buksan ang mga detalye."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Buksan ang mga setting ng <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"I-edit ang pagkakasunud-sunod ng mga setting."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Power menu"</string>
@@ -884,13 +877,23 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> aktibong app</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> na aktibong app</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Mga aktibong app"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Ihinto"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Inihinto"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Kopyahin"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Nakopya"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Mula sa <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"I-dismiss ang UI ng pagkopya"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index a3d07c8..308af4f 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"İzin ver"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB hata ayıklama işlevine izin verilmiyor"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Bu cihazda geçerli olarak oturum açmış olan kullanıcı, USB hata ayıklama özelliğini açamaz. Bu özelliği kullanmak için birincil kullanıcıya geçin."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Sistem dilini <xliff:g id="LANGUAGE">%1$s</xliff:g> olarak değiştirmek istiyor musunuz?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Başka bir cihaz tarafından sistem dilinin değiştirilmesi istendi"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Dili değiştir"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Mevcut dili koru"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Bu ağda kablosuz hata ayıklamaya izin verilsin mi?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Ağ Adı (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nKablosuz Adresi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Bu ağda her zaman izin ver"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Parlaklık"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Rengi ters çevirme"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Renk düzeltme"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Diğer ayarlar"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Kullanıcı ayarları"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Bitti"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Kapat"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> olarak ayarlanmış bir sonraki alarmınızı duymayacaksınız"</string>
<string name="alarm_template" msgid="2234991538018805736">"saat: <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"gün ve saat: <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Hızlı Ayarlar, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Hotspot"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"İş profili"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Bazıları için eğlenceliyken diğerleri için olmayabilir"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> olarak oturum açıldı"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"kullanıcı seç"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"İnternet yok"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Ayrıntıları aç."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g> ayarlarını aç."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Ayarların sırasını düzenle."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Güç menüsü"</string>
@@ -884,13 +877,23 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> etkin uygulama</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> etkin uygulama</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Etkin uygulamalar"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Durdur"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Durduruldu"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Kopyala"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopyalandı"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> uygulamasından"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Kopyalanan kullanıcı arayüzünü kapat"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 55f7a27..0161060 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Дозволити"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Ви не можете вмикати налагодження USB"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Користувач поточного облікового запису не може вмикати налагодження USB. Щоб увімкнути цю функцію, увійдіть в обліковий запис основного користувача."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Змінити мову системи на таку: <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Запит на змінення мови системи надіслано з іншого пристрою"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Змінити мову"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Залишити поточну мову"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Дозволити налагодження через Wi-Fi у цій мережі?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Ім\'я мережі (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nАдреса Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Завжди дозволяти в цій мережі"</string>
@@ -242,7 +238,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Яскравість"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Інверсія кольорів"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Корекція кольору"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Більше налаштувань"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Налаштування користувача"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Готово"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Закрити"</string>
@@ -470,7 +465,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Наступний сигнал о <xliff:g id="WHEN">%1$s</xliff:g> не пролунає"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Швидкі налаштування, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Точка доступу"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Робочий профіль"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Це цікаво, але будьте обачні"</string>
@@ -653,7 +647,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Ви ввійшли як <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"вибрати користувача"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Немає Інтернету"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Відкрити деталі."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Відкрити налаштування <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Змінити порядок налаштувань."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Меню кнопки живлення"</string>
@@ -898,13 +891,23 @@
<item quantity="many"><xliff:g id="COUNT_1">%s</xliff:g> активних додатків</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> активного додатка</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Активні додатки"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Зупинити"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Зупинено"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Копіювати"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Скопійовано"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"З додатка <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Закрити вікно копіювання"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index d9420c4..ce492dd 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -236,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"چمکیلا پن"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"رنگوں کی تقلیب"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"رنگ کی اصلاح"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"مزید ترتیبات"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"صارف کی ترتیبات"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"ہو گیا"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"بند کریں"</string>
@@ -460,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"آپ کو <xliff:g id="WHEN">%1$s</xliff:g> بجے اپنا اگلا الارم سنائی نہیں دے گا"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> بجے"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> بجے"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"فوری ترتیبات، <xliff:g id="TITLE">%s</xliff:g>۔"</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"ہاٹ اسپاٹ"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"دفتری پروفائل"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"کچھ کیلئے دلچسپ لیکن سبھی کیلئے نہیں"</string>
@@ -639,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> کے بطور سائن ان ہے"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"صارف منتخب کریں"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"انٹرنیٹ نہیں ہے"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"تفصیلات کھولیں۔"</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g> ترتیبات کھولیں۔"</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"ترتیبات کی ترتیب میں ترمیم کریں۔"</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"پاور مینو"</string>
@@ -880,13 +877,20 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> فعال ایپس</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> فعال ایپ</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"فعال ایپس"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"روکیں"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"رکی ہوئی ہے"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"کاپی کریں"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"کاپی کر دیا گیا ہے"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> سے"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"کاپی شدہ UI کو برخاست کریں"</string>
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"کاپی کردہ ٹیکسٹ میں ترمیم کریں"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"کاپی کردہ تصویر میں ترمیم کریں"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"قریبی آلے کو بھیجیں"</string>
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index e92e060..6d6c371 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Ruxsat berish"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB orqali nosozliklarni tuzatishga ruxsat berilmagan"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Ayni paytda ushbu qurilmaga o‘z hisobi bilan kirgan foydalanuvchi USB orqali nosozliklarni aniqlash funksiyasini yoqa olmaydi. Bu funksiyadan foydalanish uchun asosiy foydalanuvchi profiliga o‘ting."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Tizim tilini <xliff:g id="LANGUAGE">%1$s</xliff:g> tiliga oʻzgartirishni istaysizmi?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Tizim tilini oʻzgartirishni boshqa qurilma soʻragan"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Tilni almashtirish"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Joriy tilni qoldirish"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Wi-Fi orqali debagging uchun ruxsat berilsinmi?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Tarmoq nomi (SSID):\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi Manzil (BSSID):\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Bu tarmoqda doim ruxsat etilsin"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Yorqinlik"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Ranglarni akslantirish"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Ranglarni tuzatish"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Boshqa sozlamalar"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Foydalanuvchi sozlamalari"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Tayyor"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Yopish"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Keyingi signal (<xliff:g id="WHEN">%1$s</xliff:g>) chalinmaydi"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Tezkor sozlamalar, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Hotspot"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Ish profili"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Diqqat!"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> sifatida kirgansiz"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"foydalanuvchini tanlash"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Internetga ulanmagansiz"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Tafsilotlarini ko‘rsatish."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g> sozlamalarini ochish."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Sozlamalar tartibini o‘zgartirish."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Quvvat menyusi"</string>
@@ -884,13 +877,23 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> ta faol ilova</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> ta faol ilova</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Faol ilovalar"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Toʻxtatildi"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Nusxa olish"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Nusxa olindi"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Manba: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"UI nusxasini bekor qilish"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 9527711..5d69e03 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Cho phép"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Không cho phép chế độ gỡ lỗi qua USB"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Người dùng hiện đã đăng nhập vào thiết bị này không thể bật tính năng gỡ lỗi USB. Để sử dụng tính năng này, hãy chuyển sang người dùng chính."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Bạn có muốn thay đổi ngôn ngữ hệ thống thành <xliff:g id="LANGUAGE">%1$s</xliff:g> không?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Thiết bị khác yêu cầu thay đổi ngôn ngữ hệ thống"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Thay đổi ngôn ngữ"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Giữ ngôn ngữ hiện tại"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Cho phép gỡ lỗi qua Wi-Fi trên mạng này?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Tên mạng (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nĐịa chỉ Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Luôn cho phép trên mạng này"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Độ sáng"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Đảo màu"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Chỉnh màu"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Chế độ cài đặt khác"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Cài đặt người dùng"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Xong"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Đóng"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Bạn sẽ không nghe thấy báo thức tiếp theo lúc <xliff:g id="WHEN">%1$s</xliff:g> của mình"</string>
<string name="alarm_template" msgid="2234991538018805736">"lúc <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"vào <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Cài đặt nhanh, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Điểm phát sóng"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Hồ sơ công việc"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Thú vị đối với một số người nhưng không phải tất cả"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Đã đăng nhập là <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"chọn người dùng"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Không có Internet"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Mở chi tiết."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Mở cài đặt <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Chỉnh sửa thứ tự cài đặt."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Trình đơn nguồn"</string>
@@ -884,13 +877,23 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> ứng dụng đang hoạt động</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> ứng dụng đang hoạt động</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Ứng dụng đang hoạt động"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Dừng"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Đã dừng"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Sao chép"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Đã sao chép"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Từ <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Đóng giao diện người dùng sao chép"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index ecf5c77..f032907 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"允许"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"不允许使用 USB 调试功能"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"目前已登录此设备的用户无法开启 USB 调试功能。要使用此功能,请切换为主要用户的帐号。"</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"是否要将系统语言更改为<xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"另一台设备请求更改系统语言"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"更改语言"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"保持当前语言"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"要允许通过此网络进行无线调试吗?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"网络名称 (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWLAN 地址 (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"始终允许通过此网络进行调试"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"亮度"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"颜色反转"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"色彩校正"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"更多设置"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"用户设置"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"完成"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"关闭"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"您在<xliff:g id="WHEN">%1$s</xliff:g>将不会听到下次闹钟响铃"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"快捷设置,<xliff:g id="TITLE">%s</xliff:g>。"</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"热点"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"工作资料"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"并不适合所有用户"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"目前登录的用户名为<xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"选择用户"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"未连接到互联网"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"打开详情页面。"</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"打开<xliff:g id="ID_1">%s</xliff:g>设置。"</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"修改设置顺序。"</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"电源菜单"</string>
@@ -884,13 +877,23 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> 个使用中的应用</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> 个使用中的应用</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"使用中的应用"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"停止"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"已停止"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"复制"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"已复制"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"来自<xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"关闭复制界面"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index c85e2630..dbb4ffc 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -236,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"亮度"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"色彩反轉"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"色彩校正"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"更多設定"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"使用者設定"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"完成"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"關閉"</string>
@@ -460,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"您不會<xliff:g id="WHEN">%1$s</xliff:g>聽到鬧鐘"</string>
<string name="alarm_template" msgid="2234991538018805736">"在 <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"在<xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"<xliff:g id="TITLE">%s</xliff:g>的快速設定。"</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"熱點"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"工作設定檔"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"這只是測試版本,並不包含完整功能"</string>
@@ -639,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"已登入為<xliff:g id="ID_1">%s</xliff:g>。"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"揀使用者"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"沒有互聯網連線"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"開啟詳細資料頁面。"</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"開啟<xliff:g id="ID_1">%s</xliff:g>設定頁面。"</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"編輯設定次序。"</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"電源選單"</string>
@@ -880,13 +877,23 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> 個使用中的應用程式</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> 個使用中的應用程式</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"使用中的應用程式"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"停止"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"已停止"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"複製"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"已複製"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"來自「<xliff:g id="APPNAME">%1$s</xliff:g>」"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"關閉剪貼簿使用者介面"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 19c2b3a..d7185a4 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"允許"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"無權使用 USB 偵錯功能"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"目前登入這個裝置的使用者無法啟用 USB 偵錯功能。如要使用這項功能,請切換到主要使用者。"</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"要將系統語言變更為<xliff:g id="LANGUAGE">%1$s</xliff:g>嗎?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"另一部裝置要求變更系統語言"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"變更語言"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"繼續使用目前的語言"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"要允許透過這個網路執行無線偵錯嗎?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"網路名稱 (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi 位址 (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"一律允許透過這個網路執行"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"亮度"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"色彩反轉"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"色彩校正"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"更多設定"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"使用者設定"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"完成"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"關閉"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"你不會聽到下一個<xliff:g id="WHEN">%1$s</xliff:g> 的鬧鐘"</string>
<string name="alarm_template" msgid="2234991538018805736">"於<xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"於<xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"快速設定,<xliff:g id="TITLE">%s</xliff:g>。"</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"無線基地台"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"工作資料夾"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"有趣與否,見仁見智"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"以「<xliff:g id="ID_1">%s</xliff:g>」的身分登入"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"選擇使用者"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"沒有網際網路連線"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"開啟詳細資料。"</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"開啟「<xliff:g id="ID_1">%s</xliff:g>」設定。"</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"編輯設定順序。"</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"電源按鈕選單"</string>
@@ -884,13 +877,23 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> 個使用中的應用程式</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> 個使用中的應用程式</item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"使用中的應用程式"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"停止"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"已停止"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"複製"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"已複製"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"來自「<xliff:g id="APPNAME">%1$s</xliff:g>」"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"關閉剪貼簿 UI"</string>
+ <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
+ <skip />
+ <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
+ <skip />
+ <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
+ <skip />
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 8d8a8ac..5425b26 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -46,14 +46,10 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Vumela"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Ukususa iphutha kwe-USB akuvunyelwe"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Umsebenzisi manje ongene ngemvume kule divayisi entsha akakwazi ukuvula ukulungisa amaphutha ku-USB. Ukuze usebenzise lesi sici, shintshela kumsebenzisi oyinhloko."</string>
- <!-- no translation found for hdmi_cec_set_menu_language_title (1259765420091503742) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_description (8176716678074126619) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_accept (2513689457281009578) -->
- <skip />
- <!-- no translation found for hdmi_cec_set_menu_language_decline (7650721096558646011) -->
- <skip />
+ <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Ingabe ufuna ukushintsha ulimi lwesistimu lube isi-<xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+ <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Ushintsho lolimi lwesistimu lucelwe enye idivayisi"</string>
+ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Shintsha ulimi"</string>
+ <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Gcina ulimi lwamanje"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Vumela ukulungisa amaphutha okungenantambo kule nethiwekhi?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Igama Lenethiwekhi (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nIkheli le-Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Njalo nje vumela le nethiwekhi"</string>
@@ -240,7 +236,6 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Ukugqama"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Ukuguqulwa kombala"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Ukulungiswa kombala"</string>
- <string name="quick_settings_more_settings" msgid="2878235926753776694">"Izilungiselelo eziningi"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Amasethingi womsebenzisi"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Kwenziwe"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Vala"</string>
@@ -464,7 +459,6 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"Ngeke uzwe i-alamu yakho elandelayo ngo-<xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"ngo-<xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"nge-<xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Izilungiselelo ezisheshayo, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"I-Hotspot"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Iphrofayela yomsebenzi"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Kuyajabulisa kwabanye kodwa hhayi bonke"</string>
@@ -643,7 +637,6 @@
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Ungene ngemvume njengo-<xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"khetha umsebenzisi"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Ayikho i-inthanethi"</string>
- <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Vula imininingwane."</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Vula izilungiselelo ze-<xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Hlela uhlelo lwezilungiselelo."</string>
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Imenyu yamandla"</string>
@@ -884,13 +877,20 @@
<item quantity="one">ama-app asebenzayo angu-<xliff:g id="COUNT_1">%s</xliff:g></item>
<item quantity="other">ama-app asebenzayo angu-<xliff:g id="COUNT_1">%s</xliff:g></item>
</plurals>
+ <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
+ <skip />
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Ama-app asebenzayo"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Misa"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Imisiwe"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Kopisha"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Ikopishiwe"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Kusukela ku-<xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Chitha ukukopisha i-UI"</string>
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Hlela umbhalo okopishiwe"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Hlela umfanekiso okopishiwe"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Thumela kudivayisi eseduze"</string>
+ <!-- no translation found for add (81036585205287996) -->
+ <skip />
+ <!-- no translation found for manage_users (1823875311934643849) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index e6ab0ff..2992859 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -114,13 +114,6 @@
<attr name="hybridNotificationTextStyle" format="reference" />
</declare-styleable>
- <declare-styleable name="AutoSizingList">
- <!-- Whether AutoSizingList will show only as many items as fit on screen and
- remove extra items instead of scrolling. -->
- <attr name="enableAutoSizing" format="boolean" />
- <attr name="itemHeight" format="dimension" />
- </declare-styleable>
-
<declare-styleable name="PluginInflateContainer">
<attr name="viewType" format="string" />
</declare-styleable>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 1514778..faf518e 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -88,6 +88,7 @@
<color name="keyguard_user_switcher_background_gradient_color">#77000000</color>
<color name="user_switcher_fullscreen_bg">@android:color/system_neutral1_900</color>
+ <color name="user_switcher_fullscreen_popup_item_tint">@*android:color/text_color_primary_device_default_dark</color>
<!-- The color of the navigation bar icons. Need to be in sync with ic_sysbar_* -->
<color name="navigation_bar_icon_color">#E5FFFFFF</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 47822b7..bb1ffa8 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -292,43 +292,6 @@
<!-- SystemUIFactory component -->
<string name="config_systemUIFactoryComponent" translatable="false">com.android.systemui.SystemUIFactory</string>
- <!-- SystemUI Services: The classes of base stuff to start by default for all
- configurations. -->
- <string-array name="config_systemUIServiceComponents" translatable="false">
- <item>com.android.systemui.util.NotificationChannels</item>
- <item>com.android.systemui.keyguard.KeyguardViewMediator</item>
- <item>com.android.keyguard.KeyguardBiometricLockoutLogger</item>
- <item>com.android.systemui.recents.Recents</item>
- <item>com.android.systemui.volume.VolumeUI</item>
- <item>com.android.systemui.statusbar.phone.StatusBar</item>
- <item>com.android.systemui.usb.StorageNotification</item>
- <item>com.android.systemui.power.PowerUI</item>
- <item>com.android.systemui.media.RingtonePlayer</item>
- <item>com.android.systemui.keyboard.KeyboardUI</item>
- <item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
- <item>@string/config_systemUIVendorServiceComponent</item>
- <item>com.android.systemui.util.leak.GarbageMonitor$Service</item>
- <item>com.android.systemui.LatencyTester</item>
- <item>com.android.systemui.globalactions.GlobalActionsComponent</item>
- <item>com.android.systemui.ScreenDecorations</item>
- <item>com.android.systemui.biometrics.AuthController</item>
- <item>com.android.systemui.log.SessionTracker</item>
- <item>com.android.systemui.SliceBroadcastRelayHandler</item>
- <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
- <item>com.android.systemui.theme.ThemeOverlayController</item>
- <item>com.android.systemui.accessibility.WindowMagnification</item>
- <item>com.android.systemui.accessibility.SystemActions</item>
- <item>com.android.systemui.toast.ToastUI</item>
- <item>com.android.systemui.wmshell.WMShell</item>
- <item>com.android.systemui.clipboardoverlay.ClipboardListener</item>
- </string-array>
-
- <!-- SystemUI Services: The classes of the additional stuff to start. Services here are
- specified as an overlay to provide configuration-specific services that
- supplement those listed in config_systemUIServiceComponents. -->
- <string-array name="config_additionalSystemUIServiceComponents" translatable="false">
- </string-array>
-
<!-- QS tile shape store width. negative implies fill configuration instead of stroke-->
<dimen name="config_qsTileStrokeWidthActive">-1dp</dimen>
<dimen name="config_qsTileStrokeWidthInactive">-1dp</dimen>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index fe79f27..47ffb18 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -43,6 +43,8 @@
<dimen name="navigation_edge_panel_height">96dp</dimen>
<!-- The threshold to drag to trigger the edge action -->
<dimen name="navigation_edge_action_drag_threshold">16dp</dimen>
+ <!-- The threshold to progress back animation for edge swipe -->
+ <dimen name="navigation_edge_action_progress_threshold">400dp</dimen>
<!-- The minimum display position of the arrow on the screen -->
<dimen name="navigation_edge_arrow_min_y">64dp</dimen>
<!-- The amount by which the arrow is shifted to avoid the finger-->
@@ -500,26 +502,10 @@
<dimen name="qs_panel_elevation">4dp</dimen>
<dimen name="qs_panel_padding_bottom">@dimen/new_footer_height</dimen>
<dimen name="qs_panel_padding_top">48dp</dimen>
- <dimen name="qs_detail_header_padding">0dp</dimen>
- <dimen name="qs_detail_image_width">56dp</dimen>
- <dimen name="qs_detail_image_height">56dp</dimen>
- <dimen name="qs_detail_image_padding">16dp</dimen>
- <dimen name="qs_detail_item_height">48dp</dimen>
- <dimen name="qs_detail_header_text_size">20sp</dimen>
- <dimen name="qs_detail_button_text_size">14sp</dimen>
- <dimen name="qs_detail_item_primary_text_size">16sp</dimen>
- <dimen name="qs_detail_item_secondary_text_size">14sp</dimen>
- <dimen name="qs_detail_empty_text_size">14sp</dimen>
- <dimen name="qs_detail_header_margin_top">28dp</dimen>
- <dimen name="qs_detail_header_text_padding">16dp</dimen>
+
<dimen name="qs_data_usage_text_size">14sp</dimen>
<dimen name="qs_data_usage_usage_text_size">36sp</dimen>
- <dimen name="qs_detail_padding_start">16dp</dimen>
- <dimen name="qs_detail_items_padding_top">4dp</dimen>
- <dimen name="qs_detail_item_icon_size">24dp</dimen>
- <dimen name="qs_detail_item_icon_width">32dp</dimen>
- <dimen name="qs_detail_item_icon_marginStart">0dp</dimen>
- <dimen name="qs_detail_item_icon_marginEnd">20dp</dimen>
+
<dimen name="qs_header_mobile_icon_size">@dimen/status_bar_icon_drawing_size</dimen>
<dimen name="qs_header_carrier_separator_width">6dp</dimen>
<dimen name="qs_carrier_margin_width">4dp</dimen>
@@ -533,9 +519,6 @@
<dimen name="qs_security_footer_background_inset">0dp</dimen>
<dimen name="qs_security_footer_corner_radius">28dp</dimen>
- <!-- Desired qs icon overlay size. -->
- <dimen name="qs_detail_icon_overlay_size">24dp</dimen>
-
<dimen name="segmented_button_spacing">0dp</dimen>
<dimen name="borderless_button_radius">2dp</dimen>
@@ -547,8 +530,6 @@
<!-- Padding between subtitles and the following text in the QSFooter dialog -->
<dimen name="qs_footer_dialog_subtitle_padding">20dp</dimen>
- <dimen name="qs_detail_margin_top">@*android:dimen/quick_qs_offset_height</dimen>
-
<!-- Zen mode panel: spacing between two-line condition upper and lower lines -->
<dimen name="zen_mode_condition_detail_item_interline_spacing">4dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index d39e295..3b7e9d4 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -609,8 +609,6 @@
<string name="quick_settings_inversion_label">Color inversion</string>
<!-- QuickSettings: Label for the toggle that controls whether display color correction is enabled. [CHAR LIMIT=NONE] -->
<string name="quick_settings_color_correction_label">Color correction</string>
- <!-- QuickSettings: Control panel: Label for button that navigates to settings. [CHAR LIMIT=NONE] -->
- <string name="quick_settings_more_settings">More settings</string>
<!-- QuickSettings: Control panel: Label for button that navigates to user settings. [CHAR LIMIT=NONE] -->
<string name="quick_settings_more_user_settings">User settings</string>
<!-- QuickSettings: Control panel: Label for button that dismisses control panel. [CHAR LIMIT=NONE] -->
@@ -1213,9 +1211,6 @@
<!-- Alarm template for far alarms [CHAR LIMIT=25] -->
<string name="alarm_template_far">on <xliff:g id="when" example="Fri 7:00 AM">%1$s</xliff:g></string>
- <!-- Accessibility label for Quick Settings detail screens [CHAR LIMIT=NONE] -->
- <string name="accessibility_quick_settings_detail">Quick Settings, <xliff:g id="title" example="Wi-Fi">%s</xliff:g>.</string>
-
<!-- Accessibility label for hotspot icon [CHAR LIMIT=NONE] -->
<string name="accessibility_status_bar_hotspot">Hotspot</string>
@@ -1731,11 +1726,6 @@
<string name="data_connection_no_internet">No internet</string>
<!-- accessibility label for quick settings items that open a details page [CHAR LIMIT=NONE] -->
- <string name="accessibility_quick_settings_open_details">Open details.</string>
-
- <!-- accessibility label for quick settings items that are currently disabled. Must have a reason [CHAR LIMIT=NONE] -->
-
- <!-- accessibility label for quick settings items that open a details page [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_open_settings">Open <xliff:g name="page" example="Bluetooth">%s</xliff:g> settings.</string>
<!-- accessibility label for button to edit quick settings [CHAR LIMIT=NONE] -->
@@ -2402,4 +2392,8 @@
<!-- Generic "add" string [CHAR LIMIT=NONE] -->
<string name="add">Add</string>
+ <!-- Add supervised user -->
+ <string name="add_user_supervised" translatable="false">@*android:string/supervised_user_creation_label</string>
+ <!-- Manage users - For system user management [CHAR LIMIT=40] -->
+ <string name="manage_users">Manage users</string>
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 9448d3f..b983545 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -96,17 +96,12 @@
<item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
</style>
- <style name="TextAppearance.QS.DetailHeader">
- <item name="android:textSize">@dimen/qs_detail_header_text_size</item>
- <item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item>
- </style>
-
<style name="TextAppearance.QS.DetailItemPrimary">
- <item name="android:textSize">@dimen/qs_detail_item_primary_text_size</item>
+ <item name="android:textSize">@dimen/qs_tile_text_size</item>
</style>
<style name="TextAppearance.QS.DetailItemSecondary">
- <item name="android:textSize">@dimen/qs_detail_item_secondary_text_size</item>
+ <item name="android:textSize">@dimen/qs_tile_text_size</item>
<item name="android:textColor">?android:attr/colorAccent</item>
</style>
@@ -120,23 +115,6 @@
<item name="android:textColor">?android:attr/colorError</item>
</style>
- <style name="TextAppearance.QS.DetailButton">
- <item name="android:textSize">@dimen/qs_detail_button_text_size</item>
- <item name="android:textColor">?android:attr/textColorSecondary</item>
- <item name="android:textAllCaps">true</item>
- <item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item>
- <item name="android:gravity">center</item>
- </style>
-
- <style name="TextAppearance.QS.DetailButton.White">
- <item name="android:textColor">@color/zen_introduction</item>
- </style>
-
- <style name="TextAppearance.QS.DetailEmpty">
- <item name="android:textSize">@dimen/qs_detail_empty_text_size</item>
- <item name="android:textColor">?android:attr/textColorPrimary</item>
- </style>
-
<style name="TextAppearance.QS.SegmentedButton">
<item name="android:textSize">16sp</item>
<item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item>
@@ -167,7 +145,7 @@
</style>
<style name="TextAppearance.QS.UserSwitcher">
- <item name="android:textSize">@dimen/qs_detail_item_secondary_text_size</item>
+ <item name="android:textSize">@dimen/qs_tile_text_size</item>
<item name="android:textColor">?android:attr/textColorSecondary</item>
</style>
@@ -433,9 +411,6 @@
<item name="numColumns">3</item>
</style>
- <style name="AutoSizingList">
- <item name="enableAutoSizing">true</item>
- </style>
<style name="Theme.SystemUI.MediaProjectionAlertDialog">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
@@ -779,11 +754,10 @@
<item name="android:windowSplashScreenAnimatedIcon">@drawable/ic_blank</item>
</style>
- <style name="Theme.CreateUser" parent="@style/Theme.SystemUI">
+ <style name="Theme.CreateUser" parent="@android:style/Theme.DeviceDefault.NoActionBar">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">#33000000</item>
- <item name="android:windowActionBar">false</item>
- <item name="android:windowNoTitle">true</item>
+ <item name="android:windowFullscreen">true</item>
</style>
<style name="Theme.PeopleTileConfigActivity" parent="@style/Theme.SystemUI">
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
index 4d0c443..c9a659a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
@@ -17,6 +17,7 @@
package com.android.systemui.shared.system;
import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
+import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
@@ -31,6 +32,7 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.util.ArrayMap;
+import android.util.SparseArray;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.view.WindowManager;
@@ -55,7 +57,7 @@
public static final int ACTIVITY_TYPE_ASSISTANT = WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
public final int activityType;
- public final int taskId;
+ public int taskId;
public final SurfaceControl leash;
public final boolean isTranslucent;
public final Rect clipRect;
@@ -67,7 +69,7 @@
public final Rect startScreenSpaceBounds;
public final boolean isNotInRecents;
public final Rect contentInsets;
- public final ActivityManager.RunningTaskInfo taskInfo;
+ public ActivityManager.RunningTaskInfo taskInfo;
public final boolean allowEnterPip;
public final int rotationChange;
public final int windowType;
@@ -139,12 +141,21 @@
// changes should be ordered top-to-bottom in z
final int mode = change.getMode();
- // Launcher animates leaf tasks directly, so always reparent all task leashes to root leash.
- t.reparent(leash, info.getRootLeash());
- t.setPosition(leash, change.getStartAbsBounds().left - info.getRootOffset().x,
- change.getStartAbsBounds().top - info.getRootOffset().y);
+ // Don't move anything that isn't independent within its parents
+ if (!TransitionInfo.isIndependent(change, info)) {
+ if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT || mode == TRANSIT_CHANGE) {
+ t.setPosition(leash, change.getEndRelOffset().x, change.getEndRelOffset().y);
+ }
+ return;
+ }
- t.show(leash);
+ final boolean hasParent = change.getParent() != null;
+
+ if (!hasParent) {
+ t.reparent(leash, info.getRootLeash());
+ t.setPosition(leash, change.getStartAbsBounds().left - info.getRootOffset().x,
+ change.getStartAbsBounds().top - info.getRootOffset().y);
+ }
// Put all the OPEN/SHOW on top
if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) {
if (isOpening) {
@@ -181,8 +192,12 @@
}
SurfaceControl leashSurface = new SurfaceControl.Builder()
.setName(change.getLeash().toString() + "_transition-leash")
- .setContainerLayer().setParent(change.getParent() == null ? info.getRootLeash()
- : info.getChange(change.getParent()).getLeash()).build();
+ .setContainerLayer()
+ // Initial the surface visible to respect the visibility of the original surface.
+ .setHidden(false)
+ .setParent(change.getParent() == null ? info.getRootLeash()
+ : info.getChange(change.getParent()).getLeash())
+ .build();
// Copied Transitions setup code (which expects bottom-to-top order, so we swap here)
setupLeash(leashSurface, change, info.getChanges().size() - order, info, t);
t.reparent(change.getLeash(), leashSurface);
@@ -253,17 +268,42 @@
public static RemoteAnimationTargetCompat[] wrap(TransitionInfo info, boolean wallpapers,
SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap) {
final ArrayList<RemoteAnimationTargetCompat> out = new ArrayList<>();
+ final SparseArray<RemoteAnimationTargetCompat> childTaskTargets = new SparseArray<>();
for (int i = 0; i < info.getChanges().size(); i++) {
final TransitionInfo.Change change = info.getChanges().get(i);
final boolean changeIsWallpaper =
(change.getFlags() & TransitionInfo.FLAG_IS_WALLPAPER) != 0;
if (wallpapers != changeIsWallpaper) continue;
- out.add(new RemoteAnimationTargetCompat(change, info.getChanges().size() - i, info, t));
+ final RemoteAnimationTargetCompat targetCompat =
+ new RemoteAnimationTargetCompat(change, info.getChanges().size() - i, info, t);
if (leashMap != null) {
- leashMap.put(change.getLeash(), out.get(out.size() - 1).leash);
+ leashMap.put(change.getLeash(), targetCompat.leash);
}
+ final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
+ if (taskInfo != null) {
+ if (taskInfo.parentTaskId != -1) {
+ // Cache child task targets to override its parent target later and exclude
+ // child task while wrapping up animate targets. Otherwise the child task might
+ // get transformed twice with the flow like RecentsView#redrawLiveTile.
+ childTaskTargets.put(taskInfo.parentTaskId, targetCompat);
+ continue;
+ }
+
+ final RemoteAnimationTargetCompat childTaskTarget =
+ childTaskTargets.get(taskInfo.taskId);
+ if (childTaskTarget != null) {
+ // Launcher monitors leaf tasks to perform animation, hence override the parent
+ // task target with child task info so Launcher can locate and animate root
+ // surface directly with leaf task information.
+ targetCompat.taskInfo = childTaskTarget.taskInfo;
+ targetCompat.taskId = childTaskTarget.taskId;
+ }
+ }
+
+ out.add(targetCompat);
}
+
return out.toArray(new RemoteAnimationTargetCompat[out.size()]);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 2ef8d6d..99e0ec1 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -86,8 +86,6 @@
import android.util.SparseArray;
import android.util.SparseBooleanArray;
-import androidx.lifecycle.Observer;
-
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.util.LatencyTracker;
@@ -109,7 +107,6 @@
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.util.Assert;
-import com.android.systemui.util.RingerModeTracker;
import com.google.android.collect.Lists;
@@ -146,7 +143,6 @@
private static final boolean DEBUG_ACTIVE_UNLOCK = Build.IS_DEBUGGABLE;
private static final boolean DEBUG_SPEW = false;
private static final int BIOMETRIC_LOCKOUT_RESET_DELAY_MS = 600;
- private int mNumActiveUnlockTriggers = 0;
private static final String ACTION_FACE_UNLOCK_STARTED
= "com.android.facelock.FACE_UNLOCK_STARTED";
@@ -157,7 +153,6 @@
private static final int MSG_TIME_UPDATE = 301;
private static final int MSG_BATTERY_UPDATE = 302;
private static final int MSG_SIM_STATE_CHANGE = 304;
- private static final int MSG_RINGER_MODE_CHANGED = 305;
private static final int MSG_PHONE_STATE_CHANGED = 306;
private static final int MSG_DEVICE_PROVISIONED = 308;
private static final int MSG_DPM_STATE_CHANGED = 309;
@@ -313,7 +308,6 @@
private TrustManager mTrustManager;
private UserManager mUserManager;
private KeyguardBypassController mKeyguardBypassController;
- private RingerModeTracker mRingerModeTracker;
private int mFingerprintRunningState = BIOMETRIC_STATE_STOPPED;
private int mFaceRunningState = BIOMETRIC_STATE_STOPPED;
private boolean mIsFaceAuthUserRequested;
@@ -325,8 +319,6 @@
private final InteractionJankMonitor mInteractionJankMonitor;
private final LatencyTracker mLatencyTracker;
private boolean mLogoutEnabled;
- // cached value to avoid IPCs
- private boolean mIsUdfpsEnrolled;
private boolean mIsFaceEnrolled;
// If the user long pressed the lock icon, disabling face auth for the current session.
private boolean mLockIconPressed;
@@ -362,13 +354,6 @@
private final Handler mHandler;
- private final Observer<Integer> mRingerModeObserver = new Observer<Integer>() {
- @Override
- public void onChanged(Integer ringer) {
- mHandler.obtainMessage(MSG_RINGER_MODE_CHANGED, ringer, 0).sendToTarget();
- }
- };
-
private SparseBooleanArray mBiometricEnabledForUser = new SparseBooleanArray();
private BiometricManager mBiometricManager;
private IBiometricEnabledOnKeyguardCallback mBiometricEnabledCallback =
@@ -1808,10 +1793,6 @@
mFaceRunningState = BIOMETRIC_STATE_STOPPED;
}
- private void registerRingerTracker() {
- mRingerModeTracker.getRingerMode().observeForever(mRingerModeObserver);
- }
-
@VisibleForTesting
@Inject
protected KeyguardUpdateMonitor(
@@ -1819,7 +1800,6 @@
@Main Looper mainLooper,
BroadcastDispatcher broadcastDispatcher,
DumpManager dumpManager,
- RingerModeTracker ringerModeTracker,
@Background Executor backgroundExecutor,
@Main Executor mainExecutor,
StatusBarStateController statusBarStateController,
@@ -1837,7 +1817,6 @@
mBroadcastDispatcher = broadcastDispatcher;
mInteractionJankMonitor = interactionJankMonitor;
mLatencyTracker = latencyTracker;
- mRingerModeTracker = ringerModeTracker;
mStatusBarStateController = statusBarStateController;
mStatusBarStateController.addCallback(mStatusBarStateControllerListener);
mStatusBarState = mStatusBarStateController.getState();
@@ -1862,9 +1841,6 @@
case MSG_SIM_STATE_CHANGE:
handleSimStateChange(msg.arg1, msg.arg2, (int) msg.obj);
break;
- case MSG_RINGER_MODE_CHANGED:
- handleRingerModeChange(msg.arg1);
- break;
case MSG_PHONE_STATE_CHANGED:
handlePhoneStateChanged((String) msg.obj);
break;
@@ -2006,8 +1982,6 @@
}
});
- mHandler.post(this::registerRingerTracker);
-
final IntentFilter allUserFilter = new IntentFilter();
allUserFilter.addAction(Intent.ACTION_USER_INFO_CHANGED);
allUserFilter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED);
@@ -2117,10 +2091,6 @@
false, mTimeFormatChangeObserver, UserHandle.USER_ALL);
}
- private void updateUdfpsEnrolled(int userId) {
- mIsUdfpsEnrolled = mAuthController.isUdfpsEnrolled(userId);
- }
-
private void updateFaceEnrolled(int userId) {
mIsFaceEnrolled = whitelistIpcs(
() -> mFaceManager != null && mFaceManager.isHardwareDetected()
@@ -2132,7 +2102,7 @@
* @return true if there's at least one udfps enrolled for the current user.
*/
public boolean isUdfpsEnrolled() {
- return mIsUdfpsEnrolled;
+ return mAuthController.isUdfpsEnrolled(getCurrentUser());
}
/**
@@ -2186,7 +2156,6 @@
return;
}
- updateUdfpsEnrolled(getCurrentUser());
final boolean shouldListenForFingerprint = shouldListenForFingerprint(isUdfpsSupported());
final boolean runningOrRestarting = mFingerprintRunningState == BIOMETRIC_STATE_RUNNING
|| mFingerprintRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING;
@@ -2750,12 +2719,6 @@
Assert.isMainThread();
updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
updateSecondaryLockscreenRequirement(userId);
- for (int i = 0; i < mCallbacks.size(); i++) {
- KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
- if (cb != null) {
- cb.onDevicePolicyManagerStateChanged();
- }
- }
}
/**
@@ -2834,21 +2797,6 @@
}
/**
- * Handle {@link #MSG_RINGER_MODE_CHANGED}
- */
- private void handleRingerModeChange(int mode) {
- Assert.isMainThread();
- if (DEBUG) Log.d(TAG, "handleRingerModeChange(" + mode + ")");
- mRingMode = mode;
- for (int i = 0; i < mCallbacks.size(); i++) {
- KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
- if (cb != null) {
- cb.onRingerModeChanged(mode);
- }
- }
- }
-
- /**
* Handle {@link #MSG_TIME_UPDATE}
*/
private void handleTimeUpdate() {
@@ -3235,7 +3183,6 @@
// Notify listener of the current state
callback.onRefreshBatteryInfo(mBatteryStatus);
callback.onTimeChanged();
- callback.onRingerModeChanged(mRingMode);
callback.onPhoneStateChanged(mPhoneState);
callback.onRefreshCarrierInfo();
callback.onClockVisibilityChanged();
@@ -3546,7 +3493,6 @@
mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver);
mBroadcastDispatcher.unregisterReceiver(mBroadcastAllReceiver);
- mRingerModeTracker.getRingerMode().removeObserver(mRingerModeObserver);
mLockPatternUtils.unregisterStrongAuthTracker(mStrongAuthTracker);
mTrustManager.unregisterTrustListener(this);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 47e1035..8d5603d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -15,10 +15,7 @@
*/
package com.android.keyguard;
-import android.app.admin.DevicePolicyManager;
-import android.graphics.Bitmap;
import android.hardware.biometrics.BiometricSourceType;
-import android.media.AudioManager;
import android.os.SystemClock;
import android.telephony.TelephonyManager;
import android.view.WindowManagerPolicyConstants;
@@ -70,13 +67,6 @@
public void onRefreshCarrierInfo() { }
/**
- * Called when the ringer mode changes.
- * @param state the current ringer state, as defined in
- * {@link AudioManager#RINGER_MODE_CHANGED_ACTION}
- */
- public void onRingerModeChanged(int state) { }
-
- /**
* Called when the phone state changes. String will be one of:
* {@link TelephonyManager#EXTRA_STATE_IDLE}
* {@link TelephonyManager@EXTRA_STATE_RINGING}
@@ -124,12 +114,6 @@
public void onDeviceProvisioned() { }
/**
- * Called when the device policy changes.
- * See {@link DevicePolicyManager#ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED}
- */
- public void onDevicePolicyManagerStateChanged() { }
-
- /**
* Called when the user change begins.
*/
public void onUserSwitching(int userId) { }
@@ -168,14 +152,7 @@
public void onEmergencyCallAction() { }
/**
- * Called when the transport background changes.
- * @param bitmap
- */
- public void onSetBackground(Bitmap bitmap) {
- }
-
- /**
- * Called when the device has started waking up.
+ * Called when the device has started waking up and after biometric states are updated.
*
* @deprecated use {@link com.android.systemui.keyguard.WakefulnessLifecycle}.
*/
@@ -183,7 +160,8 @@
public void onStartedWakingUp() { }
/**
- * Called when the device has started going to sleep.
+ * Called when the device has started going to sleep and after biometric recognized
+ * states are reset.
* @param why see {@link #onFinishedGoingToSleep(int)}
*
* @deprecated use {@link com.android.systemui.keyguard.WakefulnessLifecycle}.
@@ -304,7 +282,6 @@
*/
public void onTrustAgentErrorMessage(CharSequence message) { }
-
/**
* Called when a value of logout enabled is change.
*/
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 80a3a0e..4ad5183 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -433,7 +433,6 @@
public void onDozingChanged(boolean isDozing) {
mIsDozing = isDozing;
updateBurnInOffsets();
- updateIsUdfpsEnrolled();
updateVisibility();
}
@@ -513,7 +512,6 @@
mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(
KeyguardUpdateMonitor.getCurrentUser());
}
- updateIsUdfpsEnrolled();
updateVisibility();
}
diff --git a/packages/SystemUI/src/com/android/systemui/DarkReceiverImpl.kt b/packages/SystemUI/src/com/android/systemui/DarkReceiverImpl.kt
index 42d38cb..13d96e4 100644
--- a/packages/SystemUI/src/com/android/systemui/DarkReceiverImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/DarkReceiverImpl.kt
@@ -32,11 +32,11 @@
private val dualToneHandler = DualToneHandler(context)
init {
- onDarkChanged(Rect(), 1f, DarkIconDispatcher.DEFAULT_ICON_TINT)
+ onDarkChanged(ArrayList<Rect>(), 1f, DarkIconDispatcher.DEFAULT_ICON_TINT)
}
- override fun onDarkChanged(area: Rect?, darkIntensity: Float, tint: Int) {
- val intensity = if (DarkIconDispatcher.isInArea(area, this)) darkIntensity else 0f
+ override fun onDarkChanged(areas: ArrayList<Rect>?, darkIntensity: Float, tint: Int) {
+ val intensity = if (DarkIconDispatcher.isInAreas(areas, this)) darkIntensity else 0f
setBackgroundColor(dualToneHandler.getSingleColor(intensity))
}
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt b/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
new file mode 100644
index 0000000..6bec8aa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
@@ -0,0 +1,276 @@
+/*
+ * 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.systemui
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ValueAnimator
+import android.annotation.Dimension
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Matrix
+import android.graphics.Paint
+import android.graphics.Path
+import android.graphics.Rect
+import android.graphics.RectF
+import android.graphics.Region
+import android.util.AttributeSet
+import android.view.Display
+import android.view.DisplayCutout
+import android.view.DisplayInfo
+import android.view.Surface
+import android.view.View
+import androidx.annotation.VisibleForTesting
+import com.android.systemui.RegionInterceptingFrameLayout.RegionInterceptableView
+import com.android.systemui.animation.Interpolators
+
+/**
+ * A class that handles common actions of display cutout view.
+ * - Draws cutouts.
+ * - Handles camera protection.
+ * - Intercepts touches on cutout areas.
+ */
+open class DisplayCutoutBaseView : View, RegionInterceptableView {
+
+ private val shouldDrawCutout: Boolean = DisplayCutout.getFillBuiltInDisplayCutout(
+ context.resources, context.display?.uniqueId)
+ private var displayMode: Display.Mode? = null
+ private val location = IntArray(2)
+ protected var displayRotation = 0
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
+ @JvmField val displayInfo = DisplayInfo()
+ @JvmField protected var pendingRotationChange = false
+ @JvmField protected val paint = Paint()
+ @JvmField protected val cutoutPath = Path()
+
+ @JvmField protected var showProtection = false
+ @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
+ @JvmField val protectionRect: RectF = RectF()
+ @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
+ @JvmField val protectionPath: Path = Path()
+ private val protectionRectOrig: RectF = RectF()
+ private val protectionPathOrig: Path = Path()
+ private var cameraProtectionProgress: Float = HIDDEN_CAMERA_PROTECTION_SCALE
+ private var cameraProtectionAnimator: ValueAnimator? = null
+
+ constructor(context: Context) : super(context)
+
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+
+ constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int)
+ : super(context, attrs, defStyleAttr)
+
+ override fun onAttachedToWindow() {
+ super.onAttachedToWindow()
+ updateCutout()
+ }
+
+ fun onDisplayChanged(displayId: Int) {
+ val oldMode: Display.Mode? = displayMode
+ displayMode = display.mode
+
+ // Skip if display mode or cutout hasn't changed.
+ if (!displayModeChanged(oldMode, displayMode) &&
+ display.cutout == displayInfo.displayCutout) {
+ return
+ }
+ if (displayId == display.displayId) {
+ updateCutout()
+ updateProtectionBoundingPath()
+ }
+ }
+
+ open fun updateRotation(rotation: Int) {
+ displayRotation = rotation
+ updateCutout()
+ updateProtectionBoundingPath()
+ }
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
+ public override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+ if (!shouldDrawCutout) {
+ return
+ }
+ canvas.save()
+ getLocationOnScreen(location)
+ canvas.translate(-location[0].toFloat(), -location[1].toFloat())
+
+ drawCutouts(canvas)
+ drawCutoutProtection(canvas)
+ canvas.restore()
+ }
+
+ override fun shouldInterceptTouch(): Boolean {
+ return displayInfo.displayCutout != null && visibility == VISIBLE && shouldDrawCutout
+ }
+
+ override fun getInterceptRegion(): Region? {
+ displayInfo.displayCutout ?: return null
+
+ val cutoutBounds: Region = rectsToRegion(displayInfo.displayCutout?.boundingRects)
+ // Transform to window's coordinate space
+ rootView.getLocationOnScreen(location)
+ cutoutBounds.translate(-location[0], -location[1])
+
+ // Intersect with window's frame
+ cutoutBounds.op(rootView.left, rootView.top, rootView.right, rootView.bottom,
+ Region.Op.INTERSECT)
+ return cutoutBounds
+ }
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
+ open fun updateCutout() {
+ if (pendingRotationChange) {
+ return
+ }
+ cutoutPath.reset()
+ display.getDisplayInfo(displayInfo)
+ displayInfo.displayCutout?.cutoutPath?.let { path -> cutoutPath.set(path) }
+ invalidate()
+ }
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
+ open fun drawCutouts(canvas: Canvas) {
+ displayInfo.displayCutout?.cutoutPath ?: return
+ canvas.drawPath(cutoutPath, paint)
+ }
+
+ protected open fun drawCutoutProtection(canvas: Canvas) {
+ if (cameraProtectionProgress > HIDDEN_CAMERA_PROTECTION_SCALE &&
+ !protectionRect.isEmpty) {
+ canvas.scale(cameraProtectionProgress, cameraProtectionProgress,
+ protectionRect.centerX(), protectionRect.centerY())
+ canvas.drawPath(protectionPath, paint)
+ }
+ }
+
+ /**
+ * Converts a set of [Rect]s into a [Region]
+ */
+ fun rectsToRegion(rects: List<Rect?>?): Region {
+ val result = Region.obtain()
+ if (rects != null) {
+ for (r in rects) {
+ if (r != null && !r.isEmpty) {
+ result.op(r, Region.Op.UNION)
+ }
+ }
+ }
+ return result
+ }
+
+ open fun enableShowProtection(show: Boolean) {
+ if (showProtection == show) {
+ return
+ }
+ showProtection = show
+ updateProtectionBoundingPath()
+ // Delay the relayout until the end of the animation when hiding the cutout,
+ // otherwise we'd clip it.
+ if (showProtection) {
+ requestLayout()
+ }
+ cameraProtectionAnimator?.cancel()
+ cameraProtectionAnimator = ValueAnimator.ofFloat(cameraProtectionProgress,
+ if (showProtection) 1.0f else HIDDEN_CAMERA_PROTECTION_SCALE).setDuration(750)
+ cameraProtectionAnimator?.interpolator = Interpolators.DECELERATE_QUINT
+ cameraProtectionAnimator?.addUpdateListener(ValueAnimator.AnimatorUpdateListener {
+ animation: ValueAnimator ->
+ cameraProtectionProgress = animation.animatedValue as Float
+ invalidate()
+ })
+ cameraProtectionAnimator?.addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ cameraProtectionAnimator = null
+ if (!showProtection) {
+ requestLayout()
+ }
+ }
+ })
+ cameraProtectionAnimator?.start()
+ }
+
+ open fun setProtection(path: Path, pathBounds: Rect) {
+ protectionPathOrig.reset()
+ protectionPathOrig.set(path)
+ protectionPath.reset()
+ protectionRectOrig.setEmpty()
+ protectionRectOrig.set(pathBounds)
+ protectionRect.setEmpty()
+ }
+
+ protected open fun updateProtectionBoundingPath() {
+ if (pendingRotationChange) {
+ return
+ }
+ val lw: Int = displayInfo.logicalWidth
+ val lh: Int = displayInfo.logicalHeight
+ val flipped = (displayInfo.rotation == Surface.ROTATION_90 ||
+ displayInfo.rotation == Surface.ROTATION_270)
+ val dw = if (flipped) lh else lw
+ val dh = if (flipped) lw else lh
+ val m = Matrix()
+ transformPhysicalToLogicalCoordinates(displayInfo.rotation, dw, dh, m)
+ if (!protectionPathOrig.isEmpty) {
+ // Reset the protection path so we don't aggregate rotations
+ protectionPath.set(protectionPathOrig)
+ protectionPath.transform(m)
+ m.mapRect(protectionRect, protectionRectOrig)
+ }
+ }
+
+ private fun displayModeChanged(oldMode: Display.Mode?, newMode: Display.Mode?): Boolean {
+ if (oldMode == null) {
+ return true
+ }
+
+ // We purposely ignore refresh rate and id changes here, because we don't need to
+ // invalidate for those, and they can trigger the refresh rate to increase
+ return oldMode?.physicalHeight != newMode?.physicalHeight ||
+ oldMode?.physicalWidth != newMode?.physicalWidth
+ }
+
+ companion object {
+ private const val HIDDEN_CAMERA_PROTECTION_SCALE = 0.5f
+
+ @JvmStatic protected fun transformPhysicalToLogicalCoordinates(
+ @Surface.Rotation rotation: Int,
+ @Dimension physicalWidth: Int,
+ @Dimension physicalHeight: Int,
+ out: Matrix
+ ) {
+ when (rotation) {
+ Surface.ROTATION_0 -> out.reset()
+ Surface.ROTATION_90 -> {
+ out.setRotate(270f)
+ out.postTranslate(0f, physicalWidth.toFloat())
+ }
+ Surface.ROTATION_180 -> {
+ out.setRotate(180f)
+ out.postTranslate(physicalWidth.toFloat(), physicalHeight.toFloat())
+ }
+ Surface.ROTATION_270 -> {
+ out.setRotate(90f)
+ out.postTranslate(physicalHeight.toFloat(), 0f)
+ }
+ else -> throw IllegalArgumentException("Unknown rotation: $rotation")
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java b/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java
index c7f1006..95f666c 100644
--- a/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java
@@ -60,6 +60,7 @@
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PluginInflateContainer);
String viewType = a.getString(R.styleable.PluginInflateContainer_viewType);
+ a.recycle();
try {
mClass = (Class<ViewProvider>) Class.forName(viewType);
} catch (Exception e) {
diff --git a/packages/SystemUI/src/com/android/systemui/ResizingSpace.java b/packages/SystemUI/src/com/android/systemui/ResizingSpace.java
index c2bc53e..bb4176d 100644
--- a/packages/SystemUI/src/com/android/systemui/ResizingSpace.java
+++ b/packages/SystemUI/src/com/android/systemui/ResizingSpace.java
@@ -35,6 +35,7 @@
TypedArray a = context.obtainStyledAttributes(attrs, android.R.styleable.ViewGroup_Layout);
mWidth = a.getResourceId(android.R.styleable.ViewGroup_Layout_layout_width, 0);
mHeight = a.getResourceId(android.R.styleable.ViewGroup_Layout_layout_height, 0);
+ a.recycle();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt b/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt
new file mode 100644
index 0000000..ee1d9a3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt
@@ -0,0 +1,195 @@
+/*
+ * 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.systemui
+
+import android.content.Context
+import android.content.pm.ActivityInfo
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.ColorFilter
+import android.graphics.Paint
+import android.graphics.PixelFormat
+import android.graphics.PorterDuff
+import android.graphics.PorterDuffColorFilter
+import android.graphics.PorterDuffXfermode
+import android.graphics.drawable.Drawable
+import android.hardware.graphics.common.AlphaInterpretation
+import android.hardware.graphics.common.DisplayDecorationSupport
+import android.view.RoundedCorner
+import android.view.RoundedCorners
+
+/**
+ * When the HWC of the device supports Composition.DISPLAY_DECORATON, we use this layer to draw
+ * screen decorations.
+ */
+class ScreenDecorHwcLayer(context: Context, displayDecorationSupport: DisplayDecorationSupport)
+ : DisplayCutoutBaseView(context) {
+ public val colorMode: Int
+ private val useInvertedAlphaColor: Boolean
+ private val color: Int
+ private val bgColor: Int
+ private val cornerFilter: ColorFilter
+ private val cornerBgFilter: ColorFilter
+ private val clearPaint: Paint
+
+ private var roundedCornerTopSize = 0
+ private var roundedCornerBottomSize = 0
+ private var roundedCornerDrawableTop: Drawable? = null
+ private var roundedCornerDrawableBottom: Drawable? = null
+
+ init {
+ if (displayDecorationSupport.format != PixelFormat.R_8) {
+ throw IllegalArgumentException("Attempting to use unsupported mode " +
+ "${PixelFormat.formatToString(displayDecorationSupport.format)}")
+ }
+ if (DEBUG_COLOR) {
+ color = Color.GREEN
+ bgColor = Color.TRANSPARENT
+ colorMode = ActivityInfo.COLOR_MODE_DEFAULT
+ useInvertedAlphaColor = false
+ } else {
+ colorMode = ActivityInfo.COLOR_MODE_A8
+ useInvertedAlphaColor = displayDecorationSupport.alphaInterpretation ==
+ AlphaInterpretation.COVERAGE
+ if (useInvertedAlphaColor) {
+ color = Color.TRANSPARENT
+ bgColor = Color.BLACK
+ } else {
+ color = Color.BLACK
+ bgColor = Color.TRANSPARENT
+ }
+ }
+ cornerFilter = PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN)
+ cornerBgFilter = PorterDuffColorFilter(bgColor, PorterDuff.Mode.SRC_OUT)
+
+ clearPaint = Paint()
+ clearPaint.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)
+ }
+
+ override fun onAttachedToWindow() {
+ super.onAttachedToWindow()
+ viewRootImpl.setDisplayDecoration(true)
+
+ if (useInvertedAlphaColor) {
+ paint.set(clearPaint)
+ } else {
+ paint.color = color
+ paint.style = Paint.Style.FILL
+ }
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ if (useInvertedAlphaColor) {
+ canvas.drawColor(bgColor)
+ }
+ // Cutouts are drawn in DisplayCutoutBaseView.onDraw()
+ super.onDraw(canvas)
+ drawRoundedCorners(canvas)
+ }
+
+ private fun drawRoundedCorners(canvas: Canvas) {
+ if (roundedCornerTopSize == 0 && roundedCornerBottomSize == 0) {
+ return
+ }
+ var degree: Int
+ for (i in RoundedCorner.POSITION_TOP_LEFT
+ until RoundedCorners.ROUNDED_CORNER_POSITION_LENGTH) {
+ canvas.save()
+ degree = getRoundedCornerRotationDegree(90 * i)
+ canvas.rotate(degree.toFloat())
+ canvas.translate(
+ getRoundedCornerTranslationX(degree).toFloat(),
+ getRoundedCornerTranslationY(degree).toFloat())
+ if (i == RoundedCorner.POSITION_TOP_LEFT || i == RoundedCorner.POSITION_TOP_RIGHT) {
+ drawRoundedCorner(canvas, roundedCornerDrawableTop, roundedCornerTopSize)
+ } else {
+ drawRoundedCorner(canvas, roundedCornerDrawableBottom, roundedCornerBottomSize)
+ }
+ canvas.restore()
+ }
+ }
+
+ private fun drawRoundedCorner(canvas: Canvas, drawable: Drawable?, size: Int) {
+ if (useInvertedAlphaColor) {
+ canvas.drawRect(0f, 0f, size.toFloat(), size.toFloat(), clearPaint)
+ drawable?.colorFilter = cornerBgFilter
+ } else {
+ drawable?.colorFilter = cornerFilter
+ }
+ drawable?.draw(canvas)
+ // Clear color filter when we are done with drawing.
+ drawable?.clearColorFilter()
+ }
+
+ private fun getRoundedCornerRotationDegree(defaultDegree: Int): Int {
+ return (defaultDegree - 90 * displayRotation + 360) % 360
+ }
+
+ private fun getRoundedCornerTranslationX(degree: Int): Int {
+ return when (degree) {
+ 0, 90 -> 0
+ 180 -> -width
+ 270 -> -height
+ else -> throw IllegalArgumentException("Incorrect degree: $degree")
+ }
+ }
+
+ private fun getRoundedCornerTranslationY(degree: Int): Int {
+ return when (degree) {
+ 0, 270 -> 0
+ 90 -> -width
+ 180 -> -height
+ else -> throw IllegalArgumentException("Incorrect degree: $degree")
+ }
+ }
+
+ /**
+ * Update the rounded corner drawables.
+ */
+ fun updateRoundedCornerDrawable(top: Drawable, bottom: Drawable) {
+ roundedCornerDrawableTop = top
+ roundedCornerDrawableBottom = bottom
+ updateRoundedCornerDrawableBounds()
+ invalidate()
+ }
+
+ /**
+ * Update the rounded corner size.
+ */
+ fun updateRoundedCornerSize(top: Int, bottom: Int) {
+ roundedCornerTopSize = top
+ roundedCornerBottomSize = bottom
+ updateRoundedCornerDrawableBounds()
+ invalidate()
+ }
+
+ private fun updateRoundedCornerDrawableBounds() {
+ if (roundedCornerDrawableTop != null) {
+ roundedCornerDrawableTop?.setBounds(0, 0, roundedCornerTopSize,
+ roundedCornerTopSize)
+ }
+ if (roundedCornerDrawableBottom != null) {
+ roundedCornerDrawableBottom?.setBounds(0, 0, roundedCornerBottomSize,
+ roundedCornerBottomSize)
+ }
+ invalidate()
+ }
+
+ companion object {
+ private val DEBUG_COLOR = ScreenDecorations.DEBUG_COLOR
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 783415e..2ec5f4f 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -14,24 +14,17 @@
package com.android.systemui;
-import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.DisplayCutout.BOUNDS_POSITION_BOTTOM;
import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT;
import static android.view.DisplayCutout.BOUNDS_POSITION_LENGTH;
import static android.view.DisplayCutout.BOUNDS_POSITION_RIGHT;
import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
-import static android.view.Surface.ROTATION_0;
-import static android.view.Surface.ROTATION_180;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.annotation.Dimension;
import android.annotation.IdRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -40,11 +33,11 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
-import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
@@ -52,10 +45,10 @@
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.Region;
import android.graphics.drawable.Drawable;
import android.hardware.display.DisplayManager;
+import android.hardware.graphics.common.AlphaInterpretation;
+import android.hardware.graphics.common.DisplayDecorationSupport;
import android.os.Handler;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -63,14 +56,11 @@
import android.util.DisplayMetrics;
import android.util.DisplayUtils;
import android.util.Log;
-import android.view.Display;
import android.view.DisplayCutout;
import android.view.DisplayCutout.BoundsPosition;
-import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.RoundedCorners;
-import android.view.Surface;
import android.view.View;
import android.view.View.OnLayoutChangeListener;
import android.view.ViewGroup;
@@ -83,8 +73,6 @@
import androidx.annotation.VisibleForTesting;
import com.android.internal.util.Preconditions;
-import com.android.systemui.RegionInterceptingFrameLayout.RegionInterceptableView;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
@@ -106,6 +94,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -117,7 +106,7 @@
* for antialiasing and emulation purposes.
*/
@SysUISingleton
-public class ScreenDecorations extends CoreStartable implements Tunable , Dumpable{
+public class ScreenDecorations extends CoreStartable implements Tunable , Dumpable {
private static final boolean DEBUG = false;
private static final String TAG = "ScreenDecorations";
@@ -129,7 +118,7 @@
private static final boolean DEBUG_SCREENSHOT_ROUNDED_CORNERS =
SystemProperties.getBoolean("debug.screenshot_rounded_corners", false);
private static final boolean VERBOSE = false;
- private static final boolean DEBUG_COLOR = DEBUG_SCREENSHOT_ROUNDED_CORNERS;
+ static final boolean DEBUG_COLOR = DEBUG_SCREENSHOT_ROUNDED_CORNERS;
private DisplayManager mDisplayManager;
@VisibleForTesting
@@ -138,7 +127,8 @@
private final Executor mMainExecutor;
private final TunerService mTunerService;
private final SecureSettings mSecureSettings;
- private DisplayManager.DisplayListener mDisplayListener;
+ @VisibleForTesting
+ DisplayManager.DisplayListener mDisplayListener;
private CameraAvailabilityListener mCameraListener;
private final UserTracker mUserTracker;
private final PrivacyDotViewController mDotViewController;
@@ -158,23 +148,36 @@
protected OverlayWindow[] mOverlays = null;
@Nullable
private DisplayCutoutView[] mCutoutViews;
+ @VisibleForTesting
+ ViewGroup mScreenDecorHwcWindow;
+ @VisibleForTesting
+ ScreenDecorHwcLayer mScreenDecorHwcLayer;
private float mDensity;
private WindowManager mWindowManager;
private int mRotation;
private SettingObserver mColorInversionSetting;
private DelayableExecutor mExecutor;
private Handler mHandler;
- private boolean mPendingRotationChange;
+ boolean mPendingRotationChange;
private boolean mIsRoundedCornerMultipleRadius;
private Drawable mRoundedCornerDrawable;
private Drawable mRoundedCornerDrawableTop;
private Drawable mRoundedCornerDrawableBottom;
- private String mDisplayUniqueId;
+ @VisibleForTesting
+ String mDisplayUniqueId;
+ private int mTintColor = Color.BLACK;
+ @VisibleForTesting
+ protected DisplayDecorationSupport mHwcScreenDecorationSupport;
private CameraAvailabilityListener.CameraTransitionCallback mCameraTransitionCallback =
new CameraAvailabilityListener.CameraTransitionCallback() {
@Override
public void onApplyCameraProtection(@NonNull Path protectionPath, @NonNull Rect bounds) {
+ if (mScreenDecorHwcLayer != null) {
+ mScreenDecorHwcLayer.setProtection(protectionPath, bounds);
+ mScreenDecorHwcLayer.enableShowProtection(true);
+ return;
+ }
if (mCutoutViews == null) {
Log.w(TAG, "DisplayCutoutView do not initialized");
return;
@@ -184,13 +187,17 @@
// Check Null since not all mCutoutViews[pos] be inflated at the meanwhile
if (dcv != null) {
dcv.setProtection(protectionPath, bounds);
- dcv.setShowProtection(true);
+ dcv.enableShowProtection(true);
}
}
}
@Override
public void onHideCameraProtection() {
+ if (mScreenDecorHwcLayer != null) {
+ mScreenDecorHwcLayer.enableShowProtection(false);
+ return;
+ }
if (mCutoutViews == null) {
Log.w(TAG, "DisplayCutoutView do not initialized");
return;
@@ -199,27 +206,59 @@
for (DisplayCutoutView dcv : mCutoutViews) {
// Check Null since not all mCutoutViews[pos] be inflated at the meanwhile
if (dcv != null) {
- dcv.setShowProtection(false);
+ dcv.enableShowProtection(false);
}
}
}
};
- /**
- * Converts a set of {@link Rect}s into a {@link Region}
- *
- * @hide
- */
- public static Region rectsToRegion(List<Rect> rects) {
- Region result = Region.obtain();
- if (rects != null) {
- for (Rect r : rects) {
- if (r != null && !r.isEmpty()) {
- result.op(r, Region.Op.UNION);
- }
+ private PrivacyDotViewController.ShowingListener mPrivacyDotShowingListener =
+ new PrivacyDotViewController.ShowingListener() {
+ @Override
+ public void onPrivacyDotShown(@Nullable View v) {
+ // We don't need to control the window visibility when the hwc doesn't support screen
+ // decoration since the overlay windows are always visible in this case.
+ if (mHwcScreenDecorationSupport == null || v == null) {
+ return;
}
+ mExecutor.execute(() -> {
+ for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
+ if (mOverlays[i] == null) {
+ continue;
+ }
+ final ViewGroup overlayView = mOverlays[i].getRootView();
+ if (overlayView.findViewById(v.getId()) != null) {
+ overlayView.setVisibility(View.VISIBLE);
+ }
+ }
+ });
}
- return result;
+
+ @Override
+ public void onPrivacyDotHidden(@Nullable View v) {
+ // We don't need to control the window visibility when the hwc doesn't support screen
+ // decoration since the overlay windows are always visible in this case.
+ if (mHwcScreenDecorationSupport == null || v == null) {
+ return;
+ }
+ mExecutor.execute(() -> {
+ for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
+ if (mOverlays[i] == null) {
+ continue;
+ }
+ final ViewGroup overlayView = mOverlays[i].getRootView();
+ if (overlayView.findViewById(v.getId()) != null) {
+ overlayView.setVisibility(View.INVISIBLE);
+ }
+ }
+ });
+ }
+ };
+
+ private static boolean eq(DisplayDecorationSupport a, DisplayDecorationSupport b) {
+ if (a == null) return (b == null);
+ if (b == null) return false;
+ return a.format == b.format && a.alphaInterpretation == b.alphaInterpretation;
}
@Inject
@@ -241,6 +280,7 @@
mDotViewController = dotViewController;
mThreadFactory = threadFactory;
mDotFactory = dotFactory;
+ dotViewController.setShowingListener(mPrivacyDotShowingListener);
}
@Override
@@ -265,6 +305,7 @@
mIsRoundedCornerMultipleRadius = isRoundedCornerMultipleRadius(mContext, mDisplayUniqueId);
mWindowManager = mContext.getSystemService(WindowManager.class);
mDisplayManager = mContext.getSystemService(DisplayManager.class);
+ mHwcScreenDecorationSupport = mContext.getDisplay().getDisplayDecorationSupport();
updateRoundedCornerDrawable();
updateRoundedCornerRadii();
setupDecorations();
@@ -305,15 +346,36 @@
new RestartingPreDrawListener(overlayView, i, newRotation));
}
}
+
+ if (mScreenDecorHwcWindow != null) {
+ mScreenDecorHwcWindow.getViewTreeObserver().addOnPreDrawListener(
+ new RestartingPreDrawListener(
+ mScreenDecorHwcWindow,
+ -1, // Pass -1 for views with no specific position.
+ newRotation));
+ }
}
+
final String newUniqueId = mContext.getDisplay().getUniqueId();
- if ((newUniqueId != null && !newUniqueId.equals(mDisplayUniqueId))
- || (mDisplayUniqueId != null && !mDisplayUniqueId.equals(newUniqueId))) {
+ if (!Objects.equals(newUniqueId, mDisplayUniqueId)) {
mDisplayUniqueId = newUniqueId;
mIsRoundedCornerMultipleRadius =
isRoundedCornerMultipleRadius(mContext, mDisplayUniqueId);
+ final DisplayDecorationSupport newScreenDecorationSupport =
+ mContext.getDisplay().getDisplayDecorationSupport();
+ // When the value of mSupportHwcScreenDecoration is changed, re-setup the whole
+ // screen decoration.
+ if (!eq(newScreenDecorationSupport, mHwcScreenDecorationSupport)) {
+ mHwcScreenDecorationSupport = newScreenDecorationSupport;
+ removeAllOverlays();
+ setupDecorations();
+ return;
+ }
updateRoundedCornerDrawable();
}
+ if (mScreenDecorHwcLayer != null) {
+ mScreenDecorHwcLayer.onDisplayChanged(displayId);
+ }
updateOrientation();
}
};
@@ -359,6 +421,11 @@
List<DecorProvider> decorProviders = mDotFactory.getProviders();
if (hasRoundedCorners() || shouldDrawCutout() || !decorProviders.isEmpty()) {
+ if (mHwcScreenDecorationSupport != null) {
+ createHwcOverlay();
+ } else {
+ removeHwcOverlay();
+ }
final DisplayCutout cutout = getCutout();
for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
if (shouldShowCutout(i, cutout) || shouldShowRoundedCorner(i, cutout)
@@ -383,14 +450,15 @@
}
} else {
removeAllOverlays();
+ removeHwcOverlay();
}
- if (hasOverlays()) {
+ if (hasOverlays() || hasHwcOverlay()) {
if (mIsRegistered) {
return;
}
DisplayMetrics metrics = new DisplayMetrics();
- mDisplayManager.getDisplay(DEFAULT_DISPLAY).getMetrics(metrics);
+ mContext.getDisplay().getMetrics(metrics);
mDensity = metrics.density;
mMainExecutor.execute(() -> mTunerService.addTunable(this, SIZE));
@@ -475,25 +543,27 @@
mOverlays = new OverlayWindow[BOUNDS_POSITION_LENGTH];
}
- if (mCutoutViews == null) {
- mCutoutViews = new DisplayCutoutView[BOUNDS_POSITION_LENGTH];
- }
-
if (mOverlays[pos] != null) {
return;
}
mOverlays[pos] = overlayForPosition(pos, decorProviders);
-
- mCutoutViews[pos] = new DisplayCutoutView(mContext, pos, this);
- mOverlays[pos].getRootView().addView(mCutoutViews[pos]);
-
final ViewGroup overlayView = mOverlays[pos].getRootView();
overlayView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
overlayView.setAlpha(0);
overlayView.setForceDarkAllowed(false);
- updateView(pos, cutout);
+ // Only show cutout and rounded corners in mOverlays when hwc don't support screen
+ // decoration.
+ if (mHwcScreenDecorationSupport == null) {
+ if (mCutoutViews == null) {
+ mCutoutViews = new DisplayCutoutView[BOUNDS_POSITION_LENGTH];
+ }
+ mCutoutViews[pos] = new DisplayCutoutView(mContext, pos);
+ mCutoutViews[pos].setColor(mTintColor);
+ overlayView.addView(mCutoutViews[pos]);
+ updateView(pos, cutout);
+ }
mWindowManager.addView(overlayView, getWindowLayoutParams(pos));
@@ -509,8 +579,37 @@
}
});
- mOverlays[pos].getRootView().getViewTreeObserver().addOnPreDrawListener(
- new ValidatingPreDrawListener(mOverlays[pos].getRootView()));
+ overlayView.getRootView().getViewTreeObserver().addOnPreDrawListener(
+ new ValidatingPreDrawListener(overlayView.getRootView()));
+ }
+
+ private boolean hasHwcOverlay() {
+ return mScreenDecorHwcWindow != null;
+ }
+
+ private void removeHwcOverlay() {
+ if (mScreenDecorHwcWindow == null) {
+ return;
+ }
+ mWindowManager.removeViewImmediate(mScreenDecorHwcWindow);
+ mScreenDecorHwcWindow = null;
+ mScreenDecorHwcLayer = null;
+ }
+
+ private void createHwcOverlay() {
+ if (mScreenDecorHwcWindow != null) {
+ return;
+ }
+ mScreenDecorHwcWindow = (ViewGroup) LayoutInflater.from(mContext).inflate(
+ R.layout.screen_decor_hwc_layer, null);
+ mScreenDecorHwcLayer = new ScreenDecorHwcLayer(mContext, mHwcScreenDecorationSupport);
+ mScreenDecorHwcWindow.addView(mScreenDecorHwcLayer, new FrameLayout.LayoutParams(
+ MATCH_PARENT, MATCH_PARENT, Gravity.TOP | Gravity.START));
+ mWindowManager.addView(mScreenDecorHwcWindow, getHwcWindowLayoutParams());
+ updateRoundedCornerSize(mRoundedDefault, mRoundedDefaultTop, mRoundedDefaultBottom);
+ updateRoundedCornerImageView();
+ mScreenDecorHwcWindow.getViewTreeObserver().addOnPreDrawListener(
+ new ValidatingPreDrawListener(mScreenDecorHwcWindow));
}
/**
@@ -523,12 +622,18 @@
decorProviders.forEach(provider -> {
removeOverlayView(provider.getViewId());
currentOverlay.addDecorProvider(provider, mRotation);
+ // If the hwc supports screen decoration and privacy dot is enabled, it means there will
+ // be only privacy dot in mOverlay. So set the initial visibility of mOverlays to
+ // INVISIBLE and will only set it to VISIBLE when the privacy dot is showing.
+ if (mHwcScreenDecorationSupport != null) {
+ currentOverlay.getRootView().setVisibility(View.INVISIBLE);
+ }
});
return currentOverlay;
}
private void updateView(@BoundsPosition int pos, @Nullable DisplayCutout cutout) {
- if (mOverlays == null || mOverlays[pos] == null) {
+ if (mOverlays == null || mOverlays[pos] == null || mHwcScreenDecorationSupport != null) {
return;
}
@@ -540,15 +645,34 @@
// update cutout view rotation
if (mCutoutViews != null && mCutoutViews[pos] != null) {
- mCutoutViews[pos].setRotation(mRotation);
+ mCutoutViews[pos].updateRotation(mRotation);
}
}
@VisibleForTesting
WindowManager.LayoutParams getWindowLayoutParams(@BoundsPosition int pos) {
+ final WindowManager.LayoutParams lp = getWindowLayoutBaseParams();
+ lp.width = getWidthLayoutParamByPos(pos);
+ lp.height = getHeightLayoutParamByPos(pos);
+ lp.setTitle(getWindowTitleByPos(pos));
+ lp.gravity = getOverlayWindowGravity(pos);
+ return lp;
+ }
+
+ private WindowManager.LayoutParams getHwcWindowLayoutParams() {
+ final WindowManager.LayoutParams lp = getWindowLayoutBaseParams();
+ lp.width = MATCH_PARENT;
+ lp.height = MATCH_PARENT;
+ lp.setTitle("ScreenDecorHwcOverlay");
+ lp.gravity = Gravity.TOP | Gravity.START;
+ if (!DEBUG_COLOR) {
+ lp.setColorMode(ActivityInfo.COLOR_MODE_A8);
+ }
+ return lp;
+ }
+
+ private WindowManager.LayoutParams getWindowLayoutBaseParams() {
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- getWidthLayoutParamByPos(pos),
- getHeightLayoutParamByPos(pos),
WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
@@ -566,8 +690,6 @@
lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
}
- lp.setTitle(getWindowTitleByPos(pos));
- lp.gravity = getOverlayWindowGravity(pos);
lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
lp.setFitInsetsTypes(0 /* types */);
lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
@@ -648,15 +770,19 @@
};
private void updateColorInversion(int colorsInvertedValue) {
- int tint = colorsInvertedValue != 0 ? Color.WHITE : Color.BLACK;
+ mTintColor = colorsInvertedValue != 0 ? Color.WHITE : Color.BLACK;
if (DEBUG_COLOR) {
- tint = Color.RED;
+ mTintColor = Color.RED;
}
- ColorStateList tintList = ColorStateList.valueOf(tint);
- if (mOverlays == null) {
+ // When the hwc supports screen decorations, the layer will use the A8 color mode which
+ // won't be affected by the color inversion. If the composition goes the client composition
+ // route, the color inversion will be handled by the RenderEngine.
+ if (mOverlays == null || mHwcScreenDecorationSupport != null) {
return;
}
+
+ ColorStateList tintList = ColorStateList.valueOf(mTintColor);
for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
if (mOverlays[i] == null) {
continue;
@@ -676,7 +802,7 @@
if (child instanceof ImageView) {
((ImageView) child).setImageTintList(tintList);
} else if (child instanceof DisplayCutoutView) {
- ((DisplayCutoutView) child).setColor(tint);
+ ((DisplayCutoutView) child).setColor(mTintColor);
}
}
}
@@ -688,6 +814,7 @@
Log.i(TAG, "ScreenDecorations is disabled");
return;
}
+
mExecutor.execute(() -> {
int oldRotation = mRotation;
mPendingRotationChange = false;
@@ -705,6 +832,14 @@
});
}
+ private static String alphaInterpretationToString(int alpha) {
+ switch (alpha) {
+ case AlphaInterpretation.COVERAGE: return "COVERAGE";
+ case AlphaInterpretation.MASK: return "MASK";
+ default: return "Unknown: " + alpha;
+ }
+ }
+
@Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
pw.println("ScreenDecorations state:");
@@ -712,6 +847,15 @@
pw.println(" mIsRoundedCornerMultipleRadius:" + mIsRoundedCornerMultipleRadius);
pw.println(" mIsPrivacyDotEnabled:" + isPrivacyDotEnabled());
pw.println(" mPendingRotationChange:" + mPendingRotationChange);
+ pw.println(" mHwcScreenDecorationSupport:");
+ if (mHwcScreenDecorationSupport == null) {
+ pw.println(" null");
+ } else {
+ pw.println(" format: "
+ + PixelFormat.formatToString(mHwcScreenDecorationSupport.format));
+ pw.println(" alphaInterpretation: "
+ + alphaInterpretationToString(mHwcScreenDecorationSupport.alphaInterpretation));
+ }
pw.println(" mRoundedDefault(x,y)=(" + mRoundedDefault.x + "," + mRoundedDefault.y + ")");
pw.println(" mRoundedDefaultTop(x,y)=(" + mRoundedDefaultTop.x + "," + mRoundedDefaultTop.y
+ ")");
@@ -739,7 +883,10 @@
}
if (newRotation != mRotation) {
mRotation = newRotation;
-
+ if (mScreenDecorHwcLayer != null) {
+ mScreenDecorHwcLayer.pendingRotationChange = false;
+ mScreenDecorHwcLayer.updateRotation(mRotation);
+ }
if (mOverlays != null) {
updateLayoutParams();
final DisplayCutout cutout = getCutout();
@@ -956,7 +1103,8 @@
private boolean shouldShowRoundedCorner(@BoundsPosition int pos,
@Nullable DisplayCutout cutout) {
- return hasRoundedCorners() && isDefaultShownOverlayPos(pos, cutout);
+ return hasRoundedCorners() && isDefaultShownOverlayPos(pos, cutout)
+ && mHwcScreenDecorationSupport == null;
}
private boolean shouldShowPrivacyDot(@BoundsPosition int pos, @Nullable DisplayCutout cutout) {
@@ -966,7 +1114,8 @@
private boolean shouldShowCutout(@BoundsPosition int pos, @Nullable DisplayCutout cutout) {
final Rect[] bounds = cutout == null ? null : cutout.getBoundingRectsAll();
final int rotatedPos = getBoundPositionFromRotation(pos, mRotation);
- return (bounds != null && !bounds[rotatedPos].isEmpty());
+ return (bounds != null && !bounds[rotatedPos].isEmpty()
+ && mHwcScreenDecorationSupport == null);
}
private boolean shouldDrawCutout() {
@@ -1027,14 +1176,22 @@
final Drawable bottom = mRoundedCornerDrawableBottom != null
? mRoundedCornerDrawableBottom : mRoundedCornerDrawable;
+ if (mScreenDecorHwcLayer != null) {
+ mScreenDecorHwcLayer.updateRoundedCornerDrawable(top, bottom);
+ return;
+ }
+
if (mOverlays == null) {
return;
}
+ final ColorStateList colorStateList = ColorStateList.valueOf(mTintColor);
for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
if (mOverlays[i] == null) {
continue;
}
final ViewGroup overlayView = mOverlays[i].getRootView();
+ ((ImageView) overlayView.findViewById(R.id.left)).setImageTintList(colorStateList);
+ ((ImageView) overlayView.findViewById(R.id.right)).setImageTintList(colorStateList);
((ImageView) overlayView.findViewById(R.id.left)).setImageDrawable(
isTopRoundedCorner(i, R.id.left) ? top : bottom);
((ImageView) overlayView.findViewById(R.id.right)).setImageDrawable(
@@ -1065,9 +1222,6 @@
Point sizeDefault,
Point sizeTop,
Point sizeBottom) {
- if (mOverlays == null) {
- return;
- }
if (sizeTop.x == 0) {
sizeTop = sizeDefault;
}
@@ -1075,6 +1229,14 @@
sizeBottom = sizeDefault;
}
+ if (mScreenDecorHwcLayer != null) {
+ mScreenDecorHwcLayer.updateRoundedCornerSize(sizeTop.x, sizeBottom.x);
+ return;
+ }
+
+ if (mOverlays == null) {
+ return;
+ }
for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
if (mOverlays[i] == null) {
continue;
@@ -1095,40 +1257,21 @@
view.setLayoutParams(params);
}
- public static class DisplayCutoutView extends View implements DisplayManager.DisplayListener,
- RegionInterceptableView {
-
- private static final float HIDDEN_CAMERA_PROTECTION_SCALE = 0.5f;
-
- private Display.Mode mDisplayMode = null;
- private final DisplayInfo mInfo = new DisplayInfo();
- private final Paint mPaint = new Paint();
+ public static class DisplayCutoutView extends DisplayCutoutBaseView {
private final List<Rect> mBounds = new ArrayList();
private final Rect mBoundingRect = new Rect();
- private final Path mBoundingPath = new Path();
- // Don't initialize these yet because they may never exist
- private RectF mProtectionRect;
- private RectF mProtectionRectOrig;
- private Path mProtectionPath;
- private Path mProtectionPathOrig;
private Rect mTotalBounds = new Rect();
- // Whether or not to show the cutout protection path
- private boolean mShowProtection = false;
- private final int[] mLocation = new int[2];
- private final ScreenDecorations mDecorations;
private int mColor = Color.BLACK;
private int mRotation;
private int mInitialPosition;
private int mPosition;
- private float mCameraProtectionProgress = HIDDEN_CAMERA_PROTECTION_SCALE;
- private ValueAnimator mCameraProtectionAnimator;
- public DisplayCutoutView(Context context, @BoundsPosition int pos,
- ScreenDecorations decorations) {
+ public DisplayCutoutView(Context context, @BoundsPosition int pos) {
super(context);
mInitialPosition = pos;
- mDecorations = decorations;
+ paint.setColor(mColor);
+ paint.setStyle(Paint.Style.FILL);
setId(R.id.display_cutout);
if (DEBUG) {
getViewTreeObserver().addOnDrawListener(() -> Log.i(TAG,
@@ -1138,145 +1281,31 @@
public void setColor(int color) {
mColor = color;
+ paint.setColor(mColor);
invalidate();
}
@Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- mContext.getSystemService(DisplayManager.class).registerDisplayListener(this,
- getHandler());
- update();
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- mContext.getSystemService(DisplayManager.class).unregisterDisplayListener(this);
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- getLocationOnScreen(mLocation);
- canvas.translate(-mLocation[0], -mLocation[1]);
-
- if (!mBoundingPath.isEmpty()) {
- mPaint.setColor(mColor);
- mPaint.setStyle(Paint.Style.FILL);
- mPaint.setAntiAlias(true);
- canvas.drawPath(mBoundingPath, mPaint);
- }
- if (mCameraProtectionProgress > HIDDEN_CAMERA_PROTECTION_SCALE
- && !mProtectionRect.isEmpty()) {
- canvas.scale(mCameraProtectionProgress, mCameraProtectionProgress,
- mProtectionRect.centerX(), mProtectionRect.centerY());
- canvas.drawPath(mProtectionPath, mPaint);
- }
- }
-
- @Override
- public void onDisplayAdded(int displayId) {
- }
-
- @Override
- public void onDisplayRemoved(int displayId) {
- }
-
- @Override
- public void onDisplayChanged(int displayId) {
- Display.Mode oldMode = mDisplayMode;
- mDisplayMode = getDisplay().getMode();
-
- // Display mode hasn't meaningfully changed, we can ignore it
- if (!modeChanged(oldMode, mDisplayMode)) {
- return;
- }
-
- if (displayId == getDisplay().getDisplayId()) {
- update();
- }
- }
-
- private boolean modeChanged(Display.Mode oldMode, Display.Mode newMode) {
- if (oldMode == null) {
- return true;
- }
-
- boolean changed = false;
- changed |= oldMode.getPhysicalHeight() != newMode.getPhysicalHeight();
- changed |= oldMode.getPhysicalWidth() != newMode.getPhysicalWidth();
- // We purposely ignore refresh rate and id changes here, because we don't need to
- // invalidate for those, and they can trigger the refresh rate to increase
-
- return changed;
- }
-
- public void setRotation(int rotation) {
+ public void updateRotation(int rotation) {
mRotation = rotation;
- update();
+ updateCutout();
}
- void setProtection(Path protectionPath, Rect pathBounds) {
- if (mProtectionPathOrig == null) {
- mProtectionPathOrig = new Path();
- mProtectionPath = new Path();
- }
- mProtectionPathOrig.set(protectionPath);
- if (mProtectionRectOrig == null) {
- mProtectionRectOrig = new RectF();
- mProtectionRect = new RectF();
- }
- mProtectionRectOrig.set(pathBounds);
- }
-
- void setShowProtection(boolean shouldShow) {
- if (mShowProtection == shouldShow) {
- return;
- }
-
- mShowProtection = shouldShow;
- updateBoundingPath();
- // Delay the relayout until the end of the animation when hiding the cutout,
- // otherwise we'd clip it.
- if (mShowProtection) {
- requestLayout();
- }
- if (mCameraProtectionAnimator != null) {
- mCameraProtectionAnimator.cancel();
- }
- mCameraProtectionAnimator = ValueAnimator.ofFloat(mCameraProtectionProgress,
- mShowProtection ? 1.0f : HIDDEN_CAMERA_PROTECTION_SCALE).setDuration(750);
- mCameraProtectionAnimator.setInterpolator(Interpolators.DECELERATE_QUINT);
- mCameraProtectionAnimator.addUpdateListener(animation -> {
- mCameraProtectionProgress = (float) animation.getAnimatedValue();
- invalidate();
- });
- mCameraProtectionAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mCameraProtectionAnimator = null;
- if (!mShowProtection) {
- requestLayout();
- }
- }
- });
- mCameraProtectionAnimator.start();
- }
-
- private void update() {
- if (!isAttachedToWindow() || mDecorations.mPendingRotationChange) {
+ @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
+ @Override
+ public void updateCutout() {
+ if (!isAttachedToWindow() || pendingRotationChange) {
return;
}
mPosition = getBoundPositionFromRotation(mInitialPosition, mRotation);
requestLayout();
- getDisplay().getDisplayInfo(mInfo);
+ getDisplay().getDisplayInfo(displayInfo);
mBounds.clear();
mBoundingRect.setEmpty();
- mBoundingPath.reset();
+ cutoutPath.reset();
int newVisible;
if (shouldDrawCutout(getContext()) && hasCutout()) {
- mBounds.addAll(mInfo.displayCutout.getBoundingRects());
+ mBounds.addAll(displayInfo.displayCutout.getBoundingRects());
localBounds(mBoundingRect);
updateGravity();
updateBoundingPath();
@@ -1291,10 +1320,11 @@
}
private void updateBoundingPath() {
- int lw = mInfo.logicalWidth;
- int lh = mInfo.logicalHeight;
+ int lw = displayInfo.logicalWidth;
+ int lh = displayInfo.logicalHeight;
- boolean flipped = mInfo.rotation == ROTATION_90 || mInfo.rotation == ROTATION_270;
+ boolean flipped = displayInfo.rotation == ROTATION_90
+ || displayInfo.rotation == ROTATION_270;
int dw = flipped ? lh : lw;
int dh = flipped ? lw : lh;
@@ -1302,49 +1332,20 @@
Path path = DisplayCutout.pathFromResources(
getResources(), getDisplay().getUniqueId(), dw, dh);
if (path != null) {
- mBoundingPath.set(path);
+ cutoutPath.set(path);
} else {
- mBoundingPath.reset();
+ cutoutPath.reset();
}
Matrix m = new Matrix();
- transformPhysicalToLogicalCoordinates(mInfo.rotation, dw, dh, m);
- mBoundingPath.transform(m);
- if (mProtectionPathOrig != null) {
- // Reset the protection path so we don't aggregate rotations
- mProtectionPath.set(mProtectionPathOrig);
- mProtectionPath.transform(m);
- m.mapRect(mProtectionRect, mProtectionRectOrig);
- }
- }
-
- private static void transformPhysicalToLogicalCoordinates(@Surface.Rotation int rotation,
- @Dimension int physicalWidth, @Dimension int physicalHeight, Matrix out) {
- switch (rotation) {
- case ROTATION_0:
- out.reset();
- break;
- case ROTATION_90:
- out.setRotate(270);
- out.postTranslate(0, physicalWidth);
- break;
- case ROTATION_180:
- out.setRotate(180);
- out.postTranslate(physicalWidth, physicalHeight);
- break;
- case ROTATION_270:
- out.setRotate(90);
- out.postTranslate(physicalHeight, 0);
- break;
- default:
- throw new IllegalArgumentException("Unknown rotation: " + rotation);
- }
+ transformPhysicalToLogicalCoordinates(displayInfo.rotation, dw, dh, m);
+ cutoutPath.transform(m);
}
private void updateGravity() {
LayoutParams lp = getLayoutParams();
if (lp instanceof FrameLayout.LayoutParams) {
FrameLayout.LayoutParams flp = (FrameLayout.LayoutParams) lp;
- int newGravity = getGravity(mInfo.displayCutout);
+ int newGravity = getGravity(displayInfo.displayCutout);
if (flp.gravity != newGravity) {
flp.gravity = newGravity;
setLayoutParams(flp);
@@ -1353,7 +1354,7 @@
}
private boolean hasCutout() {
- final DisplayCutout displayCutout = mInfo.displayCutout;
+ final DisplayCutout displayCutout = displayInfo.displayCutout;
if (displayCutout == null) {
return false;
}
@@ -1377,11 +1378,11 @@
return;
}
- if (mShowProtection) {
+ if (showProtection) {
// Make sure that our measured height encompases the protection
mTotalBounds.union(mBoundingRect);
- mTotalBounds.union((int) mProtectionRect.left, (int) mProtectionRect.top,
- (int) mProtectionRect.right, (int) mProtectionRect.bottom);
+ mTotalBounds.union((int) protectionRect.left, (int) protectionRect.top,
+ (int) protectionRect.right, (int) protectionRect.bottom);
setMeasuredDimension(
resolveSizeAndState(mTotalBounds.width(), widthMeasureSpec, 0),
resolveSizeAndState(mTotalBounds.height(), heightMeasureSpec, 0));
@@ -1413,7 +1414,7 @@
}
private void localBounds(Rect out) {
- DisplayCutout displayCutout = mInfo.displayCutout;
+ DisplayCutout displayCutout = displayInfo.displayCutout;
boundsFromDirection(displayCutout, getGravity(displayCutout), out);
}
@@ -1437,32 +1438,6 @@
}
return Gravity.NO_GRAVITY;
}
-
- @Override
- public boolean shouldInterceptTouch() {
- return mInfo.displayCutout != null && getVisibility() == VISIBLE;
- }
-
- @Override
- public Region getInterceptRegion() {
- if (mInfo.displayCutout == null) {
- return null;
- }
-
- View rootView = getRootView();
- Region cutoutBounds = rectsToRegion(
- mInfo.displayCutout.getBoundingRects());
-
- // Transform to window's coordinate space
- rootView.getLocationOnScreen(mLocation);
- cutoutBounds.translate(-mLocation[0], -mLocation[1]);
-
- // Intersect with window's frame
- cutoutBounds.op(rootView.getLeft(), rootView.getTop(), rootView.getRight(),
- rootView.getBottom(), Region.Op.INTERSECT);
-
- return cutoutBounds;
- }
}
/**
@@ -1473,6 +1448,8 @@
private final View mView;
private final int mTargetRotation;
+ // Pass -1 for ScreenDecorHwcLayer since it's a fullscreen window and has no specific
+ // position.
private final int mPosition;
private RestartingPreDrawListener(View view, @BoundsPosition int position,
@@ -1488,7 +1465,9 @@
if (mTargetRotation == mRotation) {
if (DEBUG) {
- Log.i(TAG, getWindowTitleByPos(mPosition) + " already in target rot "
+ final String title = mPosition < 0 ? "ScreenDecorHwcLayer"
+ : getWindowTitleByPos(mPosition);
+ Log.i(TAG, title + " already in target rot "
+ mTargetRotation + ", allow draw without restarting it");
}
return true;
@@ -1499,7 +1478,9 @@
// take effect.
updateOrientation();
if (DEBUG) {
- Log.i(TAG, getWindowTitleByPos(mPosition)
+ final String title = mPosition < 0 ? "ScreenDecorHwcLayer"
+ : getWindowTitleByPos(mPosition);
+ Log.i(TAG, title
+ " restarting listener fired, restarting draw for rot " + mRotation);
}
mView.invalidate();
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index daca918..23ca923 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -49,8 +49,11 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
-import java.util.Collections;
+import java.util.Comparator;
+import java.util.Map;
+import java.util.TreeMap;
+
+import javax.inject.Provider;
/**
* Application class for SystemUI.
@@ -181,17 +184,16 @@
*/
public void startServicesIfNeeded() {
- final String[] names = SystemUIFactory.getInstance()
- .getSystemUIServiceComponents(getResources());
- final String[] additionalNames = SystemUIFactory.getInstance()
- .getAdditionalSystemUIServiceComponents(getResources());
+ final String vendorComponent = SystemUIFactory.getInstance()
+ .getVendorComponent(getResources());
- final ArrayList<String> serviceComponents = new ArrayList<>();
- Collections.addAll(serviceComponents, names);
- Collections.addAll(serviceComponents, additionalNames);
-
- startServicesIfNeeded(/* metricsPrefix= */ "StartServices",
- serviceComponents.toArray(new String[serviceComponents.size()]));
+ // Sort the startables so that we get a deterministic ordering.
+ // TODO: make #start idempotent and require users of CoreStartable to call it.
+ Map<Class<?>, Provider<CoreStartable>> sortedStartables = new TreeMap<>(
+ Comparator.comparing(Class::getName));
+ sortedStartables.putAll(SystemUIFactory.getInstance().getStartableComponents());
+ startServicesIfNeeded(
+ sortedStartables, "StartServices", vendorComponent);
}
/**
@@ -201,16 +203,22 @@
* <p>This method must only be called from the main thread.</p>
*/
void startSecondaryUserServicesIfNeeded() {
- String[] names = SystemUIFactory.getInstance().getSystemUIServiceComponentsPerUser(
- getResources());
- startServicesIfNeeded(/* metricsPrefix= */ "StartSecondaryServices", names);
+ // Sort the startables so that we get a deterministic ordering.
+ Map<Class<?>, Provider<CoreStartable>> sortedStartables = new TreeMap<>(
+ Comparator.comparing(Class::getName));
+ sortedStartables.putAll(SystemUIFactory.getInstance().getStartableComponentsPerUser());
+ startServicesIfNeeded(
+ sortedStartables, "StartSecondaryServices", null);
}
- private void startServicesIfNeeded(String metricsPrefix, String[] services) {
+ private void startServicesIfNeeded(
+ Map<Class<?>, Provider<CoreStartable>> startables,
+ String metricsPrefix,
+ String vendorComponent) {
if (mServicesStarted) {
return;
}
- mServices = new CoreStartable[services.length];
+ mServices = new CoreStartable[startables.size() + (vendorComponent == null ? 0 : 1)];
if (!mBootCompleteCache.isBootComplete()) {
// check to see if maybe it was already completed long before we began
@@ -230,36 +238,29 @@
TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
Trace.TRACE_TAG_APP);
log.traceBegin(metricsPrefix);
- final int N = services.length;
- for (int i = 0; i < N; i++) {
- String clsName = services[i];
- if (DEBUG) Log.d(TAG, "loading: " + clsName);
- log.traceBegin(metricsPrefix + clsName);
- long ti = System.currentTimeMillis();
- try {
- CoreStartable obj = mComponentHelper.resolveCoreStartable(clsName);
- if (obj == null) {
- Constructor constructor = Class.forName(clsName).getConstructor(Context.class);
- obj = (CoreStartable) constructor.newInstance(this);
- }
- mServices[i] = obj;
- } catch (ClassNotFoundException
- | NoSuchMethodException
- | IllegalAccessException
- | InstantiationException
- | InvocationTargetException ex) {
- throw new RuntimeException(ex);
- }
- if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
- mServices[i].start();
- log.traceEnd();
+ int i = 0;
+ for (Map.Entry<Class<?>, Provider<CoreStartable>> entry : startables.entrySet()) {
+ String clsName = entry.getKey().getName();
+ int j = i; // Copied to make lambda happy.
+ timeInitialization(
+ clsName,
+ () -> mServices[j] = startStartable(clsName, entry.getValue()),
+ log,
+ metricsPrefix);
+ i++;
+ }
- // Warn if initialization of component takes too long
- ti = System.currentTimeMillis() - ti;
- if (ti > 1000) {
- Log.w(TAG, "Initialization of " + clsName + " took " + ti + " ms");
- }
+ if (vendorComponent != null) {
+ timeInitialization(
+ vendorComponent,
+ () -> mServices[mServices.length - 1] =
+ startAdditionalStartable(vendorComponent),
+ log,
+ metricsPrefix);
+ }
+
+ for (i = 0; i < mServices.length; i++) {
if (mBootCompleteCache.isBootComplete()) {
mServices[i].onBootCompleted();
}
@@ -272,7 +273,51 @@
mServicesStarted = true;
}
- // TODO(b/149254050): add unit tests? There doesn't seem to be a SystemUiApplicationTest...
+ private void timeInitialization(String clsName, Runnable init, TimingsTraceLog log,
+ String metricsPrefix) {
+ long ti = System.currentTimeMillis();
+ log.traceBegin(metricsPrefix + " " + clsName);
+ init.run();
+ log.traceEnd();
+
+ // Warn if initialization of component takes too long
+ ti = System.currentTimeMillis() - ti;
+ if (ti > 1000) {
+ Log.w(TAG, "Initialization of " + clsName + " took " + ti + " ms");
+ }
+ }
+
+ private CoreStartable startAdditionalStartable(String clsName) {
+ CoreStartable startable;
+ if (DEBUG) Log.d(TAG, "loading: " + clsName);
+ try {
+ Constructor<?> constructor = Class.forName(clsName).getConstructor(
+ Context.class);
+ startable = (CoreStartable) constructor.newInstance(this);
+ } catch (ClassNotFoundException
+ | NoSuchMethodException
+ | IllegalAccessException
+ | InstantiationException
+ | InvocationTargetException ex) {
+ throw new RuntimeException(ex);
+ }
+
+ return startStartable(startable);
+ }
+
+ private CoreStartable startStartable(String clsName, Provider<CoreStartable> provider) {
+ if (DEBUG) Log.d(TAG, "loading: " + clsName);
+ return startStartable(provider.get());
+ }
+
+ private CoreStartable startStartable(CoreStartable startable) {
+ if (DEBUG) Log.d(TAG, "running: " + startable);
+ startable.start();
+
+ return startable;
+ }
+
+ // TODO(b/217567642): add unit tests? There doesn't seem to be a SystemUiApplicationTest...
@Override
public boolean addDumpable(Dumpable dumpable) {
String name = dumpable.getDumpableName();
@@ -288,13 +333,21 @@
if (DEBUG) Log.d(TAG, "addDumpable(): adding '" + name + "' = " + dumpable);
mDumpables.put(name, dumpable);
- // TODO(b/149254050): replace com.android.systemui.dump.Dumpable by
+ // TODO(b/217567642): replace com.android.systemui.dump.Dumpable by
// com.android.util.Dumpable and get rid of the intermediate lambda
mDumpManager.registerDumpable(dumpable.getDumpableName(),
(fd, pw, args) -> dumpable.dump(pw, args));
return true;
}
+ // TODO(b/217567642): implement
+ @Override
+ public boolean removeDumpable(Dumpable dumpable) {
+ Log.w(TAG, "removeDumpable(" + dumpable + "): not implemented");
+
+ return false;
+ }
+
@Override
public void onConfigurationChanged(Configuration newConfig) {
if (mServicesStarted) {
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index b3be877..11fffd0 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -32,10 +32,13 @@
import com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider;
import com.android.wm.shell.transition.ShellTransitions;
+import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
+import javax.inject.Provider;
+
/**
* Class factory to provide customizable SystemUI components.
*/
@@ -190,24 +193,24 @@
}
/**
- * Returns the list of system UI components that should be started.
+ * Returns the list of {@link CoreStartable} components that should be started at startup.
*/
- public String[] getSystemUIServiceComponents(Resources resources) {
- return resources.getStringArray(R.array.config_systemUIServiceComponents);
+ public Map<Class<?>, Provider<CoreStartable>> getStartableComponents() {
+ return mSysUIComponent.getStartables();
}
/**
* Returns the list of additional system UI components that should be started.
*/
- public String[] getAdditionalSystemUIServiceComponents(Resources resources) {
- return resources.getStringArray(R.array.config_additionalSystemUIServiceComponents);
+ public String getVendorComponent(Resources resources) {
+ return resources.getString(R.string.config_systemUIVendorServiceComponent);
}
/**
- * Returns the list of system UI components that should be started per user.
+ * Returns the list of {@link CoreStartable} components that should be started per user.
*/
- public String[] getSystemUIServiceComponentsPerUser(Resources resources) {
- return resources.getStringArray(R.array.config_systemUIServiceComponentsPerUser);
+ public Map<Class<?>, Provider<CoreStartable>> getStartableComponentsPerUser() {
+ return mSysUIComponent.getPerUserStartables();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
index f8e7697..2b0c083 100644
--- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
@@ -56,6 +56,7 @@
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.text.NumberFormat;
+import java.util.ArrayList;
public class BatteryMeterView extends LinearLayout implements DarkReceiver {
@@ -125,7 +126,7 @@
updateShowPercent();
mDualToneHandler = new DualToneHandler(context);
// Init to not dark at all.
- onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
+ onDarkChanged(new ArrayList<Rect>(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
setClipChildren(false);
setClipToPadding(false);
@@ -353,8 +354,8 @@
}
@Override
- public void onDarkChanged(Rect area, float darkIntensity, int tint) {
- float intensity = DarkIconDispatcher.isInArea(area, this) ? darkIntensity : 0;
+ public void onDarkChanged(ArrayList<Rect> areas, float darkIntensity, int tint) {
+ float intensity = DarkIconDispatcher.isInAreas(areas, this) ? darkIntensity : 0;
mNonAdaptedSingleToneColor = mDualToneHandler.getSingleColor(intensity);
mNonAdaptedForegroundColor = mDualToneHandler.getFillColor(intensity);
mNonAdaptedBackgroundColor = mDualToneHandler.getBackgroundColor(intensity);
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
index 236c43b..40689ee 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
@@ -262,7 +262,8 @@
resetActionChips();
for (RemoteAction action : actions) {
Intent targetIntent = action.getActionIntent().getIntent();
- if (!TextUtils.equals(source, targetIntent.getComponent().getPackageName())) {
+ ComponentName component = targetIntent.getComponent();
+ if (component != null && !TextUtils.equals(source, component.getPackageName())) {
OverlayActionChip chip = constructActionChip(action);
mActionContainer.addView(chip);
mActionChips.add(chip);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ContextComponentHelper.java b/packages/SystemUI/src/com/android/systemui/dagger/ContextComponentHelper.java
index f53221c..e868d43 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ContextComponentHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ContextComponentHelper.java
@@ -20,7 +20,6 @@
import android.app.Service;
import android.content.BroadcastReceiver;
-import com.android.systemui.CoreStartable;
import com.android.systemui.recents.RecentsImplementation;
/**
@@ -37,8 +36,5 @@
Service resolveService(String className);
/** Turns a classname into an instance of the class or returns null. */
- CoreStartable resolveCoreStartable(String className);
-
- /** Turns a classname into an instance of the class or returns null. */
BroadcastReceiver resolveBroadcastReceiver(String className);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ContextComponentResolver.java b/packages/SystemUI/src/com/android/systemui/dagger/ContextComponentResolver.java
index fba8d35..3607e25 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ContextComponentResolver.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ContextComponentResolver.java
@@ -20,7 +20,6 @@
import android.app.Service;
import android.content.BroadcastReceiver;
-import com.android.systemui.CoreStartable;
import com.android.systemui.recents.RecentsImplementation;
import java.util.Map;
@@ -35,19 +34,16 @@
public class ContextComponentResolver implements ContextComponentHelper {
private final Map<Class<?>, Provider<Activity>> mActivityCreators;
private final Map<Class<?>, Provider<Service>> mServiceCreators;
- private final Map<Class<?>, Provider<CoreStartable>> mSystemUICreators;
private final Map<Class<?>, Provider<RecentsImplementation>> mRecentsCreators;
private final Map<Class<?>, Provider<BroadcastReceiver>> mBroadcastReceiverCreators;
@Inject
ContextComponentResolver(Map<Class<?>, Provider<Activity>> activityCreators,
Map<Class<?>, Provider<Service>> serviceCreators,
- Map<Class<?>, Provider<CoreStartable>> systemUICreators,
Map<Class<?>, Provider<RecentsImplementation>> recentsCreators,
Map<Class<?>, Provider<BroadcastReceiver>> broadcastReceiverCreators) {
mActivityCreators = activityCreators;
mServiceCreators = serviceCreators;
- mSystemUICreators = systemUICreators;
mRecentsCreators = recentsCreators;
mBroadcastReceiverCreators = broadcastReceiverCreators;
}
@@ -84,14 +80,6 @@
return resolve(className, mServiceCreators);
}
- /**
- * Looks up the SystemUI class name to see if Dagger has an instance of it.
- */
- @Override
- public CoreStartable resolveCoreStartable(String className) {
- return resolve(className, mSystemUICreators);
- }
-
private <T> T resolve(String className, Map<Class<?>, Provider<T>> creators) {
try {
Class<?> clazz = Class.forName(className);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
index 33f07c7..e1cbdcd 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
@@ -25,6 +25,7 @@
import com.android.systemui.dump.SystemUIAuxiliaryDumpService;
import com.android.systemui.keyguard.KeyguardService;
import com.android.systemui.screenrecord.RecordingService;
+import com.android.systemui.statusbar.phone.NotificationListenerWithPlugins;
import dagger.Binds;
import dagger.Module;
@@ -63,6 +64,13 @@
/** */
@Binds
@IntoMap
+ @ClassKey(NotificationListenerWithPlugins.class)
+ public abstract Service bindNotificationListenerWithPlugins(
+ NotificationListenerWithPlugins service);
+
+ /** */
+ @Binds
+ @IntoMap
@ClassKey(SystemUIService.class)
public abstract Service bindSystemUIService(SystemUIService service);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index bda8e3c..81fa99a 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -18,11 +18,14 @@
import com.android.keyguard.clock.ClockOptionsProvider;
import com.android.systemui.BootCompleteCacheImpl;
+import com.android.systemui.CoreStartable;
import com.android.systemui.Dependency;
import com.android.systemui.InitController;
import com.android.systemui.SystemUIAppComponentFactory;
+import com.android.systemui.dagger.qualifiers.PerUser;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardSliceProvider;
+import com.android.systemui.media.muteawait.MediaMuteAwaitConnectionCli;
import com.android.systemui.media.taptotransfer.MediaTttCommandLineHelper;
import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver;
import com.android.systemui.media.taptotransfer.sender.MediaTttChipControllerSender;
@@ -51,8 +54,11 @@
import com.android.wm.shell.tasksurfacehelper.TaskSurfaceHelper;
import com.android.wm.shell.transition.ShellTransitions;
+import java.util.Map;
import java.util.Optional;
+import javax.inject.Provider;
+
import dagger.BindsInstance;
import dagger.Subcomponent;
@@ -65,6 +71,7 @@
DependencyProvider.class,
SystemUIBinder.class,
SystemUIModule.class,
+ SystemUICoreStartableModule.class,
SystemUIDefaultModule.class})
public interface SysUIComponent {
@@ -144,6 +151,7 @@
getMediaTttChipControllerSender();
getMediaTttChipControllerReceiver();
getMediaTttCommandLineHelper();
+ getMediaMuteAwaitConnectionCli();
getUnfoldLatencyTracker().init();
getFoldStateLoggingProvider().ifPresent(FoldStateLoggingProvider::init);
getFoldStateLogger().ifPresent(FoldStateLogger::init);
@@ -220,6 +228,19 @@
/** */
Optional<MediaTttCommandLineHelper> getMediaTttCommandLineHelper();
+ /** */
+ Optional<MediaMuteAwaitConnectionCli> getMediaMuteAwaitConnectionCli();
+
+ /**
+ * Returns {@link CoreStartable}s that should be started with the application.
+ */
+ Map<Class<?>, Provider<CoreStartable>> getStartables();
+
+ /**
+ * Returns {@link CoreStartable}s that should be started for every user.
+ */
+ @PerUser Map<Class<?>, Provider<CoreStartable>> getPerUserStartables();
+
/**
* Member injection into the supplied argument.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
index ec2beb1..b32f878 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
@@ -16,46 +16,11 @@
package com.android.systemui.dagger;
-import com.android.keyguard.KeyguardBiometricLockoutLogger;
-import com.android.systemui.CoreStartable;
-import com.android.systemui.LatencyTester;
-import com.android.systemui.ScreenDecorations;
-import com.android.systemui.SliceBroadcastRelayHandler;
-import com.android.systemui.accessibility.SystemActions;
-import com.android.systemui.accessibility.WindowMagnification;
-import com.android.systemui.biometrics.AuthController;
-import com.android.systemui.clipboardoverlay.ClipboardListener;
-import com.android.systemui.dreams.DreamOverlayRegistrant;
-import com.android.systemui.dreams.SmartSpaceComplication;
-import com.android.systemui.dreams.complication.DreamClockDateComplication;
-import com.android.systemui.dreams.complication.DreamClockTimeComplication;
-import com.android.systemui.dreams.complication.DreamWeatherComplication;
-import com.android.systemui.globalactions.GlobalActionsComponent;
-import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.dagger.KeyguardModule;
-import com.android.systemui.log.SessionTracker;
-import com.android.systemui.media.dream.MediaDreamSentinel;
-import com.android.systemui.media.systemsounds.HomeSoundEffectController;
-import com.android.systemui.power.PowerUI;
-import com.android.systemui.privacy.television.TvOngoingPrivacyChip;
-import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsModule;
-import com.android.systemui.shortcut.ShortcutKeyDispatcher;
import com.android.systemui.statusbar.dagger.StatusBarModule;
-import com.android.systemui.statusbar.notification.InstantAppNotifier;
-import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.tv.TvStatusBar;
-import com.android.systemui.statusbar.tv.notifications.TvNotificationPanel;
-import com.android.systemui.theme.ThemeOverlayController;
-import com.android.systemui.toast.ToastUI;
-import com.android.systemui.util.leak.GarbageMonitor;
-import com.android.systemui.volume.VolumeUI;
-import com.android.systemui.wmshell.WMShell;
-import dagger.Binds;
import dagger.Module;
-import dagger.multibindings.ClassKey;
-import dagger.multibindings.IntoMap;
/**
* SystemUI objects that are injectable should go here.
@@ -66,196 +31,4 @@
KeyguardModule.class,
})
public abstract class SystemUIBinder {
- /** Inject into AuthController. */
- @Binds
- @IntoMap
- @ClassKey(AuthController.class)
- public abstract CoreStartable bindAuthController(AuthController service);
-
- /** Inject into SessionTracker. */
- @Binds
- @IntoMap
- @ClassKey(SessionTracker.class)
- public abstract CoreStartable bindSessionTracker(SessionTracker service);
-
- /** Inject into GarbageMonitor.Service. */
- @Binds
- @IntoMap
- @ClassKey(GarbageMonitor.Service.class)
- public abstract CoreStartable bindGarbageMonitorService(GarbageMonitor.Service sysui);
-
- /** Inject into ClipboardListener. */
- @Binds
- @IntoMap
- @ClassKey(ClipboardListener.class)
- public abstract CoreStartable bindClipboardListener(ClipboardListener sysui);
-
- /** Inject into GlobalActionsComponent. */
- @Binds
- @IntoMap
- @ClassKey(GlobalActionsComponent.class)
- public abstract CoreStartable bindGlobalActionsComponent(GlobalActionsComponent sysui);
-
- /** Inject into InstantAppNotifier. */
- @Binds
- @IntoMap
- @ClassKey(InstantAppNotifier.class)
- public abstract CoreStartable bindInstantAppNotifier(InstantAppNotifier sysui);
-
- /** Inject into KeyguardViewMediator. */
- @Binds
- @IntoMap
- @ClassKey(KeyguardViewMediator.class)
- public abstract CoreStartable bindKeyguardViewMediator(KeyguardViewMediator sysui);
-
- /** Inject into KeyguardBiometricLockoutLogger. */
- @Binds
- @IntoMap
- @ClassKey(KeyguardBiometricLockoutLogger.class)
- public abstract CoreStartable bindKeyguardBiometricLockoutLogger(
- KeyguardBiometricLockoutLogger sysui);
-
- /** Inject into LatencyTests. */
- @Binds
- @IntoMap
- @ClassKey(LatencyTester.class)
- public abstract CoreStartable bindLatencyTester(LatencyTester sysui);
-
- /** Inject into PowerUI. */
- @Binds
- @IntoMap
- @ClassKey(PowerUI.class)
- public abstract CoreStartable bindPowerUI(PowerUI sysui);
-
- /** Inject into Recents. */
- @Binds
- @IntoMap
- @ClassKey(Recents.class)
- public abstract CoreStartable bindRecents(Recents sysui);
-
- /** Inject into ScreenDecorations. */
- @Binds
- @IntoMap
- @ClassKey(ScreenDecorations.class)
- public abstract CoreStartable bindScreenDecorations(ScreenDecorations sysui);
-
- /** Inject into ShortcutKeyDispatcher. */
- @Binds
- @IntoMap
- @ClassKey(ShortcutKeyDispatcher.class)
- public abstract CoreStartable bindsShortcutKeyDispatcher(ShortcutKeyDispatcher sysui);
-
- /** Inject into SliceBroadcastRelayHandler. */
- @Binds
- @IntoMap
- @ClassKey(SliceBroadcastRelayHandler.class)
- public abstract CoreStartable bindSliceBroadcastRelayHandler(SliceBroadcastRelayHandler sysui);
-
- /** Inject into StatusBar. */
- @Binds
- @IntoMap
- @ClassKey(StatusBar.class)
- public abstract CoreStartable bindsStatusBar(StatusBar sysui);
-
- /** Inject into SystemActions. */
- @Binds
- @IntoMap
- @ClassKey(SystemActions.class)
- public abstract CoreStartable bindSystemActions(SystemActions sysui);
-
- /** Inject into ThemeOverlayController. */
- @Binds
- @IntoMap
- @ClassKey(ThemeOverlayController.class)
- public abstract CoreStartable bindThemeOverlayController(ThemeOverlayController sysui);
-
- /** Inject into ToastUI. */
- @Binds
- @IntoMap
- @ClassKey(ToastUI.class)
- public abstract CoreStartable bindToastUI(ToastUI service);
-
- /** Inject into TvStatusBar. */
- @Binds
- @IntoMap
- @ClassKey(TvStatusBar.class)
- public abstract CoreStartable bindsTvStatusBar(TvStatusBar sysui);
-
- /** Inject into TvNotificationPanel. */
- @Binds
- @IntoMap
- @ClassKey(TvNotificationPanel.class)
- public abstract CoreStartable bindsTvNotificationPanel(TvNotificationPanel sysui);
-
- /** Inject into TvOngoingPrivacyChip. */
- @Binds
- @IntoMap
- @ClassKey(TvOngoingPrivacyChip.class)
- public abstract CoreStartable bindsTvOngoingPrivacyChip(TvOngoingPrivacyChip sysui);
-
- /** Inject into VolumeUI. */
- @Binds
- @IntoMap
- @ClassKey(VolumeUI.class)
- public abstract CoreStartable bindVolumeUI(VolumeUI sysui);
-
- /** Inject into WindowMagnification. */
- @Binds
- @IntoMap
- @ClassKey(WindowMagnification.class)
- public abstract CoreStartable bindWindowMagnification(WindowMagnification sysui);
-
- /** Inject into WMShell. */
- @Binds
- @IntoMap
- @ClassKey(WMShell.class)
- public abstract CoreStartable bindWMShell(WMShell sysui);
-
- /** Inject into HomeSoundEffectController. */
- @Binds
- @IntoMap
- @ClassKey(HomeSoundEffectController.class)
- public abstract CoreStartable bindHomeSoundEffectController(HomeSoundEffectController sysui);
-
- /** Inject into DreamOverlay. */
- @Binds
- @IntoMap
- @ClassKey(DreamOverlayRegistrant.class)
- public abstract CoreStartable bindDreamOverlayRegistrant(
- DreamOverlayRegistrant dreamOverlayRegistrant);
-
- /** Inject into SmartSpaceComplication.Registrant */
- @Binds
- @IntoMap
- @ClassKey(SmartSpaceComplication.Registrant.class)
- public abstract CoreStartable bindSmartSpaceComplicationRegistrant(
- SmartSpaceComplication.Registrant registrant);
-
- /** Inject into MediaDreamSentinel. */
- @Binds
- @IntoMap
- @ClassKey(MediaDreamSentinel.class)
- public abstract CoreStartable bindMediaDreamSentinel(
- MediaDreamSentinel sentinel);
-
- /** Inject into DreamClockTimeComplication.Registrant */
- @Binds
- @IntoMap
- @ClassKey(DreamClockTimeComplication.Registrant.class)
- public abstract CoreStartable bindDreamClockTimeComplicationRegistrant(
- DreamClockTimeComplication.Registrant registrant);
-
- /** Inject into DreamClockDateComplication.Registrant */
- @Binds
- @IntoMap
- @ClassKey(DreamClockDateComplication.Registrant.class)
- public abstract CoreStartable bindDreamClockDateComplicationRegistrant(
- DreamClockDateComplication.Registrant registrant);
-
- /** Inject into DreamWeatherComplication.Registrant */
- @Binds
- @IntoMap
- @ClassKey(DreamWeatherComplication.Registrant.class)
- public abstract CoreStartable bindDreamWeatherComplicationRegistrant(
- DreamWeatherComplication.Registrant registrant);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
new file mode 100644
index 0000000..f78929f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -0,0 +1,201 @@
+/*
+ * 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.dagger
+
+import com.android.keyguard.KeyguardBiometricLockoutLogger
+import com.android.systemui.CoreStartable
+import com.android.systemui.LatencyTester
+import com.android.systemui.ScreenDecorations
+import com.android.systemui.SliceBroadcastRelayHandler
+import com.android.systemui.accessibility.SystemActions
+import com.android.systemui.accessibility.WindowMagnification
+import com.android.systemui.biometrics.AuthController
+import com.android.systemui.clipboardoverlay.ClipboardListener
+import com.android.systemui.dagger.qualifiers.PerUser
+import com.android.systemui.globalactions.GlobalActionsComponent
+import com.android.systemui.keyboard.KeyboardUI
+import com.android.systemui.keyguard.KeyguardViewMediator
+import com.android.systemui.log.SessionTracker
+import com.android.systemui.media.RingtonePlayer
+import com.android.systemui.power.PowerUI
+import com.android.systemui.recents.Recents
+import com.android.systemui.shortcut.ShortcutKeyDispatcher
+import com.android.systemui.statusbar.notification.InstantAppNotifier
+import com.android.systemui.theme.ThemeOverlayController
+import com.android.systemui.toast.ToastUI
+import com.android.systemui.usb.StorageNotification
+import com.android.systemui.util.NotificationChannels
+import com.android.systemui.util.leak.GarbageMonitor
+import com.android.systemui.volume.VolumeUI
+import com.android.systemui.wmshell.WMShell
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+
+/**
+ * Collection of {@link CoreStartable}s that should be run on AOSP.
+ */
+@Module
+abstract class SystemUICoreStartableModule {
+ /** Inject into AuthController. */
+ @Binds
+ @IntoMap
+ @ClassKey(AuthController::class)
+ abstract fun bindAuthController(service: AuthController): CoreStartable
+
+ /** Inject into ClipboardListener. */
+ @Binds
+ @IntoMap
+ @ClassKey(ClipboardListener::class)
+ abstract fun bindClipboardListener(sysui: ClipboardListener): CoreStartable
+
+ /** Inject into GarbageMonitor.Service. */
+ @Binds
+ @IntoMap
+ @ClassKey(GarbageMonitor::class)
+ abstract fun bindGarbageMonitorService(sysui: GarbageMonitor.Service): CoreStartable
+
+ /** Inject into GlobalActionsComponent. */
+ @Binds
+ @IntoMap
+ @ClassKey(GlobalActionsComponent::class)
+ abstract fun bindGlobalActionsComponent(sysui: GlobalActionsComponent): CoreStartable
+
+ /** Inject into InstantAppNotifier. */
+ @Binds
+ @IntoMap
+ @ClassKey(InstantAppNotifier::class)
+ abstract fun bindInstantAppNotifier(sysui: InstantAppNotifier): CoreStartable
+
+ /** Inject into KeyboardUI. */
+ @Binds
+ @IntoMap
+ @ClassKey(KeyboardUI::class)
+ abstract fun bindKeyboardUI(sysui: KeyboardUI): CoreStartable
+
+ /** Inject into KeyguardBiometricLockoutLogger */
+ @Binds
+ @IntoMap
+ @ClassKey(KeyguardBiometricLockoutLogger::class)
+ abstract fun bindKeyguardBiometricLockoutLogger(
+ sysui: KeyguardBiometricLockoutLogger
+ ): CoreStartable
+
+ /** Inject into KeyguardViewMediator. */
+ @Binds
+ @IntoMap
+ @ClassKey(KeyguardViewMediator::class)
+ abstract fun bindKeyguardViewMediator(sysui: KeyguardViewMediator): CoreStartable
+
+ /** Inject into LatencyTests. */
+ @Binds
+ @IntoMap
+ @ClassKey(LatencyTester::class)
+ abstract fun bindLatencyTester(sysui: LatencyTester): CoreStartable
+
+ /** Inject into NotificationChannels. */
+ @Binds
+ @IntoMap
+ @ClassKey(NotificationChannels::class)
+ @PerUser
+ abstract fun bindNotificationChannels(sysui: NotificationChannels): CoreStartable
+
+ /** Inject into PowerUI. */
+ @Binds
+ @IntoMap
+ @ClassKey(PowerUI::class)
+ abstract fun bindPowerUI(sysui: PowerUI): CoreStartable
+
+ /** Inject into Recents. */
+ @Binds
+ @IntoMap
+ @ClassKey(Recents::class)
+ abstract fun bindRecents(sysui: Recents): CoreStartable
+
+ /** Inject into RingtonePlayer. */
+ @Binds
+ @IntoMap
+ @ClassKey(RingtonePlayer::class)
+ abstract fun bind(sysui: RingtonePlayer): CoreStartable
+
+ /** Inject into ScreenDecorations. */
+ @Binds
+ @IntoMap
+ @ClassKey(ScreenDecorations::class)
+ abstract fun bindScreenDecorations(sysui: ScreenDecorations): CoreStartable
+
+ /** Inject into SessionTracker. */
+ @Binds
+ @IntoMap
+ @ClassKey(SessionTracker::class)
+ abstract fun bindSessionTracker(service: SessionTracker): CoreStartable
+
+ /** Inject into ShortcutKeyDispatcher. */
+ @Binds
+ @IntoMap
+ @ClassKey(ShortcutKeyDispatcher::class)
+ abstract fun bindShortcutKeyDispatcher(sysui: ShortcutKeyDispatcher): CoreStartable
+
+ /** Inject into SliceBroadcastRelayHandler. */
+ @Binds
+ @IntoMap
+ @ClassKey(SliceBroadcastRelayHandler::class)
+ abstract fun bindSliceBroadcastRelayHandler(sysui: SliceBroadcastRelayHandler): CoreStartable
+
+ /** Inject into StorageNotification. */
+ @Binds
+ @IntoMap
+ @ClassKey(StorageNotification::class)
+ abstract fun bindStorageNotification(sysui: StorageNotification): CoreStartable
+
+ /** Inject into SystemActions. */
+ @Binds
+ @IntoMap
+ @ClassKey(SystemActions::class)
+ abstract fun bindSystemActions(sysui: SystemActions): CoreStartable
+
+ /** Inject into ThemeOverlayController. */
+ @Binds
+ @IntoMap
+ @ClassKey(ThemeOverlayController::class)
+ abstract fun bindThemeOverlayController(sysui: ThemeOverlayController): CoreStartable
+
+ /** Inject into ToastUI. */
+ @Binds
+ @IntoMap
+ @ClassKey(ToastUI::class)
+ abstract fun bindToastUI(service: ToastUI): CoreStartable
+
+ /** Inject into VolumeUI. */
+ @Binds
+ @IntoMap
+ @ClassKey(VolumeUI::class)
+ abstract fun bindVolumeUI(sysui: VolumeUI): CoreStartable
+
+ /** Inject into WindowMagnification. */
+ @Binds
+ @IntoMap
+ @ClassKey(WindowMagnification::class)
+ abstract fun bindWindowMagnification(sysui: WindowMagnification): CoreStartable
+
+ /** Inject into WMShell. */
+ @Binds
+ @IntoMap
+ @ClassKey(WMShell::class)
+ abstract fun bindWMShell(sysui: WMShell): CoreStartable
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
index a178738..a4da6b4 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
@@ -48,6 +48,7 @@
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.dagger.StartStatusBarModule;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
@@ -86,6 +87,7 @@
MediaModule.class,
PowerModule.class,
QSModule.class,
+ StartStatusBarModule.class,
VolumeModule.class
})
public abstract class SystemUIDefaultModule {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/AdditionalStartable.java b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/AdditionalStartable.java
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/AdditionalStartable.java
diff --git a/core/java/android/app/ambientcontext/AmbientContextEventResponse.aidl b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/PerUser.java
similarity index 61%
copy from core/java/android/app/ambientcontext/AmbientContextEventResponse.aidl
copy to packages/SystemUI/src/com/android/systemui/dagger/qualifiers/PerUser.java
index 4dc6466..f6d5ece 100644
--- a/core/java/android/app/ambientcontext/AmbientContextEventResponse.aidl
+++ b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/PerUser.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -14,6 +14,17 @@
* limitations under the License.
*/
-package android.app.ambientcontext;
+package com.android.systemui.dagger.qualifiers;
-parcelable AmbientContextEventResponse;
\ No newline at end of file
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface PerUser {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
index 63d4d6b..a9e310d 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
@@ -105,17 +105,7 @@
updateUdfpsController();
if (mUdfpsController == null) {
- mAuthController.addCallback(new AuthController.Callback() {
- @Override
- public void onAllAuthenticatorsRegistered() {
- updateUdfpsController();
- }
-
- @Override
- public void onEnrollmentsChanged() {
- updateUdfpsController();
- }
- });
+ mAuthController.addCallback(mAuthControllerCallback);
}
}
@@ -128,6 +118,11 @@
}
@Override
+ public void destroy() {
+ mAuthController.removeCallback(mAuthControllerCallback);
+ }
+
+ @Override
public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
int screenState = newState.screenState(mParameters);
mDozeHost.cancelGentleSleep();
@@ -234,4 +229,16 @@
mWakeLock.setAcquired(false);
}
}
+
+ private final AuthController.Callback mAuthControllerCallback = new AuthController.Callback() {
+ @Override
+ public void onAllAuthenticatorsRegistered() {
+ updateUdfpsController();
+ }
+
+ @Override
+ public void onEnrollmentsChanged() {
+ updateUdfpsController();
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index 77997e4..4dacf65 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -31,10 +31,8 @@
import com.android.internal.policy.PhoneWindow;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.settingslib.dream.DreamBackend;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.complication.Complication;
-import com.android.systemui.dreams.complication.ComplicationUtils;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
import com.android.systemui.dreams.touch.DreamOverlayTouchMonitor;
@@ -59,7 +57,6 @@
// content area).
private final DreamOverlayContainerViewController mDreamOverlayContainerViewController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private final DreamBackend mDreamBackend;
// A reference to the {@link Window} used to hold the dream overlay.
private Window mWindow;
@@ -112,7 +109,6 @@
setCurrentState(Lifecycle.State.CREATED);
mLifecycleRegistry = component.getLifecycleRegistry();
mDreamOverlayTouchMonitor = component.getDreamOverlayTouchMonitor();
- mDreamBackend = component.getDreamBackend();
mDreamOverlayTouchMonitor.init();
}
@@ -122,10 +118,12 @@
@Override
public void onDestroy() {
- mKeyguardUpdateMonitor.registerCallback(mKeyguardCallback);
+ mKeyguardUpdateMonitor.removeCallback(mKeyguardCallback);
setCurrentState(Lifecycle.State.DESTROYED);
final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
- windowManager.removeView(mWindow.getDecorView());
+ if (mWindow != null) {
+ windowManager.removeView(mWindow.getDecorView());
+ }
mStateController.setOverlayActive(false);
super.onDestroy();
}
@@ -134,9 +132,6 @@
public void onStartDream(@NonNull WindowManager.LayoutParams layoutParams) {
setCurrentState(Lifecycle.State.STARTED);
mExecutor.execute(() -> {
- mStateController.setAvailableComplicationTypes(
- ComplicationUtils.convertComplicationTypes(
- mDreamBackend.getEnabledComplications()));
addOverlayWindowLocked(layoutParams);
setCurrentState(Lifecycle.State.RESUMED);
mStateController.setOverlayActive(true);
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/SmartSpaceComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/SmartSpaceComplication.java
index 09221b4..240389a 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/SmartSpaceComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/SmartSpaceComplication.java
@@ -66,6 +66,7 @@
}
private static class SmartSpaceComplicationViewHolder implements ViewHolder {
+ private static final int SMARTSPACE_COMPLICATION_WEIGHT = 10;
private final LockscreenSmartspaceController mSmartSpaceController;
private final Context mContext;
@@ -92,7 +93,7 @@
return new ComplicationLayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT,
ComplicationLayoutParams.POSITION_TOP | ComplicationLayoutParams.POSITION_START,
ComplicationLayoutParams.DIRECTION_DOWN,
- 0, true);
+ SMARTSPACE_COMPLICATION_WEIGHT, true);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationTypesUpdater.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationTypesUpdater.java
new file mode 100644
index 0000000..83249aa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationTypesUpdater.java
@@ -0,0 +1,85 @@
+/*
+ * 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.systemui.dreams.complication;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+import com.android.settingslib.dream.DreamBackend;
+import com.android.systemui.CoreStartable;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.dreams.DreamOverlayStateController;
+import com.android.systemui.util.settings.SecureSettings;
+
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+
+/**
+ * {@link ComplicationTypesUpdater} observes the state of available complication types set by the
+ * user, and pushes updates to {@link DreamOverlayStateController}.
+ */
+@SysUISingleton
+public class ComplicationTypesUpdater extends CoreStartable {
+ private final DreamBackend mDreamBackend;
+ private final Executor mExecutor;
+ private final SecureSettings mSecureSettings;
+
+ private final DreamOverlayStateController mDreamOverlayStateController;
+
+ @Inject
+ ComplicationTypesUpdater(Context context,
+ DreamBackend dreamBackend,
+ @Main Executor executor,
+ SecureSettings secureSettings,
+ DreamOverlayStateController dreamOverlayStateController) {
+ super(context);
+
+ mDreamBackend = dreamBackend;
+ mExecutor = executor;
+ mSecureSettings = secureSettings;
+ mDreamOverlayStateController = dreamOverlayStateController;
+ }
+
+ @Override
+ public void start() {
+ final ContentObserver settingsObserver = new ContentObserver(null /*handler*/) {
+ @Override
+ public void onChange(boolean selfChange) {
+ mExecutor.execute(() -> mDreamOverlayStateController.setAvailableComplicationTypes(
+ getAvailableComplicationTypes()));
+ }
+ };
+
+ mSecureSettings.registerContentObserverForUser(
+ Settings.Secure.SCREENSAVER_ENABLED_COMPLICATIONS,
+ settingsObserver,
+ UserHandle.myUserId());
+ settingsObserver.onChange(false);
+ }
+
+ /**
+ * Returns complication types that are currently available by user setting.
+ */
+ @Complication.ComplicationType
+ private int getAvailableComplicationTypes() {
+ return ComplicationUtils.convertComplicationTypes(mDreamBackend.getEnabledComplications());
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
index d8af9e5..c61f796 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
@@ -16,10 +16,14 @@
package com.android.systemui.dreams.dagger;
+import android.content.Context;
+
+import com.android.settingslib.dream.DreamBackend;
import com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule;
import com.android.systemui.dreams.touch.dagger.DreamTouchModule;
import dagger.Module;
+import dagger.Provides;
/**
* Dagger Module providing Communal-related functionality.
@@ -32,4 +36,11 @@
DreamOverlayComponent.class,
})
public interface DreamModule {
+ /**
+ * Provides an instance of the dream backend.
+ */
+ @Provides
+ static DreamBackend providesDreamBackend(Context context) {
+ return DreamBackend.getInstance(context);
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java
index 60278a9..05ab901 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java
@@ -22,7 +22,6 @@
import androidx.lifecycle.LifecycleRegistry;
import androidx.lifecycle.ViewModelStore;
-import com.android.settingslib.dream.DreamBackend;
import com.android.systemui.dreams.DreamOverlayContainerViewController;
import com.android.systemui.dreams.complication.Complication;
import com.android.systemui.dreams.complication.dagger.ComplicationModule;
@@ -69,7 +68,4 @@
/** Builds a {@link DreamOverlayTouchMonitor} */
DreamOverlayTouchMonitor getDreamOverlayTouchMonitor();
-
- /** Builds a ${@link DreamBackend} */
- DreamBackend getDreamBackend();
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
index efa063f..4eb5cb9 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
@@ -17,7 +17,6 @@
package com.android.systemui.dreams.dagger;
import android.content.ContentResolver;
-import android.content.Context;
import android.content.res.Resources;
import android.os.Handler;
import android.view.LayoutInflater;
@@ -28,7 +27,6 @@
import androidx.lifecycle.LifecycleRegistry;
import com.android.internal.util.Preconditions;
-import com.android.settingslib.dream.DreamBackend;
import com.android.systemui.R;
import com.android.systemui.battery.BatteryMeterView;
import com.android.systemui.battery.BatteryMeterViewController;
@@ -149,10 +147,4 @@
static Lifecycle providesLifecycle(LifecycleOwner lifecycleOwner) {
return lifecycleOwner.getLifecycle();
}
-
- @Provides
- @DreamOverlayComponent.DreamOverlayScope
- static DreamBackend providesDreamBackend(Context context) {
- return DreamBackend.getInstance(context);
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dump/DumpHandler.kt b/packages/SystemUI/src/com/android/systemui/dump/DumpHandler.kt
index fa951fa..e4a7406 100644
--- a/packages/SystemUI/src/com/android/systemui/dump/DumpHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/dump/DumpHandler.kt
@@ -19,6 +19,7 @@
import android.content.Context
import android.os.SystemClock
import android.os.Trace
+import com.android.systemui.CoreStartable
import com.android.systemui.R
import com.android.systemui.dump.DumpHandler.Companion.PRIORITY_ARG_CRITICAL
import com.android.systemui.dump.DumpHandler.Companion.PRIORITY_ARG_HIGH
@@ -27,6 +28,7 @@
import java.io.FileDescriptor
import java.io.PrintWriter
import javax.inject.Inject
+import javax.inject.Provider
/**
* Oversees SystemUI's output during bug reports (and dumpsys in general)
@@ -80,7 +82,8 @@
class DumpHandler @Inject constructor(
private val context: Context,
private val dumpManager: DumpManager,
- private val logBufferEulogizer: LogBufferEulogizer
+ private val logBufferEulogizer: LogBufferEulogizer,
+ private val startables: MutableMap<Class<*>, Provider<CoreStartable>>
) {
/**
* Dump the diagnostics! Behavior can be controlled via [args].
@@ -173,12 +176,21 @@
pw.println("SystemUiServiceComponents configuration:")
pw.print("vendor component: ")
pw.println(context.resources.getString(R.string.config_systemUIVendorServiceComponent))
- dumpServiceList(pw, "global", R.array.config_systemUIServiceComponents)
+ val services: MutableList<String> = startables.keys
+ .map({ cls: Class<*> -> cls.simpleName })
+ .toMutableList()
+
+ services.add(context.resources.getString(R.string.config_systemUIVendorServiceComponent))
+ dumpServiceList(pw, "global", services.toTypedArray())
dumpServiceList(pw, "per-user", R.array.config_systemUIServiceComponentsPerUser)
}
private fun dumpServiceList(pw: PrintWriter, type: String, resId: Int) {
- val services: Array<String>? = context.resources.getStringArray(resId)
+ val services: Array<String> = context.resources.getStringArray(resId)
+ dumpServiceList(pw, type, services)
+ }
+
+ private fun dumpServiceList(pw: PrintWriter, type: String, services: Array<String>?) {
pw.print(type)
pw.print(": ")
if (services == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 552f188..1ba6e34 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -95,6 +95,10 @@
/***************************************/
// 500 - quick settings
+ /**
+ * @deprecated Not needed anymore
+ */
+ @Deprecated
public static final BooleanFlag NEW_USER_SWITCHER =
new BooleanFlag(500, true);
@@ -139,9 +143,15 @@
/***************************************/
// 900 - media
- public static final BooleanFlag MEDIA_TAP_TO_TRANSFER = new BooleanFlag(900, false);
+ public static final BooleanFlag MEDIA_TAP_TO_TRANSFER = new BooleanFlag(900, true);
public static final BooleanFlag MEDIA_SESSION_ACTIONS = new BooleanFlag(901, true);
public static final BooleanFlag MEDIA_SESSION_LAYOUT = new BooleanFlag(902, false);
+ public static final BooleanFlag MEDIA_MUTE_AWAIT = new BooleanFlag(904, true);
+
+ // 1000 - dock
+ public static final BooleanFlag SIMULATE_DOCK_THROUGH_CHARGING =
+ new BooleanFlag(1000, true);
+
// Pay no attention to the reflection behind the curtain.
// ========================== Curtain ==========================
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsLayoutLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsLayoutLite.java
index f1e5b08..42230ae 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsLayoutLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsLayoutLite.java
@@ -16,8 +16,6 @@
package com.android.systemui.globalactions;
-import static com.android.systemui.util.leak.RotationUtils.ROTATION_NONE;
-
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
@@ -33,15 +31,9 @@
* ConstraintLayout implementation of the button layout created by the global actions dialog.
*/
public class GlobalActionsLayoutLite extends GlobalActionsLayout {
- private final int mMaxColumns;
- private final int mMaxRows;
public GlobalActionsLayoutLite(Context context, AttributeSet attrs) {
super(context, attrs);
- mMaxColumns = getResources().getInteger(
- com.android.systemui.R.integer.power_menu_lite_max_columns);
- mMaxRows = getResources().getInteger(
- com.android.systemui.R.integer.power_menu_lite_max_rows);
setOnClickListener(v -> { }); // Prevent parent onClickListener from triggering
}
@@ -60,10 +52,13 @@
@Override
public void onUpdateList() {
super.onUpdateList();
- int nElementsWrap = (getCurrentRotation() == ROTATION_NONE) ? mMaxColumns : mMaxRows;
+ int nElementsWrap = getResources().getInteger(
+ com.android.systemui.R.integer.power_menu_lite_max_columns);
int nChildren = getListView().getChildCount() - 1; // don't count flow element
- if (getCurrentRotation() != ROTATION_NONE && nChildren > mMaxRows) {
- // up to 4 elements can fit in a row in landscape, otherwise limit for balance
+
+ // Avoid having just one action on the last row if there are more than 2 columns because
+ // it looks unbalanced. Instead, bring the column size down to balance better.
+ if (nChildren == nElementsWrap + 1 && nElementsWrap > 2) {
nElementsWrap -= 1;
}
Flow flow = findViewById(R.id.list_flow);
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
index 1c0b104..6f7e73f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
@@ -52,6 +52,7 @@
import com.android.systemui.CoreStartable;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.dagger.SysUISingleton;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -60,6 +61,10 @@
import java.util.List;
import java.util.Set;
+import javax.inject.Inject;
+
+/** */
+@SysUISingleton
public class KeyboardUI extends CoreStartable implements InputManager.OnTabletModeChangedListener {
private static final String TAG = "KeyboardUI";
private static final boolean DEBUG = false;
@@ -117,6 +122,7 @@
private int mState;
+ @Inject
public KeyboardUI(Context context) {
super(context);
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 88555ed..b96eee7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -102,7 +102,7 @@
"persist.wm.enable_remote_keyguard_animation";
private static final int sEnableRemoteKeyguardAnimation =
- SystemProperties.getInt(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, 1);
+ SystemProperties.getInt(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, 2);
/**
* @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 0f08a18..ae7147e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -789,9 +789,10 @@
@Override
public int getBouncerPromptReason() {
int currentUser = KeyguardUpdateMonitor.getCurrentUser();
- boolean trust = mUpdateMonitor.isTrustUsuallyManaged(currentUser);
- boolean biometrics = mUpdateMonitor.isUnlockingWithBiometricsPossible(currentUser);
- boolean any = trust || biometrics;
+ boolean trustAgentsEnabled = mUpdateMonitor.isTrustUsuallyManaged(currentUser);
+ boolean biometricsEnrolled =
+ mUpdateMonitor.isUnlockingWithBiometricsPossible(currentUser);
+ boolean any = trustAgentsEnabled || biometricsEnrolled;
KeyguardUpdateMonitor.StrongAuthTracker strongAuthTracker =
mUpdateMonitor.getStrongAuthTracker();
int strongAuth = strongAuthTracker.getStrongAuthForUser(currentUser);
@@ -800,9 +801,10 @@
return KeyguardSecurityView.PROMPT_REASON_RESTART;
} else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_TIMEOUT) != 0) {
return KeyguardSecurityView.PROMPT_REASON_TIMEOUT;
- } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW) != 0) {
+ } else if ((strongAuth & STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW) != 0) {
return KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN;
- } else if (trust && (strongAuth & SOME_AUTH_REQUIRED_AFTER_USER_REQUEST) != 0) {
+ } else if (trustAgentsEnabled
+ && (strongAuth & SOME_AUTH_REQUIRED_AFTER_USER_REQUEST) != 0) {
return KeyguardSecurityView.PROMPT_REASON_USER_REQUEST;
} else if (any && ((strongAuth & STRONG_AUTH_REQUIRED_AFTER_LOCKOUT) != 0
|| mUpdateMonitor.isFingerprintLockedOut())) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index b3e6682..ce7a697 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -371,13 +371,6 @@
// Output switcher chip
ViewGroup seamlessView = mMediaViewHolder.getSeamless();
seamlessView.setVisibility(View.VISIBLE);
- seamlessView.setOnClickListener(
- v -> {
- if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
- mMediaOutputDialogFactory.create(data.getPackageName(), true,
- mMediaViewHolder.getSeamlessButton());
- }
- });
ImageView iconView = mMediaViewHolder.getSeamlessIcon();
TextView deviceName = mMediaViewHolder.getSeamlessText();
final MediaDeviceData device = data.getDevice();
@@ -387,8 +380,8 @@
final float seamlessAlpha = seamlessDisabled ? DISABLED_ALPHA : 1.0f;
mMediaViewHolder.getSeamlessButton().setAlpha(seamlessAlpha);
seamlessView.setEnabled(!seamlessDisabled);
- String deviceString = null;
- if (device != null && device.getEnabled()) {
+ CharSequence deviceString = mContext.getString(R.string.media_seamless_other_device);
+ if (device != null) {
Drawable icon = device.getIcon();
if (icon instanceof AdaptiveIcon) {
AdaptiveIcon aIcon = (AdaptiveIcon) icon;
@@ -399,13 +392,32 @@
}
deviceString = device.getName();
} else {
- // Reset to default
- Log.w(TAG, "Device is null or not enabled: " + device + ", not binding output chip.");
+ // Set to default icon
iconView.setImageResource(R.drawable.ic_media_home_devices);
- deviceString = mContext.getString(R.string.media_seamless_other_device);
}
deviceName.setText(deviceString);
seamlessView.setContentDescription(deviceString);
+ seamlessView.setOnClickListener(
+ v -> {
+ if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ return;
+ }
+ if (device.getIntent() != null) {
+ if (device.getIntent().isActivity()) {
+ mActivityStarter.startActivity(
+ device.getIntent().getIntent(), true);
+ } else {
+ try {
+ device.getIntent().send();
+ } catch (PendingIntent.CanceledException e) {
+ Log.e(TAG, "Device pending intent was canceled");
+ }
+ }
+ } else {
+ mMediaOutputDialogFactory.create(data.getPackageName(), true,
+ mMediaViewHolder.getSeamlessButton());
+ }
+ });
// Dismiss
mMediaViewHolder.getDismissText().setAlpha(isDismissible ? 1 : DISABLED_ALPHA);
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
index 4b8dfde..500e82e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
@@ -164,8 +164,17 @@
)
/** State of the media device. */
-data class MediaDeviceData(
+data class MediaDeviceData
+@JvmOverloads constructor(
+ /** Whether or not to enable the chip */
val enabled: Boolean,
+
+ /** Device icon to show in the chip */
val icon: Drawable?,
- val name: String?
+
+ /** Device display name */
+ val name: CharSequence?,
+
+ /** Optional intent to override the default output switcher for this control */
+ val intent: PendingIntent? = null
)
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 240ca36..e1ff110 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -27,8 +27,6 @@
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
-import android.content.pm.ApplicationInfo
-import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.ImageDecoder
import android.graphics.drawable.Icon
@@ -129,7 +127,7 @@
private val useQsMediaPlayer: Boolean,
private val systemClock: SystemClock,
private val tunerService: TunerService,
- private val mediaFlags: MediaFlags,
+ private val mediaFlags: MediaFlags
) : Dumpable, BcSmartspaceDataPlugin.SmartspaceTargetListener {
companion object {
@@ -170,20 +168,9 @@
/**
* Check whether this notification is an RCN
- * TODO(b/204910409) implement new API for explicitly declaring this
*/
private fun isRemoteCastNotification(sbn: StatusBarNotification): Boolean {
- val pm = context.packageManager
- try {
- val info = pm.getApplicationInfo(sbn.packageName, PackageManager.MATCH_SYSTEM_ONLY)
- if (info.privateFlags and ApplicationInfo.PRIVATE_FLAG_PRIVILEGED != 0) {
- val extras = sbn.notification.extras
- if (extras.containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME)) {
- return true
- }
- }
- } catch (e: PackageManager.NameNotFoundException) { }
- return false
+ return sbn.notification.extras.containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE)
}
@Inject
@@ -597,6 +584,25 @@
artist = HybridGroupManager.resolveText(notif)
}
+ // Device name (used for remote cast notifications)
+ var device: MediaDeviceData? = null
+ if (isRemoteCastNotification(sbn)) {
+ val extras = sbn.notification.extras
+ val deviceName = extras.getCharSequence(Notification.EXTRA_MEDIA_REMOTE_DEVICE, null)
+ val deviceIcon = extras.getInt(Notification.EXTRA_MEDIA_REMOTE_ICON, -1)
+ val deviceIntent = extras.getParcelable(Notification.EXTRA_MEDIA_REMOTE_INTENT)
+ as PendingIntent?
+ Log.d(TAG, "$key is RCN for $deviceName")
+
+ if (deviceName != null && deviceIcon > -1) {
+ // Name and icon must be present, but intent may be null
+ val enabled = deviceIntent != null && deviceIntent.isActivity
+ val deviceDrawable = Icon.createWithResource(sbn.packageName, deviceIcon)
+ .loadDrawable(sbn.getPackageContext(context))
+ device = MediaDeviceData(enabled, deviceDrawable, deviceName, deviceIntent)
+ }
+ }
+
// Control buttons
// If flag is enabled and controller has a PlaybackState, create actions from session info
// Otherwise, use the notification actions
@@ -624,7 +630,7 @@
val active = mediaEntries[key]?.active ?: true
onMediaDataLoaded(key, oldKey, MediaData(sbn.normalizedUserId, true, bgColor, app,
smallIcon, artist, song, artWorkIcon, actionIcons, actionsToShowCollapsed,
- semanticActions, sbn.packageName, token, notif.contentIntent, null,
+ semanticActions, sbn.packageName, token, notif.contentIntent, device,
active, resumeAction = resumeAction, playbackLocation = playbackLocation,
notificationKey = key, hasCheckedForResume = hasCheckedForResume,
isPlaying = isPlaying, isClearable = sbn.isClearable(),
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
index bed254f..ffae898 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
@@ -16,6 +16,7 @@
package com.android.systemui.media
+import android.graphics.drawable.Drawable
import android.media.MediaRouter2Manager
import android.media.session.MediaController
import androidx.annotation.AnyThread
@@ -27,6 +28,8 @@
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
+import com.android.systemui.media.muteawait.MediaMuteAwaitConnectionManager
+import com.android.systemui.media.muteawait.MediaMuteAwaitConnectionManagerFactory
import java.io.FileDescriptor
import java.io.PrintWriter
import java.util.concurrent.Executor
@@ -41,6 +44,7 @@
private val controllerFactory: MediaControllerFactory,
private val localMediaManagerFactory: LocalMediaManagerFactory,
private val mr2manager: MediaRouter2Manager,
+ private val muteAwaitConnectionManagerFactory: MediaMuteAwaitConnectionManagerFactory,
@Main private val fgExecutor: Executor,
@Background private val bgExecutor: Executor,
dumpManager: DumpManager
@@ -77,11 +81,25 @@
var entry = entries[key]
if (entry == null || entry?.token != data.token) {
entry?.stop()
+ if (data.device != null) {
+ // If we were already provided device info (e.g. from RCN), keep that and don't
+ // listen for updates, but process once to push updates to listeners
+ processDevice(key, oldKey, data.device)
+ return
+ }
val controller = data.token?.let {
controllerFactory.create(it)
}
- entry = Entry(key, oldKey, controller,
- localMediaManagerFactory.create(data.packageName))
+ val localMediaManager = localMediaManagerFactory.create(data.packageName)
+ val muteAwaitConnectionManager =
+ muteAwaitConnectionManagerFactory.create(localMediaManager)
+ entry = Entry(
+ key,
+ oldKey,
+ controller,
+ localMediaManager,
+ muteAwaitConnectionManager
+ )
entries[key] = entry
entry.start()
}
@@ -126,7 +144,8 @@
val key: String,
val oldKey: String?,
val controller: MediaController?,
- val localMediaManager: LocalMediaManager
+ val localMediaManager: LocalMediaManager,
+ val muteAwaitConnectionManager: MediaMuteAwaitConnectionManager?
) : LocalMediaManager.DeviceCallback, MediaController.Callback() {
val token
@@ -142,11 +161,15 @@
}
}
}
+ // A device that is not yet connected but is expected to connect imminently. Because it's
+ // expected to connect imminently, it should be displayed as the current device.
+ private var aboutToConnectDeviceOverride: MediaDeviceData? = null
@AnyThread
fun start() = bgExecutor.execute {
localMediaManager.registerCallback(this)
localMediaManager.startScan()
+ muteAwaitConnectionManager?.startListening()
playbackType = controller?.playbackInfo?.playbackType ?: PLAYBACK_TYPE_UNKNOWN
controller?.registerCallback(this)
updateCurrent()
@@ -159,6 +182,7 @@
controller?.unregisterCallback(this)
localMediaManager.stopScan()
localMediaManager.unregisterCallback(this)
+ muteAwaitConnectionManager?.stopListening()
}
fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<String>) {
@@ -197,8 +221,21 @@
}
}
+ override fun onAboutToConnectDeviceChanged(deviceName: String?, deviceIcon: Drawable?) {
+ aboutToConnectDeviceOverride = if (deviceName == null || deviceIcon == null) {
+ null
+ } else {
+ MediaDeviceData(enabled = true, deviceIcon, deviceName)
+ }
+ updateCurrent()
+ }
+
@WorkerThread
private fun updateCurrent() {
+ if (aboutToConnectDeviceOverride != null) {
+ current = aboutToConnectDeviceOverride
+ return
+ }
val device = localMediaManager.currentConnectedDevice
val route = controller?.let { mr2manager.getRoutingSessionForMediaController(it) }
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt b/packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt
index b9795f1..e146768 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt
@@ -37,4 +37,9 @@
return featureFlags.isEnabled(Flags.MEDIA_SESSION_ACTIONS) &&
featureFlags.isEnabled(Flags.MEDIA_SESSION_LAYOUT)
}
-}
\ No newline at end of file
+
+ /**
+ * Check whether we support displaying information about mute await connections.
+ */
+ fun areMuteAwaitConnectionsEnabled() = featureFlags.isEnabled(Flags.MEDIA_MUTE_AWAIT)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
index ae5f9b6..4e35d16 100644
--- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
@@ -38,16 +38,20 @@
import android.util.Log;
import com.android.systemui.CoreStartable;
+import com.android.systemui.dagger.SysUISingleton;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
+import javax.inject.Inject;
+
/**
* Service that offers to play ringtones by {@link Uri}, since our process has
* {@link android.Manifest.permission#READ_EXTERNAL_STORAGE}.
*/
+@SysUISingleton
public class RingtonePlayer extends CoreStartable {
private static final String TAG = "RingtonePlayer";
private static final boolean LOGD = false;
@@ -59,6 +63,7 @@
private final NotificationPlayer mAsyncPlayer = new NotificationPlayer(TAG);
private final HashMap<IBinder, Client> mClients = new HashMap<IBinder, Client>();
+ @Inject
public RingtonePlayer(Context context) {
super(context);
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
index f8b34f9..3225f73 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
@@ -18,15 +18,18 @@
import android.app.Service;
import android.content.Context;
+import android.os.Handler;
import android.view.WindowManager;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.media.MediaDataManager;
+import com.android.systemui.media.MediaFlags;
import com.android.systemui.media.MediaHierarchyManager;
import com.android.systemui.media.MediaHost;
import com.android.systemui.media.MediaHostStatesManager;
import com.android.systemui.media.dream.dagger.MediaComplicationComponent;
+import com.android.systemui.media.muteawait.MediaMuteAwaitConnectionCli;
import com.android.systemui.media.nearby.NearbyMediaDevicesService;
import com.android.systemui.media.taptotransfer.MediaTttCommandLineHelper;
import com.android.systemui.media.taptotransfer.MediaTttFlags;
@@ -117,12 +120,14 @@
MediaTttFlags mediaTttFlags,
CommandQueue commandQueue,
Context context,
- WindowManager windowManager) {
+ WindowManager windowManager,
+ @Main Handler mainHandler) {
if (!mediaTttFlags.isMediaTttEnabled()) {
return Optional.empty();
}
return Optional.of(
- new MediaTttChipControllerReceiver(commandQueue, context, windowManager));
+ new MediaTttChipControllerReceiver(
+ commandQueue, context, windowManager, mainHandler));
}
/** */
@@ -140,6 +145,20 @@
new MediaTttCommandLineHelper(commandRegistry, context, mainExecutor));
}
+ /** */
+ @Provides
+ @SysUISingleton
+ static Optional<MediaMuteAwaitConnectionCli> providesMediaMuteAwaitConnectionCli(
+ MediaFlags mediaFlags,
+ CommandRegistry commandRegistry,
+ Context context
+ ) {
+ if (!mediaFlags.areMuteAwaitConnectionsEnabled()) {
+ return Optional.empty();
+ }
+ return Optional.of(new MediaMuteAwaitConnectionCli(commandRegistry, context));
+ }
+
/** Inject into NearbyMediaDevicesService. */
@Binds
@IntoMap
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index 196dbf1..5b29719 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -16,6 +16,7 @@
package com.android.systemui.media.dialog;
+import android.content.res.ColorStateList;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
@@ -23,8 +24,10 @@
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.CheckBox;
import androidx.annotation.NonNull;
+import androidx.core.widget.CompoundButtonCompat;
import com.android.settingslib.Utils;
import com.android.settingslib.media.LocalMediaManager.MediaDeviceState;
@@ -100,8 +103,10 @@
}
mCheckBox.setVisibility(View.GONE);
mStatusIcon.setVisibility(View.GONE);
- mTitleText.setTextColor(Utils.getColorStateListDefaultColor(mContext,
- R.color.media_dialog_inactive_item_main_content));
+ mTitleText.setTextColor(mController.getColorInactiveItem());
+ mSeekBar.getProgressDrawable().setColorFilter(
+ new PorterDuffColorFilter(mController.getColorSeekbarProgress(),
+ PorterDuff.Mode.SRC_IN));
if (mCurrentActivePosition == position) {
mCurrentActivePosition = -1;
}
@@ -117,6 +122,10 @@
if (mController.isTransferring()) {
if (device.getState() == MediaDeviceState.STATE_CONNECTING
&& !mController.hasAdjustVolumeUserRestriction()) {
+ mProgressBar.getIndeterminateDrawable().setColorFilter(
+ new PorterDuffColorFilter(
+ mController.getColorInactiveItem(),
+ PorterDuff.Mode.SRC_IN));
setSingleLineLayout(getItemTitle(device), true /* bFocused */,
false /* showSeekBar*/,
true /* showProgressBar */, false /* showStatus */);
@@ -130,6 +139,7 @@
mTitleIcon.setAlpha(DEVICE_CONNECTED_ALPHA);
mStatusIcon.setImageDrawable(
mContext.getDrawable(R.drawable.media_output_status_failed));
+ mStatusIcon.setColorFilter(mController.getColorInactiveItem());
setTwoLineLayout(device, false /* bFocused */,
false /* showSeekBar */, false /* showProgressBar */,
true /* showSubtitle */, true /* showStatus */);
@@ -137,8 +147,7 @@
mContainerLayout.setOnClickListener(v -> onItemClick(v, device));
} else if (mController.getSelectedMediaDevice().size() > 1
&& isDeviceIncluded(mController.getSelectedMediaDevice(), device)) {
- mTitleText.setTextColor(Utils.getColorStateListDefaultColor(mContext,
- R.color.media_dialog_active_item_main_content));
+ mTitleText.setTextColor(mController.getColorActiveItem());
setSingleLineLayout(getItemTitle(device), true /* bFocused */,
true /* showSeekBar */,
false /* showProgressBar */, false /* showStatus */);
@@ -147,12 +156,13 @@
mCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
onCheckBoxClicked(false, device);
});
+ setCheckBoxColor(mCheckBox, mController.getColorActiveItem());
initSessionSeekbar();
} else if (!mController.hasAdjustVolumeUserRestriction() && currentlyConnected) {
mStatusIcon.setImageDrawable(
mContext.getDrawable(R.drawable.media_output_status_check));
- mTitleText.setTextColor(Utils.getColorStateListDefaultColor(mContext,
- R.color.media_dialog_active_item_main_content));
+ mStatusIcon.setColorFilter(mController.getColorActiveItem());
+ mTitleText.setTextColor(mController.getColorActiveItem());
setSingleLineLayout(getItemTitle(device), true /* bFocused */,
true /* showSeekBar */,
false /* showProgressBar */, true /* showStatus */);
@@ -164,6 +174,7 @@
mCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
onCheckBoxClicked(true, device);
});
+ setCheckBoxColor(mCheckBox, mController.getColorInactiveItem());
setSingleLineLayout(getItemTitle(device), false /* bFocused */,
false /* showSeekBar */,
false /* showProgressBar */, false /* showStatus */);
@@ -175,11 +186,17 @@
}
}
+ public void setCheckBoxColor(CheckBox checkBox, int color) {
+ int[][] states = {{android.R.attr.state_checked}, {}};
+ int[] colors = {color, color};
+ CompoundButtonCompat.setButtonTintList(checkBox, new
+ ColorStateList(states, colors));
+ }
+
@Override
void onBind(int customizedItem, boolean topMargin, boolean bottomMargin) {
if (customizedItem == CUSTOMIZED_ITEM_PAIR_NEW) {
- mTitleText.setTextColor(Utils.getColorStateListDefaultColor(mContext,
- R.color.media_dialog_inactive_item_main_content));
+ mTitleText.setTextColor(mController.getColorInactiveItem());
mCheckBox.setVisibility(View.GONE);
setSingleLineLayout(mContext.getText(R.string.media_output_dialog_pairing_new),
false /* bFocused */);
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
index a8d30d4..85d1795 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -18,6 +18,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.app.WallpaperColors;
import android.content.Context;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
@@ -56,7 +57,7 @@
static final int CUSTOMIZED_ITEM_GROUP = 2;
static final int CUSTOMIZED_ITEM_DYNAMIC_GROUP = 3;
- final MediaOutputController mController;
+ protected final MediaOutputController mController;
private int mMargin;
private boolean mIsAnimating;
@@ -84,6 +85,10 @@
return null;
}
+ void updateColorScheme(WallpaperColors wallpaperColors, boolean isDarkTheme) {
+ mController.setCurrentColorScheme(wallpaperColors, isDarkTheme);
+ }
+
CharSequence getItemTitle(MediaDevice device) {
return device.getName();
}
@@ -105,6 +110,10 @@
return mCurrentActivePosition;
}
+ public MediaOutputController getController() {
+ return mController;
+ }
+
/**
* ViewHolder for binding device view.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index a9e9f0f..e55b25f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -19,8 +19,14 @@
import static android.view.WindowInsets.Type.navigationBars;
import static android.view.WindowInsets.Type.statusBars;
+import android.app.WallpaperColors;
import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.ColorFilter;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -73,6 +79,7 @@
private Button mDoneButton;
private Button mStopButton;
private int mListMaxHeight;
+ private WallpaperColors mWallpaperColors;
MediaOutputBaseAdapter mAdapter;
@@ -153,10 +160,15 @@
@VisibleForTesting
void refresh() {
+ refresh(false);
+ }
+
+ void refresh(boolean deviceSetChanged) {
// Update header icon
final int iconRes = getHeaderIconRes();
final IconCompat iconCompat = getHeaderIcon();
final Drawable appSourceDrawable = getAppSourceIcon();
+ boolean colorSetUpdated = false;
if (appSourceDrawable != null) {
mAppResourceIcon.setImageDrawable(appSourceDrawable);
} else {
@@ -166,8 +178,24 @@
mHeaderIcon.setVisibility(View.VISIBLE);
mHeaderIcon.setImageResource(iconRes);
} else if (iconCompat != null) {
+ Icon icon = iconCompat.toIcon(mContext);
+ Configuration config = mContext.getResources().getConfiguration();
+ int currentNightMode = config.uiMode & Configuration.UI_MODE_NIGHT_MASK;
+ boolean isDarkThemeOn = currentNightMode == Configuration.UI_MODE_NIGHT_YES;
+ WallpaperColors wallpaperColors = WallpaperColors.fromBitmap(icon.getBitmap());
+ colorSetUpdated = !wallpaperColors.equals(mWallpaperColors);
+ if (colorSetUpdated) {
+ mAdapter.updateColorScheme(wallpaperColors, isDarkThemeOn);
+ ColorFilter buttonColorFilter = new PorterDuffColorFilter(
+ mAdapter.getController().getColorButtonBackground(),
+ PorterDuff.Mode.SRC_IN);
+ ColorFilter onlineButtonColorFilter = new PorterDuffColorFilter(
+ mAdapter.getController().getColorInactiveItem(), PorterDuff.Mode.SRC_IN);
+ mDoneButton.getBackground().setColorFilter(buttonColorFilter);
+ mStopButton.getBackground().setColorFilter(onlineButtonColorFilter);
+ }
mHeaderIcon.setVisibility(View.VISIBLE);
- mHeaderIcon.setImageIcon(iconCompat.toIcon(mContext));
+ mHeaderIcon.setImageIcon(icon);
} else {
mHeaderIcon.setVisibility(View.GONE);
}
@@ -190,7 +218,8 @@
}
if (!mAdapter.isDragging() && !mAdapter.isAnimating()) {
int currentActivePosition = mAdapter.getCurrentActivePosition();
- if (currentActivePosition >= 0 && currentActivePosition < mAdapter.getItemCount()) {
+ if (!colorSetUpdated && !deviceSetChanged && currentActivePosition >= 0
+ && currentActivePosition < mAdapter.getItemCount()) {
mAdapter.notifyItemChanged(currentActivePosition);
} else {
mAdapter.notifyDataSetChanged();
@@ -232,6 +261,11 @@
}
@Override
+ public void onDeviceListChanged() {
+ mMainThreadHandler.post(() -> refresh(true));
+ }
+
+ @Override
public void dismissDialog() {
dismiss();
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 2caecf2..1c6b7dc 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -19,10 +19,10 @@
import static android.provider.Settings.ACTION_BLUETOOTH_PAIRING_SETTINGS;
import android.app.Notification;
+import android.app.WallpaperColors;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
@@ -57,6 +57,7 @@
import com.android.settingslib.utils.ThreadUtils;
import com.android.systemui.R;
import com.android.systemui.animation.DialogLaunchAnimator;
+import com.android.systemui.monet.ColorScheme;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
@@ -103,6 +104,11 @@
private MediaOutputMetricLogger mMetricLogger;
private UiEventLogger mUiEventLogger;
+ private int mColorActiveItem;
+ private int mColorInactiveItem;
+ private int mColorSeekbarProgress;
+ private int mColorButtonBackground;
+
@Inject
public MediaOutputController(@NonNull Context context, String packageName,
boolean aboveStatusbar, MediaSessionManager mediaSessionManager, LocalBluetoothManager
@@ -125,6 +131,14 @@
mVolumeAdjustmentForRemoteGroupSessions = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions);
mDialogManager = dialogManager;
+ mColorActiveItem = Utils.getColorStateListDefaultColor(mContext,
+ R.color.media_dialog_active_item_main_content);
+ mColorInactiveItem = Utils.getColorStateListDefaultColor(mContext,
+ R.color.media_dialog_inactive_item_main_content);
+ mColorSeekbarProgress = Utils.getColorStateListDefaultColor(mContext,
+ android.R.color.system_accent1_200);
+ mColorButtonBackground = Utils.getColorStateListDefaultColor(mContext,
+ R.color.media_dialog_item_background);
}
void start(@NonNull Callback cb) {
@@ -171,7 +185,7 @@
@Override
public void onDeviceListUpdate(List<MediaDevice> devices) {
buildMediaDevices(devices);
- mCallback.onRouteChanged();
+ mCallback.onDeviceListChanged();
}
@Override
@@ -264,13 +278,8 @@
}
void setColorFilter(Drawable drawable, boolean isActive) {
- final ColorStateList list =
- mContext.getResources().getColorStateList(
- isActive
- ? R.color.media_dialog_active_item_main_content
- : R.color.media_dialog_inactive_item_main_content,
- mContext.getTheme());
- drawable.setColorFilter(new PorterDuffColorFilter(list.getDefaultColor(),
+ drawable.setColorFilter(new PorterDuffColorFilter(isActive
+ ? mColorActiveItem : mColorInactiveItem,
PorterDuff.Mode.SRC_IN));
}
@@ -301,6 +310,38 @@
return null;
}
+ void setCurrentColorScheme(WallpaperColors wallpaperColors, boolean isDarkTheme) {
+ ColorScheme mCurrentColorScheme = new ColorScheme(wallpaperColors,
+ isDarkTheme);
+ if (isDarkTheme) {
+ mColorActiveItem = mCurrentColorScheme.getNeutral1().get(10);
+ mColorInactiveItem = mCurrentColorScheme.getAccent1().get(2);
+ mColorSeekbarProgress = mCurrentColorScheme.getAccent1().get(3);
+ mColorButtonBackground = mCurrentColorScheme.getAccent1().get(2);
+ } else {
+ mColorActiveItem = mCurrentColorScheme.getNeutral1().get(10);
+ mColorInactiveItem = mCurrentColorScheme.getAccent1().get(7);
+ mColorSeekbarProgress = mCurrentColorScheme.getAccent1().get(3);
+ mColorButtonBackground = mCurrentColorScheme.getAccent2().get(1);
+ }
+ }
+
+ public int getColorActiveItem() {
+ return mColorActiveItem;
+ }
+
+ public int getColorInactiveItem() {
+ return mColorInactiveItem;
+ }
+
+ public int getColorSeekbarProgress() {
+ return mColorSeekbarProgress;
+ }
+
+ public int getColorButtonBackground() {
+ return mColorButtonBackground;
+ }
+
private void buildMediaDevices(List<MediaDevice> devices) {
// For the first time building list, to make sure the top device is the connected device.
if (mMediaDevices.isEmpty()) {
@@ -570,11 +611,16 @@
void onMediaStoppedOrPaused();
/**
- * Override to handle the device updating.
+ * Override to handle the device status or attributes updating.
*/
void onRouteChanged();
/**
+ * Override to handle the devices set updating.
+ */
+ void onDeviceListChanged();
+
+ /**
* Override to dismiss dialog.
*/
void dismissDialog();
diff --git a/packages/SystemUI/src/com/android/systemui/media/dream/dagger/MediaComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/media/dream/dagger/MediaComplicationComponent.java
index 3372899..3408d97 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dream/dagger/MediaComplicationComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dream/dagger/MediaComplicationComponent.java
@@ -90,9 +90,9 @@
static ComplicationLayoutParams provideLayoutParams() {
return new ComplicationLayoutParams(0,
ViewGroup.LayoutParams.WRAP_CONTENT,
- ComplicationLayoutParams.POSITION_BOTTOM
- | ComplicationLayoutParams.POSITION_END,
- ComplicationLayoutParams.DIRECTION_UP,
+ ComplicationLayoutParams.POSITION_TOP
+ | ComplicationLayoutParams.POSITION_START,
+ ComplicationLayoutParams.DIRECTION_DOWN,
0,
true);
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionCli.kt b/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionCli.kt
new file mode 100644
index 0000000..2ae3a63
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionCli.kt
@@ -0,0 +1,75 @@
+/*
+ * 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.systemui.media.muteawait
+
+import android.content.Context
+import android.media.AudioAttributes.USAGE_MEDIA
+import android.media.AudioDeviceAttributes
+import android.media.AudioManager
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.commandline.Command
+import com.android.systemui.statusbar.commandline.CommandRegistry
+import java.io.PrintWriter
+import java.util.concurrent.TimeUnit
+import javax.inject.Inject
+
+/** A command line interface to manually test [MediaMuteAwaitConnectionManager]. */
+@SysUISingleton
+class MediaMuteAwaitConnectionCli @Inject constructor(
+ commandRegistry: CommandRegistry,
+ private val context: Context
+) {
+ init {
+ commandRegistry.registerCommand(MEDIA_MUTE_AWAIT_COMMAND) { MuteAwaitCommand() }
+ }
+
+ inner class MuteAwaitCommand : Command {
+ override fun execute(pw: PrintWriter, args: List<String>) {
+ val device = AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_OUTPUT,
+ /* type= */ Integer.parseInt(args[0]),
+ ADDRESS,
+ /* name= */ args[1],
+ listOf(),
+ listOf(),
+ )
+ val startOrCancel = args[2]
+
+ val audioManager: AudioManager =
+ context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
+ when (startOrCancel) {
+ START ->
+ audioManager.muteAwaitConnection(
+ intArrayOf(USAGE_MEDIA), device, TIMEOUT, TIMEOUT_UNITS
+ )
+ CANCEL -> audioManager.cancelMuteAwaitConnection(device)
+ else -> pw.println("Must specify `$START` or `$CANCEL`; was $startOrCancel")
+ }
+ }
+ override fun help(pw: PrintWriter) {
+ pw.println("Usage: adb shell cmd statusbar $MEDIA_MUTE_AWAIT_COMMAND " +
+ "[type] [name] [$START|$CANCEL]")
+ }
+ }
+}
+
+private const val MEDIA_MUTE_AWAIT_COMMAND = "media-mute-await"
+private const val START = "start"
+private const val CANCEL = "cancel"
+private const val ADDRESS = "address"
+private const val TIMEOUT = 5L
+private val TIMEOUT_UNITS = TimeUnit.SECONDS
diff --git a/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManager.kt b/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManager.kt
new file mode 100644
index 0000000..22bc557
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManager.kt
@@ -0,0 +1,93 @@
+/*
+ * 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.systemui.media.muteawait
+
+import android.content.Context
+import android.graphics.drawable.Drawable
+import android.media.AudioAttributes.USAGE_MEDIA
+import android.media.AudioDeviceAttributes
+import android.media.AudioManager
+import com.android.settingslib.media.DeviceIconUtil
+import com.android.settingslib.media.LocalMediaManager
+import com.android.systemui.dagger.qualifiers.Main
+import java.util.concurrent.Executor
+
+/**
+ * A class responsible for keeping track of devices that have muted audio playback until the device
+ * is connected. The device connection expected to happen imminently, so we'd like to display the
+ * device name in the media player. When the about-to-connect device changes, [localMediaManager]
+ * will be notified.
+ *
+ * See [AudioManager.muteAwaitConnection] and b/206614671 for more details.
+ *
+ * TODO(b/206614671): Add logging.
+ */
+class MediaMuteAwaitConnectionManager constructor(
+ @Main private val mainExecutor: Executor,
+ private val localMediaManager: LocalMediaManager,
+ private val context: Context,
+ private val deviceIconUtil: DeviceIconUtil
+) {
+ var currentMutedDevice: AudioDeviceAttributes? = null
+
+ val audioManager: AudioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
+
+ val muteAwaitConnectionChangeListener = object : AudioManager.MuteAwaitConnectionCallback() {
+ override fun onMutedUntilConnection(device: AudioDeviceAttributes, mutedUsages: IntArray) {
+ if (USAGE_MEDIA in mutedUsages) {
+ // There should only be one device that's mutedUntilConnection at a time, so we can
+ // safely override any previous value.
+ currentMutedDevice = device
+ localMediaManager.dispatchAboutToConnectDeviceChanged(device.name, device.getIcon())
+ }
+ }
+
+ override fun onUnmutedEvent(
+ @UnmuteEvent unmuteEvent: Int,
+ device: AudioDeviceAttributes,
+ mutedUsages: IntArray
+ ) {
+ if (currentMutedDevice == device && USAGE_MEDIA in mutedUsages) {
+ currentMutedDevice = null
+ localMediaManager.dispatchAboutToConnectDeviceChanged(null, null)
+ }
+ }
+ }
+
+ /** Start listening for mute await events. */
+ fun startListening() {
+ audioManager.registerMuteAwaitConnectionCallback(
+ mainExecutor, muteAwaitConnectionChangeListener
+ )
+ val currentDevice = audioManager.mutingExpectedDevice
+ if (currentDevice != null) {
+ currentMutedDevice = currentDevice
+ localMediaManager.dispatchAboutToConnectDeviceChanged(
+ currentDevice.name, currentDevice.getIcon()
+ )
+ }
+ }
+
+ /** Stop listening for mute await events. */
+ fun stopListening() {
+ audioManager.unregisterMuteAwaitConnectionCallback(muteAwaitConnectionChangeListener)
+ }
+
+ private fun AudioDeviceAttributes.getIcon(): Drawable {
+ return deviceIconUtil.getIconFromAudioDeviceType(this.type, context)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerFactory.kt b/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerFactory.kt
new file mode 100644
index 0000000..118b2dd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerFactory.kt
@@ -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.systemui.media.muteawait
+
+import android.content.Context
+import com.android.settingslib.media.DeviceIconUtil
+import com.android.settingslib.media.LocalMediaManager
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.media.MediaFlags
+import java.util.concurrent.Executor
+import javax.inject.Inject
+
+/** Factory class to create [MediaMuteAwaitConnectionManager] instances. */
+@SysUISingleton
+class MediaMuteAwaitConnectionManagerFactory @Inject constructor(
+ private val mediaFlags: MediaFlags,
+ private val context: Context,
+ @Main private val mainExecutor: Executor
+) {
+ private val deviceIconUtil = DeviceIconUtil()
+
+ /** Creates a [MediaMuteAwaitConnectionManager]. */
+ fun create(localMediaManager: LocalMediaManager): MediaMuteAwaitConnectionManager? {
+ if (!mediaFlags.areMuteAwaitConnectionsEnabled()) {
+ return null
+ }
+ return MediaMuteAwaitConnectionManager(
+ mainExecutor, localMediaManager, context, deviceIconUtil
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
index 26f31cd..9dd8222 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
@@ -78,6 +78,7 @@
override fun execute(pw: PrintWriter, args: List<String>) {
val routeInfo = MediaRoute2Info.Builder("id", args[0])
.addFeature("feature")
+ .setPackageName(TEST_PACKAGE_NAME)
.build()
val commandName = args[1]
@@ -137,16 +138,25 @@
override fun execute(pw: PrintWriter, args: List<String>) {
val statusBarManager = context.getSystemService(Context.STATUS_BAR_SERVICE)
as StatusBarManager
+ val routeInfo = MediaRoute2Info.Builder("id", "Test Name")
+ .addFeature("feature")
+ .setPackageName(TEST_PACKAGE_NAME)
+ .build()
+
when(val commandName = args[0]) {
CLOSE_TO_SENDER_STATE ->
statusBarManager.updateMediaTapToTransferReceiverDisplay(
StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER,
- routeInfo
+ routeInfo,
+ null,
+ null
)
FAR_FROM_SENDER_STATE ->
statusBarManager.updateMediaTapToTransferReceiverDisplay(
StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER,
- routeInfo
+ routeInfo,
+ null,
+ null
)
else ->
pw.println("Invalid command name $commandName")
@@ -170,7 +180,4 @@
@VisibleForTesting
const val FAR_FROM_SENDER_STATE = "FarFromSender"
private const val CLI_TAG = "MediaTransferCli"
-
-private val routeInfo = MediaRoute2Info.Builder("id", "Test Name")
- .addFeature("feature")
- .build()
\ No newline at end of file
+private const val TEST_PACKAGE_NAME = "com.android.systemui"
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
index adae07b..4993105 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
@@ -22,6 +22,7 @@
import android.graphics.PixelFormat
import android.view.Gravity
import android.view.LayoutInflater
+import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import com.android.internal.widget.CachingIconView
@@ -35,7 +36,7 @@
* gets displayed to the user.
*/
abstract class MediaTttChipControllerCommon<T : MediaTttChipState>(
- private val context: Context,
+ internal val context: Context,
private val windowManager: WindowManager,
@LayoutRes private val chipLayoutRes: Int
) {
@@ -47,7 +48,7 @@
gravity = Gravity.TOP.or(Gravity.CENTER_HORIZONTAL)
type = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY
flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- title = "Media Tap-To-Transfer Chip View"
+ title = WINDOW_TITLE
format = PixelFormat.TRANSLUCENT
setTrustedOverlay()
}
@@ -100,9 +101,20 @@
* This is in the common superclass since both the sender and the receiver show an icon.
*/
internal fun setIcon(chipState: T, currentChipView: ViewGroup) {
- currentChipView.findViewById<CachingIconView>(R.id.app_icon).apply {
- this.setImageDrawable(chipState.appIconDrawable)
- this.contentDescription = chipState.appIconContentDescription
+ val appIconView = currentChipView.requireViewById<CachingIconView>(R.id.app_icon)
+ appIconView.contentDescription = chipState.getAppName(context)
+
+ val appIcon = chipState.getAppIcon(context)
+ val visibility = if (appIcon != null) {
+ View.VISIBLE
+ } else {
+ View.GONE
}
+ appIconView.setImageDrawable(appIcon)
+ appIconView.visibility = visibility
}
}
+
+// Used in CTS tests UpdateMediaTapToTransferSenderDisplayTest and
+// UpdateMediaTapToTransferReceiverDisplayTest
+private const val WINDOW_TITLE = "Media Transfer Chip View"
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipState.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipState.kt
index c510cbb..2da48ce 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipState.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipState.kt
@@ -16,15 +16,42 @@
package com.android.systemui.media.taptotransfer.common
+import android.content.Context
+import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
+import android.util.Log
/**
* A superclass chip state that will be subclassed by the sender chip and receiver chip.
*
- * @property appIconDrawable a drawable representing the icon of the app playing the media.
- * @property appIconContentDescription a string to use as the content description for the icon.
+ * @property appPackageName the package name of the app playing the media. Will be used to fetch the
+ * app icon and app name.
*/
open class MediaTttChipState(
- internal val appIconDrawable: Drawable,
- internal val appIconContentDescription: String
-)
+ internal val appPackageName: String?,
+) {
+ open fun getAppIcon(context: Context): Drawable? {
+ appPackageName ?: return null
+ return try {
+ context.packageManager.getApplicationIcon(appPackageName)
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.w(TAG, "Cannot find icon for package $appPackageName", e)
+ null
+ }
+ }
+
+ /** Returns the name of the app playing the media or null if we can't find it. */
+ open fun getAppName(context: Context): String? {
+ appPackageName ?: return null
+ return try {
+ context.packageManager.getApplicationInfo(
+ appPackageName, PackageManager.ApplicationInfoFlags.of(0)
+ ).loadLabel(context.packageManager).toString()
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.w(TAG, "Cannot find name for package $appPackageName", e)
+ null
+ }
+ }
+}
+
+private val TAG = MediaTttChipState::class.simpleName!!
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt
index df6b934..6a4b62a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt
@@ -16,14 +16,35 @@
package com.android.systemui.media.taptotransfer.receiver
+import android.content.Context
import android.graphics.drawable.Drawable
import com.android.systemui.media.taptotransfer.common.MediaTttChipState
/**
* A class that stores all the information necessary to display the media tap-to-transfer chip on
* the receiver device.
+ *
+ * @property appIconDrawable a drawable representing the icon of the app playing the media. If
+ * present, this will be used in [this.getAppIcon] instead of [appPackageName].
+ * @property appName a name for the app playing the media. If present, this will be used in
+ * [this.getAppName] instead of [appPackageName].
*/
class ChipStateReceiver(
- appIconDrawable: Drawable,
- appIconContentDescription: String
-) : MediaTttChipState(appIconDrawable, appIconContentDescription)
+ appPackageName: String?,
+ private val appIconDrawable: Drawable?,
+ private val appName: CharSequence?
+) : MediaTttChipState(appPackageName) {
+ override fun getAppIcon(context: Context): Drawable? {
+ if (appIconDrawable != null) {
+ return appIconDrawable
+ }
+ return super.getAppIcon(context)
+ }
+
+ override fun getAppName(context: Context): String? {
+ if (appName != null) {
+ return appName.toString()
+ }
+ return super.getAppName(context)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
index 2d3ca5f..18623c0 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
@@ -18,14 +18,17 @@
import android.app.StatusBarManager
import android.content.Context
-import android.graphics.Color
+import android.graphics.drawable.Drawable
import android.graphics.drawable.Icon
import android.media.MediaRoute2Info
+import android.os.Handler
import android.util.Log
import android.view.ViewGroup
import android.view.WindowManager
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon
import com.android.systemui.statusbar.CommandQueue
import javax.inject.Inject
@@ -40,22 +43,19 @@
commandQueue: CommandQueue,
context: Context,
windowManager: WindowManager,
+ @Main private val mainHandler: Handler,
) : MediaTttChipControllerCommon<ChipStateReceiver>(
context, windowManager, R.layout.media_ttt_chip_receiver
) {
- // TODO(b/216141279): Use app icon from media route info instead of this fake one.
- private val fakeAppIconDrawable =
- Icon.createWithResource(context, R.drawable.ic_avatar_user).loadDrawable(context).also {
- it.setTint(Color.YELLOW)
- }
-
private val commandQueueCallbacks = object : CommandQueue.Callbacks {
override fun updateMediaTapToTransferReceiverDisplay(
@StatusBarManager.MediaTransferReceiverState displayState: Int,
- routeInfo: MediaRoute2Info
+ routeInfo: MediaRoute2Info,
+ appIcon: Icon?,
+ appName: CharSequence?
) {
this@MediaTttChipControllerReceiver.updateMediaTapToTransferReceiverDisplay(
- displayState, routeInfo
+ displayState, routeInfo, appIcon, appName
)
}
}
@@ -66,11 +66,28 @@
private fun updateMediaTapToTransferReceiverDisplay(
@StatusBarManager.MediaTransferReceiverState displayState: Int,
- routeInfo: MediaRoute2Info
+ routeInfo: MediaRoute2Info,
+ appIcon: Icon?,
+ appName: CharSequence?
) {
when(displayState) {
- StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER ->
- displayChip(ChipStateReceiver(fakeAppIconDrawable, routeInfo.name.toString()))
+ StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER -> {
+ val packageName = routeInfo.packageName
+ if (appIcon == null) {
+ displayChip(ChipStateReceiver(packageName, null, appName))
+ } else {
+ appIcon.loadDrawableAsync(
+ context,
+ Icon.OnDrawableLoadedListener { drawable ->
+ displayChip(
+ ChipStateReceiver(packageName, drawable, appName)
+ )},
+ // Notify the listener on the main handler since the listener will update
+ // the UI.
+ mainHandler
+ )
+ }
+ }
StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER -> removeChip()
else ->
Log.e(RECEIVER_TAG, "Unhandled MediaTransferReceiverState $displayState")
@@ -82,4 +99,4 @@
}
}
-private const val RECEIVER_TAG = "MediaTapToTransferReceiver"
+private const val RECEIVER_TAG = "MediaTapToTransferRcvr"
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
index 05baf78..9b537fb 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
@@ -17,7 +17,6 @@
package com.android.systemui.media.taptotransfer.sender
import android.content.Context
-import android.graphics.drawable.Drawable
import android.view.View
import com.android.internal.statusbar.IUndoMediaTransferCallback
import com.android.systemui.R
@@ -31,9 +30,8 @@
* contain additional information that is necessary for only that state.
*/
sealed class ChipStateSender(
- appIconDrawable: Drawable,
- appIconContentDescription: String
-) : MediaTttChipState(appIconDrawable, appIconContentDescription) {
+ appPackageName: String?
+) : MediaTttChipState(appPackageName) {
/** Returns a fully-formed string with the text that the chip should display. */
abstract fun getChipTextString(context: Context): String
@@ -60,10 +58,9 @@
* @property otherDeviceName the name of the other device involved in the transfer.
*/
class AlmostCloseToStartCast(
- appIconDrawable: Drawable,
- appIconContentDescription: String,
+ appPackageName: String?,
private val otherDeviceName: String,
-) : ChipStateSender(appIconDrawable, appIconContentDescription) {
+) : ChipStateSender(appPackageName) {
override fun getChipTextString(context: Context): String {
return context.getString(R.string.media_move_closer_to_start_cast, otherDeviceName)
}
@@ -77,10 +74,9 @@
* @property otherDeviceName the name of the other device involved in the transfer.
*/
class AlmostCloseToEndCast(
- appIconDrawable: Drawable,
- appIconContentDescription: String,
+ appPackageName: String?,
private val otherDeviceName: String,
-) : ChipStateSender(appIconDrawable, appIconContentDescription) {
+) : ChipStateSender(appPackageName) {
override fun getChipTextString(context: Context): String {
return context.getString(R.string.media_move_closer_to_end_cast, otherDeviceName)
}
@@ -93,10 +89,9 @@
* @property otherDeviceName the name of the other device involved in the transfer.
*/
class TransferToReceiverTriggered(
- appIconDrawable: Drawable,
- appIconContentDescription: String,
+ appPackageName: String?,
private val otherDeviceName: String
-) : ChipStateSender(appIconDrawable, appIconContentDescription) {
+) : ChipStateSender(appPackageName) {
override fun getChipTextString(context: Context): String {
return context.getString(R.string.media_transfer_playing_different_device, otherDeviceName)
}
@@ -109,9 +104,8 @@
* sender) has been initiated (but not completed).
*/
class TransferToThisDeviceTriggered(
- appIconDrawable: Drawable,
- appIconContentDescription: String
-) : ChipStateSender(appIconDrawable, appIconContentDescription) {
+ appPackageName: String?,
+) : ChipStateSender(appPackageName) {
override fun getChipTextString(context: Context): String {
return context.getString(R.string.media_transfer_playing_this_device)
}
@@ -127,11 +121,10 @@
* undo button. The undo button will only be shown if this is non-null.
*/
class TransferToReceiverSucceeded(
- appIconDrawable: Drawable,
- appIconContentDescription: String,
+ appPackageName: String?,
private val otherDeviceName: String,
val undoCallback: IUndoMediaTransferCallback? = null
-) : ChipStateSender(appIconDrawable, appIconContentDescription) {
+) : ChipStateSender(appPackageName) {
override fun getChipTextString(context: Context): String {
return context.getString(R.string.media_transfer_playing_different_device, otherDeviceName)
}
@@ -149,10 +142,7 @@
// but that may take too long to go through the binder and the user may be confused as
// to why the UI hasn't changed yet. So, we immediately change the UI here.
controllerSender.displayChip(
- TransferToThisDeviceTriggered(
- this.appIconDrawable,
- this.appIconContentDescription
- )
+ TransferToThisDeviceTriggered(this.appPackageName)
)
}
}
@@ -166,11 +156,10 @@
* undo button. The undo button will only be shown if this is non-null.
*/
class TransferToThisDeviceSucceeded(
- appIconDrawable: Drawable,
- appIconContentDescription: String,
+ appPackageName: String?,
private val otherDeviceName: String,
val undoCallback: IUndoMediaTransferCallback? = null
-) : ChipStateSender(appIconDrawable, appIconContentDescription) {
+) : ChipStateSender(appPackageName) {
override fun getChipTextString(context: Context): String {
return context.getString(R.string.media_transfer_playing_this_device)
}
@@ -189,8 +178,7 @@
// to why the UI hasn't changed yet. So, we immediately change the UI here.
controllerSender.displayChip(
TransferToReceiverTriggered(
- this.appIconDrawable,
- this.appIconContentDescription,
+ this.appPackageName,
this.otherDeviceName
)
)
@@ -200,9 +188,8 @@
/** A state representing that a transfer has failed. */
class TransferFailed(
- appIconDrawable: Drawable,
- appIconContentDescription: String
-) : ChipStateSender(appIconDrawable, appIconContentDescription) {
+ appPackageName: String?,
+) : ChipStateSender(appPackageName) {
override fun getChipTextString(context: Context): String {
return context.getString(R.string.media_transfer_failed)
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
index d1790d2..da767ea 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
@@ -18,8 +18,6 @@
import android.app.StatusBarManager
import android.content.Context
-import android.graphics.Color
-import android.graphics.drawable.Icon
import android.media.MediaRoute2Info
import android.util.Log
import android.view.View
@@ -45,12 +43,6 @@
) : MediaTttChipControllerCommon<ChipStateSender>(
context, windowManager, R.layout.media_ttt_chip
) {
- // TODO(b/216141276): Use app icon from media route info instead of this fake one.
- private val fakeAppIconDrawable =
- Icon.createWithResource(context, R.drawable.ic_avatar_user).loadDrawable(context).also {
- it.setTint(Color.YELLOW)
- }
-
private val commandQueueCallbacks = object : CommandQueue.Callbacks {
override fun updateMediaTapToTransferSenderDisplay(
@StatusBarManager.MediaTransferSenderState displayState: Int,
@@ -72,46 +64,24 @@
routeInfo: MediaRoute2Info,
undoCallback: IUndoMediaTransferCallback?
) {
- // TODO(b/217418566): This app icon content description is incorrect --
- // routeInfo.name is the name of the device, not the name of the app.
- val appIconContentDescription = routeInfo.name.toString()
+ val appPackageName = routeInfo.packageName
val otherDeviceName = routeInfo.name.toString()
val chipState = when(displayState) {
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST ->
- AlmostCloseToStartCast(
- fakeAppIconDrawable, appIconContentDescription, otherDeviceName
- )
+ AlmostCloseToStartCast(appPackageName, otherDeviceName)
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST ->
- AlmostCloseToEndCast(
- fakeAppIconDrawable, appIconContentDescription, otherDeviceName
- )
+ AlmostCloseToEndCast(appPackageName, otherDeviceName)
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED ->
- TransferToReceiverTriggered(
- fakeAppIconDrawable, appIconContentDescription, otherDeviceName
- )
+ TransferToReceiverTriggered(appPackageName, otherDeviceName)
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED ->
- TransferToThisDeviceTriggered(
- fakeAppIconDrawable, appIconContentDescription
- )
+ TransferToThisDeviceTriggered(appPackageName)
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED ->
- TransferToReceiverSucceeded(
- fakeAppIconDrawable,
- appIconContentDescription,
- otherDeviceName,
- undoCallback
- )
+ TransferToReceiverSucceeded(appPackageName, otherDeviceName, undoCallback)
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED ->
- TransferToThisDeviceSucceeded(
- fakeAppIconDrawable,
- appIconContentDescription,
- otherDeviceName,
- undoCallback
- )
+ TransferToThisDeviceSucceeded(appPackageName, otherDeviceName, undoCallback)
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED,
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED ->
- TransferFailed(
- fakeAppIconDrawable, appIconContentDescription
- )
+ TransferFailed(appPackageName)
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER -> {
removeChip()
null
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index 98b49b1..aa1117c 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -31,6 +31,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
+import android.os.Trace;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
@@ -215,9 +216,11 @@
/** @return {@code true} if taskbar is enabled, false otherwise */
private boolean initializeTaskbarIfNecessary() {
if (mIsTablet) {
+ Trace.beginSection("NavigationBarController#initializeTaskbarIfNecessary");
// Remove navigation bar when taskbar is showing
removeNavigationBar(mContext.getDisplayId());
mTaskbarDelegate.init(mContext.getDisplayId());
+ Trace.endSection();
} else {
mTaskbarDelegate.destroy();
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index be45a62..9199911 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -263,11 +263,14 @@
// Notify FalsingManager that an intentional gesture has occurred.
// TODO(b/186519446): use a different method than isFalseTouch
mFalsingManager.isFalseTouch(BACK_GESTURE);
- boolean sendDown = sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
- boolean sendUp = sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK);
- if (DEBUG_MISSING_GESTURE) {
- Log.d(DEBUG_MISSING_GESTURE_TAG, "Triggered back: down=" + sendDown
- + ", up=" + sendUp);
+ // Only inject back keycodes when ahead-of-time back dispatching is disabled.
+ if (mBackAnimation == null) {
+ boolean sendDown = sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
+ boolean sendUp = sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK);
+ if (DEBUG_MISSING_GESTURE) {
+ Log.d(DEBUG_MISSING_GESTURE_TAG, "Triggered back: down="
+ + sendDown + ", up=" + sendUp);
+ }
}
mOverviewProxyService.notifyBackAction(true, (int) mDownPoint.x,
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
index c18209d..a6bad15 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
@@ -43,6 +43,7 @@
import android.view.WindowManager;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
+import android.window.BackEvent;
import androidx.core.graphics.ColorUtils;
import androidx.dynamicanimation.animation.DynamicAnimation;
@@ -161,7 +162,8 @@
// The amount the arrow is shifted to avoid the finger.
private int mFingerOffset;
- private final float mSwipeThreshold;
+ private final float mSwipeTriggerThreshold;
+ private final float mSwipeProgressThreshold;
private final Path mArrowPath = new Path();
private final Point mDisplaySize = new Point();
@@ -351,10 +353,15 @@
loadColors(context);
updateArrowDirection();
- mSwipeThreshold = context.getResources()
+ mSwipeTriggerThreshold = context.getResources()
.getDimension(R.dimen.navigation_edge_action_drag_threshold);
- setVisibility(GONE);
+ mSwipeProgressThreshold = context.getResources()
+ .getDimension(R.dimen.navigation_edge_action_progress_threshold);
+ if (mBackAnimation != null) {
+ mBackAnimation.setSwipeThresholds(mSwipeTriggerThreshold, mSwipeProgressThreshold);
+ }
+ setVisibility(GONE);
Executor backgroundExecutor = Dependency.get(Dependency.BACKGROUND_EXECUTOR);
boolean isPrimaryDisplay = mContext.getDisplayId() == DEFAULT_DISPLAY;
mRegionSamplingHelper = new RegionSamplingHelper(this,
@@ -464,7 +471,8 @@
@Override
public void onMotionEvent(MotionEvent event) {
if (mBackAnimation != null) {
- mBackAnimation.onBackMotion(event);
+ mBackAnimation.onBackMotion(
+ event, mIsLeftPanel ? BackEvent.EDGE_LEFT : BackEvent.EDGE_RIGHT);
}
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
@@ -728,7 +736,7 @@
mPreviousTouchTranslation = touchTranslation;
// Apply a haptic on drag slop passed
- if (!mDragSlopPassed && touchTranslation > mSwipeThreshold) {
+ if (!mDragSlopPassed && touchTranslation > mSwipeTriggerThreshold) {
mDragSlopPassed = true;
mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
mVibrationTime = SystemClock.uptimeMillis();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/AutoSizingList.java b/packages/SystemUI/src/com/android/systemui/qs/AutoSizingList.java
deleted file mode 100644
index 18d28bf..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/AutoSizingList.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2016 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.qs;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.database.DataSetObserver;
-import android.os.Handler;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.LinearLayout;
-import android.widget.ListAdapter;
-
-import com.android.systemui.R;
-
-/**
- * Similar to a ListView, but it will show only as many items as fit on screen and
- * bind those instead of scrolling.
- */
-public class AutoSizingList extends LinearLayout {
-
- private static final String TAG = "AutoSizingList";
- private final int mItemSize;
- private final Handler mHandler;
-
- @Nullable
- private ListAdapter mAdapter;
- private int mCount;
- private boolean mEnableAutoSizing;
-
- public AutoSizingList(Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
-
- mHandler = new Handler();
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AutoSizingList);
- mItemSize = a.getDimensionPixelSize(R.styleable.AutoSizingList_itemHeight, 0);
- mEnableAutoSizing = a.getBoolean(R.styleable.AutoSizingList_enableAutoSizing, true);
- a.recycle();
- }
-
- public void setAdapter(ListAdapter adapter) {
- if (mAdapter != null) {
- mAdapter.unregisterDataSetObserver(mDataObserver);
- }
- mAdapter = adapter;
- if (adapter != null) {
- adapter.registerDataSetObserver(mDataObserver);
- }
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int requestedHeight = MeasureSpec.getSize(heightMeasureSpec);
- if (requestedHeight != 0) {
- int count = getItemCount(requestedHeight);
- if (mCount != count) {
- postRebindChildren();
- mCount = count;
- }
- }
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
-
- private int getItemCount(int requestedHeight) {
- int desiredCount = getDesiredCount();
- return mEnableAutoSizing ? Math.min(requestedHeight / mItemSize, desiredCount)
- : desiredCount;
- }
-
- private int getDesiredCount() {
- return mAdapter != null ? mAdapter.getCount() : 0;
- }
-
- private void postRebindChildren() {
- mHandler.post(mBindChildren);
- }
-
- private void rebindChildren() {
- if (mAdapter == null) {
- return;
- }
- for (int i = 0; i < mCount; i++) {
- View v = i < getChildCount() ? getChildAt(i) : null;
- View newView = mAdapter.getView(i, v, this);
- if (newView != v) {
- if (v != null) {
- removeView(v);
- }
- addView(newView, i);
- }
- }
- // Ditch extra views.
- while (getChildCount() > mCount) {
- removeViewAt(getChildCount() - 1);
- }
- }
-
- private final Runnable mBindChildren = new Runnable() {
- @Override
- public void run() {
- rebindChildren();
- }
- };
-
- private final DataSetObserver mDataObserver = new DataSetObserver() {
- @Override
- public void onChanged() {
- if (mCount > getDesiredCount()) {
- mCount = getDesiredCount();
- }
- postRebindChildren();
- }
-
- @Override
- public void onInvalidated() {
- postRebindChildren();
- }
- };
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
index bbe0a99..89735c3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
@@ -27,6 +27,7 @@
import android.provider.DeviceConfig.NAMESPACE_SYSTEMUI
import android.text.format.DateUtils
import android.util.ArrayMap
+import android.util.IndentingPrintWriter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -38,14 +39,19 @@
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.TASK_MANAGER_ENABLED
+import com.android.systemui.Dumpable
import com.android.systemui.R
import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dump.DumpManager
import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.util.DeviceConfigProxy
+import com.android.systemui.util.indentIfPossible
import com.android.systemui.util.time.SystemClock
+import java.io.FileDescriptor
+import java.io.PrintWriter
import java.util.Objects
import java.util.concurrent.Executor
import javax.inject.Inject
@@ -60,8 +66,9 @@
private val activityManager: IActivityManager,
private val packageManager: PackageManager,
private val deviceConfigProxy: DeviceConfigProxy,
- private val dialogLaunchAnimator: DialogLaunchAnimator
-) : IForegroundServiceObserver.Stub() {
+ private val dialogLaunchAnimator: DialogLaunchAnimator,
+ private val dumpManager: DumpManager
+) : IForegroundServiceObserver.Stub(), Dumpable {
companion object {
private val LOG_TAG = FgsManagerController::class.java.simpleName
@@ -116,6 +123,8 @@
isAvailable = deviceConfigProxy
.getBoolean(NAMESPACE_SYSTEMUI, TASK_MANAGER_ENABLED, true)
+ dumpManager.registerDumpable(this)
+
initialized = true
}
}
@@ -379,6 +388,16 @@
}
override fun hashCode(): Int = Objects.hash(userId, packageName)
+
+ fun dump(pw: PrintWriter) {
+ pw.println("UserPackage: [")
+ pw.indentIfPossible {
+ pw.println("userId=$userId")
+ pw.println("packageName=$packageName")
+ pw.println("uiControl=$uiControl")
+ }
+ pw.println("]")
+ }
}
private data class StartTimeAndTokens(
@@ -398,6 +417,22 @@
fun isEmpty(): Boolean {
return tokens.isEmpty()
}
+
+ fun dump(pw: PrintWriter) {
+ pw.println("StartTimeAndTokens: [")
+ pw.indentIfPossible {
+ pw.println("startTime=$startTime (time running =" +
+ " ${systemClock.elapsedRealtime() - startTime}ms)")
+ pw.println("tokens: [")
+ pw.indentIfPossible {
+ for (token in tokens) {
+ pw.println("$token")
+ }
+ }
+ pw.println("]")
+ }
+ pw.println("]")
+ }
}
private class AppItemViewHolder(parent: View) : RecyclerView.ViewHolder(parent) {
@@ -429,9 +464,54 @@
var appLabel: CharSequence = ""
var icon: Drawable? = null
var stopped = false
+
+ fun dump(pw: PrintWriter, systemClock: SystemClock) {
+ pw.println("RunningApp: [")
+ pw.indentIfPossible {
+ pw.println("userId=$userId")
+ pw.println("packageName=$packageName")
+ pw.println("timeStarted=$timeStarted (time since start =" +
+ " ${systemClock.elapsedRealtime() - timeStarted}ms)\"")
+ pw.println("uiControl=$uiControl")
+ pw.println("appLabel=$appLabel")
+ pw.println("icon=$icon")
+ pw.println("stopped=$stopped")
+ }
+ pw.println("]")
+ }
}
private enum class UIControl {
NORMAL, HIDE_BUTTON, HIDE_ENTRY
}
+
+ override fun dump(fd: FileDescriptor, printwriter: PrintWriter, args: Array<out String>) {
+ val pw = IndentingPrintWriter(printwriter)
+ synchronized(lock) {
+ pw.println("changesSinceDialog=$changesSinceDialog")
+ pw.println("Running service tokens: [")
+ pw.indentIfPossible {
+ runningServiceTokens.forEach { (userPackage, startTimeAndTokens) ->
+ pw.println("{")
+ pw.indentIfPossible {
+ userPackage.dump(pw)
+ startTimeAndTokens.dump(pw)
+ }
+ pw.println("}")
+ }
+ }
+ pw.println("]")
+
+ pw.println("Loaded package UI info: [")
+ pw.indentIfPossible {
+ runningApps.forEach { (userPackage, runningApp) ->
+ pw.println("{")
+ userPackage.dump(pw)
+ runningApp.dump(pw, systemClock)
+ pw.println("}")
+ }
+ }
+ pw.println("]")
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
index 77feb90..5df8b80 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
@@ -191,6 +191,10 @@
reformatForNewFooter(securityFooter)
val fgsFooter = fgsManagerFooterController.view
securityFootersContainer?.addView(fgsFooter)
+ (fgsFooter.layoutParams as LinearLayout.LayoutParams).apply {
+ width = 0
+ weight = 1f
+ }
val visibilityListener =
VisibilityChangedDispatcher.OnVisibilityChangedListener { visibility ->
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index 707313f..f868055 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -44,7 +44,6 @@
private final float[] mFancyClippingRadii = new float[] {0, 0, 0, 0, 0, 0, 0, 0};
private final Path mFancyClippingPath = new Path();
private int mHeightOverride = -1;
- private View mQSDetail;
private QuickStatusBarHeader mHeader;
private float mQsExpansion;
private QSCustomizer mQSCustomizer;
@@ -63,7 +62,6 @@
protected void onFinishInflate() {
super.onFinishInflate();
mQSPanelContainer = findViewById(R.id.expanded_qs_scroll_view);
- mQSDetail = findViewById(R.id.qs_detail);
mHeader = findViewById(R.id.header);
mQSCustomizer = findViewById(R.id.qs_customize);
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
@@ -175,9 +173,6 @@
int height = calculateContainerHeight();
int scrollBottom = calculateContainerBottom();
setBottom(getTop() + height);
- mQSDetail.setBottom(getTop() + scrollBottom);
- int qsDetailBottomMargin = ((MarginLayoutParams) mQSDetail.getLayoutParams()).bottomMargin;
- mQSDetail.setBottom(getTop() + scrollBottom - qsDetailBottomMargin);
}
protected int calculateContainerHeight() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
deleted file mode 100644
index 04e2252..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
+++ /dev/null
@@ -1,439 +0,0 @@
-/*
- * Copyright (C) 2016 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.qs;
-
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_MORE_SETTINGS;
-
-import android.animation.Animator;
-import android.animation.Animator.AnimatorListener;
-import android.animation.AnimatorListenerAdapter;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.drawable.Animatable;
-import android.util.AttributeSet;
-import android.util.SparseArray;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewStub;
-import android.view.WindowInsets;
-import android.view.accessibility.AccessibilityEvent;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.Switch;
-import android.widget.TextView;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.UiEventLogger;
-import com.android.internal.policy.SystemBarUtils;
-import com.android.systemui.Dependency;
-import com.android.systemui.FontSizeUtils;
-import com.android.systemui.R;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.plugins.qs.DetailAdapter;
-import com.android.systemui.plugins.qs.QSContainerController;
-import com.android.systemui.statusbar.CommandQueue;
-
-public class QSDetail extends LinearLayout {
-
- private static final String TAG = "QSDetail";
- private static final long FADE_DURATION = 300;
-
- private final SparseArray<View> mDetailViews = new SparseArray<>();
- private final UiEventLogger mUiEventLogger = QSEvents.INSTANCE.getQsUiEventsLogger();
-
- private ViewGroup mDetailContent;
- private FalsingManager mFalsingManager;
- protected TextView mDetailSettingsButton;
- protected TextView mDetailDoneButton;
- @VisibleForTesting
- QSDetailClipper mClipper;
- @Nullable
- private DetailAdapter mDetailAdapter;
- private QSPanelController mQsPanelController;
-
- protected View mQsDetailHeader;
- protected TextView mQsDetailHeaderTitle;
- private ViewStub mQsDetailHeaderSwitchStub;
- @Nullable
- private Switch mQsDetailHeaderSwitch;
- protected ImageView mQsDetailHeaderProgress;
-
- @Nullable
- protected QSTileHost mHost;
-
- private boolean mScanState;
- private boolean mClosingDetail;
- private boolean mFullyExpanded;
- private QuickStatusBarHeader mHeader;
- private boolean mTriggeredExpand;
- private boolean mShouldAnimate;
- private int mOpenX;
- private int mOpenY;
- private boolean mAnimatingOpen;
- private boolean mSwitchState;
- private QSFooter mFooter;
-
- @Nullable
- private QSContainerController mQsContainerController;
-
- public QSDetail(Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- FontSizeUtils.updateFontSize(mDetailDoneButton, R.dimen.qs_detail_button_text_size);
- FontSizeUtils.updateFontSize(mDetailSettingsButton, R.dimen.qs_detail_button_text_size);
-
- for (int i = 0; i < mDetailViews.size(); i++) {
- mDetailViews.valueAt(i).dispatchConfigurationChanged(newConfig);
- }
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mDetailContent = findViewById(android.R.id.content);
- mDetailSettingsButton = findViewById(android.R.id.button2);
- mDetailDoneButton = findViewById(android.R.id.button1);
-
- mQsDetailHeader = findViewById(R.id.qs_detail_header);
- mQsDetailHeaderTitle = (TextView) mQsDetailHeader.findViewById(android.R.id.title);
- mQsDetailHeaderSwitchStub = mQsDetailHeader.findViewById(R.id.toggle_stub);
- mQsDetailHeaderProgress = findViewById(R.id.qs_detail_header_progress);
-
- updateDetailText();
-
- mClipper = new QSDetailClipper(this);
- }
-
- public void setContainerController(QSContainerController controller) {
- mQsContainerController = controller;
- }
-
- /** */
- public void setQsPanel(QSPanelController panelController, QuickStatusBarHeader header,
- QSFooter footer, FalsingManager falsingManager) {
- mQsPanelController = panelController;
- mHeader = header;
- mFooter = footer;
- mHeader.setCallback(mQsPanelCallback);
- mQsPanelController.setCallback(mQsPanelCallback);
- mFalsingManager = falsingManager;
- }
-
- public void setHost(QSTileHost host) {
- mHost = host;
- }
- public boolean isShowingDetail() {
- return mDetailAdapter != null;
- }
-
- public void setFullyExpanded(boolean fullyExpanded) {
- mFullyExpanded = fullyExpanded;
- }
-
- public void setExpanded(boolean qsExpanded) {
- if (!qsExpanded) {
- mTriggeredExpand = false;
- }
- }
-
- private void updateDetailText() {
- int resId = mDetailAdapter != null ? mDetailAdapter.getDoneText() : Resources.ID_NULL;
- mDetailDoneButton.setText(
- (resId != Resources.ID_NULL) ? resId : R.string.quick_settings_done);
- resId = mDetailAdapter != null ? mDetailAdapter.getSettingsText() : Resources.ID_NULL;
- mDetailSettingsButton.setText(
- (resId != Resources.ID_NULL) ? resId : R.string.quick_settings_more_settings);
- }
-
- public void updateResources() {
- updateDetailText();
- MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();
- lp.topMargin = SystemBarUtils.getQuickQsOffsetHeight(mContext);
- setLayoutParams(lp);
- }
-
- @Override
- public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- int bottomNavBar = insets.getInsets(WindowInsets.Type.navigationBars()).bottom;
- MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();
- lp.bottomMargin = bottomNavBar;
- setLayoutParams(lp);
- return super.onApplyWindowInsets(insets);
- }
-
- public boolean isClosingDetail() {
- return mClosingDetail;
- }
-
- public interface Callback {
- /** Handle an event of showing detail. */
- void onShowingDetail(@Nullable DetailAdapter detail, int x, int y);
- void onToggleStateChanged(boolean state);
- void onScanStateChanged(boolean state);
- }
-
- /** Handle an event of showing detail. */
- public void handleShowingDetail(final @Nullable DetailAdapter adapter, int x, int y,
- boolean toggleQs) {
- final boolean showingDetail = adapter != null;
- final boolean wasShowingDetail = mDetailAdapter != null;
- setClickable(showingDetail);
- if (showingDetail) {
- setupDetailHeader(adapter);
- if (toggleQs && !mFullyExpanded) {
- mTriggeredExpand = true;
- Dependency.get(CommandQueue.class).animateExpandSettingsPanel(null);
- } else {
- mTriggeredExpand = false;
- }
- mShouldAnimate = adapter.shouldAnimate();
- mOpenX = x;
- mOpenY = y;
- } else {
- // Ensure we collapse into the same point we opened from.
- x = mOpenX;
- y = mOpenY;
- if (toggleQs && mTriggeredExpand) {
- Dependency.get(CommandQueue.class).animateCollapsePanels();
- mTriggeredExpand = false;
- }
- // Always animate on close, even if the last opened detail adapter had shouldAnimate()
- // return false. This is necessary to avoid a race condition which could leave the
- // keyguard in a bad state where QS remains visible underneath the notifications, clock,
- // and status area.
- mShouldAnimate = true;
- }
-
- boolean visibleDiff = wasShowingDetail != showingDetail;
- if (!visibleDiff && !wasShowingDetail) return; // already in right state
- AnimatorListener listener;
- if (showingDetail) {
- int viewCacheIndex = adapter.getMetricsCategory();
- View detailView = adapter.createDetailView(mContext, mDetailViews.get(viewCacheIndex),
- mDetailContent);
- if (detailView == null) throw new IllegalStateException("Must return detail view");
-
- setupDetailFooter(adapter);
-
- mDetailContent.removeAllViews();
- mDetailContent.addView(detailView);
- mDetailViews.put(viewCacheIndex, detailView);
- Dependency.get(MetricsLogger.class).visible(adapter.getMetricsCategory());
- mUiEventLogger.log(adapter.openDetailEvent());
- announceForAccessibility(mContext.getString(
- R.string.accessibility_quick_settings_detail,
- adapter.getTitle()));
- mDetailAdapter = adapter;
- listener = mHideGridContentWhenDone;
- setVisibility(View.VISIBLE);
- updateDetailText();
- } else {
- if (wasShowingDetail) {
- Dependency.get(MetricsLogger.class).hidden(mDetailAdapter.getMetricsCategory());
- mUiEventLogger.log(mDetailAdapter.closeDetailEvent());
- }
- mClosingDetail = true;
- mDetailAdapter = null;
- listener = mTeardownDetailWhenDone;
- // Only update visibility if already expanded. Otherwise, a race condition can cause the
- // keyguard to enter a bad state where the QS tiles are displayed underneath the
- // notifications, clock, and status area.
- if (mQsPanelController.isExpanded()) {
- mHeader.setVisibility(View.VISIBLE);
- mFooter.setVisibility(View.VISIBLE);
- mQsPanelController.setGridContentVisibility(true);
- mQsPanelCallback.onScanStateChanged(false);
- }
- }
- sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
- animateDetailVisibleDiff(x, y, visibleDiff, listener);
- if (mQsContainerController != null) {
- mQsContainerController.setDetailShowing(showingDetail);
- }
- }
-
- protected void animateDetailVisibleDiff(int x, int y, boolean visibleDiff, AnimatorListener listener) {
- if (visibleDiff) {
- mAnimatingOpen = mDetailAdapter != null;
- if (mFullyExpanded || mDetailAdapter != null) {
- setAlpha(1);
- mClipper.updateCircularClip(mShouldAnimate, x, y, mDetailAdapter != null, listener);
- } else {
- animate().alpha(0)
- .setDuration(mShouldAnimate ? FADE_DURATION : 0)
- .setListener(listener)
- .start();
- }
- }
- }
-
- protected void setupDetailFooter(DetailAdapter adapter) {
- final Intent settingsIntent = adapter.getSettingsIntent();
- mDetailSettingsButton.setVisibility(settingsIntent != null ? VISIBLE : GONE);
- mDetailSettingsButton.setOnClickListener(v -> {
- if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
- return;
- }
- Dependency.get(MetricsLogger.class).action(ACTION_QS_MORE_SETTINGS,
- adapter.getMetricsCategory());
- mUiEventLogger.log(adapter.moreSettingsEvent());
- Dependency.get(ActivityStarter.class)
- .postStartActivityDismissingKeyguard(settingsIntent, 0);
- });
- mDetailDoneButton.setOnClickListener(v -> {
- if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
- return;
- }
- announceForAccessibility(
- mContext.getString(R.string.accessibility_desc_quick_settings));
- if (!adapter.onDoneButtonClicked()) {
- mQsPanelController.closeDetail();
- }
- });
- }
-
- protected void setupDetailHeader(final DetailAdapter adapter) {
- mQsDetailHeaderTitle.setText(adapter.getTitle());
- final Boolean toggleState = adapter.getToggleState();
- if (toggleState == null) {
- if (mQsDetailHeaderSwitch != null) mQsDetailHeaderSwitch.setVisibility(INVISIBLE);
- mQsDetailHeader.setClickable(false);
- } else {
- if (mQsDetailHeaderSwitch == null) {
- mQsDetailHeaderSwitch = (Switch) mQsDetailHeaderSwitchStub.inflate();
- }
- mQsDetailHeaderSwitch.setVisibility(VISIBLE);
- handleToggleStateChanged(toggleState, adapter.getToggleEnabled());
- mQsDetailHeader.setClickable(true);
- mQsDetailHeader.setOnClickListener(v -> {
- if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
- return;
- }
- boolean checked = !mQsDetailHeaderSwitch.isChecked();
- mQsDetailHeaderSwitch.setChecked(checked);
- adapter.setToggleState(checked);
- });
- }
- }
-
- private void handleToggleStateChanged(boolean state, boolean toggleEnabled) {
- mSwitchState = state;
- if (mAnimatingOpen) {
- return;
- }
- if (mQsDetailHeaderSwitch != null) mQsDetailHeaderSwitch.setChecked(state);
- mQsDetailHeader.setEnabled(toggleEnabled);
- if (mQsDetailHeaderSwitch != null) mQsDetailHeaderSwitch.setEnabled(toggleEnabled);
- }
-
- private void handleScanStateChanged(boolean state) {
- if (mScanState == state) return;
- mScanState = state;
- final Animatable anim = (Animatable) mQsDetailHeaderProgress.getDrawable();
- if (state) {
- mQsDetailHeaderProgress.animate().cancel();
- mQsDetailHeaderProgress.animate()
- .alpha(1)
- .withEndAction(anim::start)
- .start();
- } else {
- mQsDetailHeaderProgress.animate().cancel();
- mQsDetailHeaderProgress.animate()
- .alpha(0f)
- .withEndAction(anim::stop)
- .start();
- }
- }
-
- private void checkPendingAnimations() {
- handleToggleStateChanged(mSwitchState,
- mDetailAdapter != null && mDetailAdapter.getToggleEnabled());
- }
-
- protected Callback mQsPanelCallback = new Callback() {
- @Override
- public void onToggleStateChanged(final boolean state) {
- post(new Runnable() {
- @Override
- public void run() {
- handleToggleStateChanged(state,
- mDetailAdapter != null && mDetailAdapter.getToggleEnabled());
- }
- });
- }
-
- @Override
- public void onShowingDetail(
- final @Nullable DetailAdapter detail, final int x, final int y) {
- post(new Runnable() {
- @Override
- public void run() {
- if (isAttachedToWindow()) {
- handleShowingDetail(detail, x, y, false /* toggleQs */);
- }
- }
- });
- }
-
- @Override
- public void onScanStateChanged(final boolean state) {
- post(new Runnable() {
- @Override
- public void run() {
- handleScanStateChanged(state);
- }
- });
- }
- };
-
- private final AnimatorListenerAdapter mHideGridContentWhenDone = new AnimatorListenerAdapter() {
- public void onAnimationCancel(Animator animation) {
- // If we have been cancelled, remove the listener so that onAnimationEnd doesn't get
- // called, this will avoid accidentally turning off the grid when we don't want to.
- animation.removeListener(this);
- mAnimatingOpen = false;
- checkPendingAnimations();
- };
-
- @Override
- public void onAnimationEnd(Animator animation) {
- // Only hide content if still in detail state.
- if (mDetailAdapter != null) {
- mQsPanelController.setGridContentVisibility(false);
- mHeader.setVisibility(View.INVISIBLE);
- mFooter.setVisibility(View.INVISIBLE);
- }
- mAnimatingOpen = false;
- checkPendingAnimations();
- }
- };
-
- private final AnimatorListenerAdapter mTeardownDetailWhenDone = new AnimatorListenerAdapter() {
- public void onAnimationEnd(Animator animation) {
- mDetailContent.removeAllViews();
- setVisibility(View.INVISIBLE);
- mClosingDetail = false;
- };
- };
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
index 43136d3..b02efba 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
@@ -25,7 +25,7 @@
import androidx.annotation.Nullable;
-/** Helper for quick settings detail panel clip animations. **/
+/** Helper for quick settings detail panel clip animations. Currently used by the customizer **/
public class QSDetailClipper {
private final View mDetail;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailDisplayer.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailDisplayer.java
deleted file mode 100644
index afd4f0f..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetailDisplayer.java
+++ /dev/null
@@ -1,48 +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 com.android.systemui.qs;
-
-import androidx.annotation.Nullable;
-
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.plugins.qs.DetailAdapter;
-
-import javax.inject.Inject;
-
-/**
- * Proxy class for talking with the QSPanel and showing custom content within it.
- */
-@SysUISingleton
-public class QSDetailDisplayer {
- @Nullable
- private QSPanelController mQsPanelController;
-
- @Inject
- public QSDetailDisplayer() {
- }
-
- public void setQsPanelController(@Nullable QSPanelController qsPanelController) {
- mQsPanelController = qsPanelController;
- }
-
- /** Show the supplied DetailAdapter in the Quick Settings. */
- public void showDetailAdapter(DetailAdapter detailAdapter, int x, int y) {
- if (mQsPanelController != null) {
- mQsPanelController.showDetailAdapter(detailAdapter, x, y);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java
deleted file mode 100644
index eb3247b..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * Copyright (C) 2014 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.qs;
-
-import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import androidx.annotation.Nullable;
-
-import com.android.systemui.FontSizeUtils;
-import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QSTile;
-
-/**
- * Quick settings common detail view with line items.
- */
-public class QSDetailItems extends FrameLayout {
- private static final String TAG = "QSDetailItems";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
- private final int mQsDetailIconOverlaySize;
- private final Context mContext;
- private final H mHandler = new H();
- private final Adapter mAdapter = new Adapter();
-
- private String mTag;
- @Nullable
- private Callback mCallback;
- private boolean mItemsVisible = true;
- private AutoSizingList mItemList;
- private View mEmpty;
- private TextView mEmptyText;
- private ImageView mEmptyIcon;
-
- private Item[] mItems;
-
- public QSDetailItems(Context context, AttributeSet attrs) {
- super(context, attrs);
- mContext = context;
- mTag = TAG;
- mQsDetailIconOverlaySize = (int) getResources().getDimension(
- R.dimen.qs_detail_icon_overlay_size);
- }
-
- public static QSDetailItems convertOrInflate(Context context, View convert, ViewGroup parent) {
- if (convert instanceof QSDetailItems) {
- return (QSDetailItems) convert;
- }
- return (QSDetailItems) LayoutInflater.from(context).inflate(R.layout.qs_detail_items,
- parent, false);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mItemList = findViewById(android.R.id.list);
- mItemList.setVisibility(GONE);
- mItemList.setAdapter(mAdapter);
- mEmpty = findViewById(android.R.id.empty);
- mEmpty.setVisibility(GONE);
- mEmptyText = mEmpty.findViewById(android.R.id.title);
- mEmptyIcon = mEmpty.findViewById(android.R.id.icon);
- }
-
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- FontSizeUtils.updateFontSize(mEmptyText, R.dimen.qs_detail_empty_text_size);
- int count = mItemList.getChildCount();
- for (int i = 0; i < count; i++) {
- View item = mItemList.getChildAt(i);
- FontSizeUtils.updateFontSize(item, android.R.id.title,
- R.dimen.qs_detail_item_primary_text_size);
- FontSizeUtils.updateFontSize(item, android.R.id.summary,
- R.dimen.qs_detail_item_secondary_text_size);
- }
- }
-
- public void setTagSuffix(String suffix) {
- mTag = TAG + "." + suffix;
- }
-
- public void setEmptyState(int icon, int text) {
- mEmptyIcon.post(() -> {
- mEmptyIcon.setImageResource(icon);
- mEmptyText.setText(text);
- });
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- if (DEBUG) Log.d(mTag, "onAttachedToWindow");
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- if (DEBUG) Log.d(mTag, "onDetachedFromWindow");
- mCallback = null;
- }
-
- public void setCallback(Callback callback) {
- mHandler.removeMessages(H.SET_CALLBACK);
- mHandler.obtainMessage(H.SET_CALLBACK, callback).sendToTarget();
- }
-
- /** Set items. */
- public void setItems(@Nullable Item[] items) {
- mHandler.removeMessages(H.SET_ITEMS);
- mHandler.obtainMessage(H.SET_ITEMS, items).sendToTarget();
- }
-
- public void setItemsVisible(boolean visible) {
- mHandler.removeMessages(H.SET_ITEMS_VISIBLE);
- mHandler.obtainMessage(H.SET_ITEMS_VISIBLE, visible ? 1 : 0, 0).sendToTarget();
- }
-
- private void handleSetCallback(Callback callback) {
- mCallback = callback;
- }
-
- private void handleSetItems(Item[] items) {
- final int itemCount = items != null ? items.length : 0;
- mEmpty.setVisibility(itemCount == 0 ? VISIBLE : GONE);
- mItemList.setVisibility(itemCount == 0 ? GONE : VISIBLE);
- mItems = items;
- mAdapter.notifyDataSetChanged();
- }
-
- private void handleSetItemsVisible(boolean visible) {
- if (mItemsVisible == visible) return;
- mItemsVisible = visible;
- for (int i = 0; i < mItemList.getChildCount(); i++) {
- mItemList.getChildAt(i).setVisibility(mItemsVisible ? VISIBLE : INVISIBLE);
- }
- }
-
- private class Adapter extends BaseAdapter {
-
- @Override
- public int getCount() {
- return mItems != null ? mItems.length : 0;
- }
-
- @Override
- public Object getItem(int position) {
- return mItems[position];
- }
-
- @Override
- public long getItemId(int position) {
- return 0;
- }
-
- @Override
- public View getView(int position, View view, ViewGroup parent) {
- final Item item = mItems[position];
- if (view == null) {
- view = LayoutInflater.from(mContext).inflate(R.layout.qs_detail_item, parent,
- false);
- }
- view.setVisibility(mItemsVisible ? VISIBLE : INVISIBLE);
- final ImageView iv = (ImageView) view.findViewById(android.R.id.icon);
- if (item.icon != null) {
- iv.setImageDrawable(item.icon.getDrawable(iv.getContext()));
- } else {
- iv.setImageResource(item.iconResId);
- }
- iv.getOverlay().clear();
- if (item.overlay != null) {
- item.overlay.setBounds(0, 0, mQsDetailIconOverlaySize, mQsDetailIconOverlaySize);
- iv.getOverlay().add(item.overlay);
- }
- final TextView title = (TextView) view.findViewById(android.R.id.title);
- title.setText(item.line1);
- final TextView summary = (TextView) view.findViewById(android.R.id.summary);
- final boolean twoLines = !TextUtils.isEmpty(item.line2);
- title.setMaxLines(twoLines ? 1 : 2);
- summary.setVisibility(twoLines ? VISIBLE : GONE);
- summary.setText(twoLines ? item.line2 : null);
- view.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- if (mCallback != null) {
- mCallback.onDetailItemClick(item);
- }
- }
- });
-
- final ImageView icon2 = (ImageView) view.findViewById(android.R.id.icon2);
- if (item.canDisconnect) {
- icon2.setImageResource(R.drawable.ic_qs_cancel);
- icon2.setVisibility(VISIBLE);
- icon2.setClickable(true);
- icon2.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- if (mCallback != null) {
- mCallback.onDetailItemDisconnect(item);
- }
- }
- });
- } else if (item.icon2 != -1) {
- icon2.setVisibility(VISIBLE);
- icon2.setImageResource(item.icon2);
- icon2.setClickable(false);
- } else {
- icon2.setVisibility(GONE);
- }
-
- return view;
- }
- };
-
- private class H extends Handler {
- private static final int SET_ITEMS = 1;
- private static final int SET_CALLBACK = 2;
- private static final int SET_ITEMS_VISIBLE = 3;
-
- public H() {
- super(Looper.getMainLooper());
- }
-
- @Override
- public void handleMessage(Message msg) {
- if (msg.what == SET_ITEMS) {
- handleSetItems((Item[]) msg.obj);
- } else if (msg.what == SET_CALLBACK) {
- handleSetCallback((QSDetailItems.Callback) msg.obj);
- } else if (msg.what == SET_ITEMS_VISIBLE) {
- handleSetItemsVisible(msg.arg1 != 0);
- }
- }
- }
-
- public static class Item {
- public Item(int iconResId, CharSequence line1, Object tag) {
- this.iconResId = iconResId;
- this.line1 = line1;
- this.tag = tag;
- }
-
- public int iconResId;
- @Nullable
- public QSTile.Icon icon;
- @Nullable
- public Drawable overlay;
- public CharSequence line1;
- @Nullable
- public CharSequence line2;
- public Object tag;
- public boolean canDisconnect;
- public int icon2 = -1;
- }
-
- public interface Callback {
- void onDetailItemClick(Item item);
- void onDetailItemDisconnect(Item item);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSEvents.kt b/packages/SystemUI/src/com/android/systemui/qs/QSEvents.kt
index cc5a771..24bb16a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSEvents.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSEvents.kt
@@ -94,15 +94,28 @@
override fun getId() = _id
}
+/**
+ * Events from the QS DND tile dialog. {@see QSZenModeDialogMetricsLogger}
+ * Other names for DND (Do Not Disturb) include "Zen" and "Priority mode".
+ */
enum class QSDndEvent(private val _id: Int) : UiEventLogger.UiEventEnum {
- @UiEvent(doc = "TODO(beverlyt)")
+ @UiEvent(doc = "User selected an option on the DND dialog")
QS_DND_CONDITION_SELECT(420),
- @UiEvent(doc = "TODO(beverlyt)")
+ @UiEvent(doc = "User increased countdown duration of DND from the DND dialog")
QS_DND_TIME_UP(422),
- @UiEvent(doc = "TODO(beverlyt)")
- QS_DND_TIME_DOWN(423);
+ @UiEvent(doc = "User decreased countdown duration of DND from the DND dialog")
+ QS_DND_TIME_DOWN(423),
+
+ @UiEvent(doc = "User enabled DND from the QS DND dialog to last until manually turned off")
+ QS_DND_DIALOG_ENABLE_FOREVER(946),
+
+ @UiEvent(doc = "User enabled DND from the QS DND dialog to last until the next alarm goes off")
+ QS_DND_DIALOG_ENABLE_UNTIL_ALARM(947),
+
+ @UiEvent(doc = "User enabled DND from the QS DND dialog to last until countdown is done")
+ QS_DND_DIALOG_ENABLE_UNTIL_COUNTDOWN(948);
override fun getId() = _id
}
@@ -111,13 +124,13 @@
@UiEvent(doc = "The current user has been switched in the detail panel")
QS_USER_SWITCH(424),
- @UiEvent(doc = "User switcher QS detail panel open")
+ @UiEvent(doc = "User switcher QS dialog open")
QS_USER_DETAIL_OPEN(425),
- @UiEvent(doc = "User switcher QS detail panel closed")
+ @UiEvent(doc = "User switcher QS dialog closed")
QS_USER_DETAIL_CLOSE(426),
- @UiEvent(doc = "User switcher QS detail panel more settings pressed")
+ @UiEvent(doc = "User switcher QS dialog more settings pressed")
QS_USER_MORE_SETTINGS(427),
@UiEvent(doc = "The user has added a guest in the detail panel")
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 50952bd..17f85ee 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -33,7 +33,6 @@
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
-import android.widget.FrameLayout.LayoutParams;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
@@ -85,7 +84,6 @@
private QSSquishinessController mQSSquishinessController;
protected QuickStatusBarHeader mHeader;
protected NonInterceptingScrollView mQSPanelScrollView;
- private QSDetail mQSDetail;
private boolean mListening;
private QSContainerImpl mContainer;
private int mLayoutDirection;
@@ -96,8 +94,6 @@
private boolean mQsDisabled;
private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
- private final CommandQueue mCommandQueue;
- private final QSDetailDisplayer mQsDetailDisplayer;
private final MediaHost mQsMediaHost;
private final MediaHost mQqsMediaHost;
private final QSFragmentComponent.Factory mQsComponentFactory;
@@ -126,7 +122,6 @@
* otherwise.
*/
private boolean mInSplitShade;
- private boolean mPulseExpanding;
/**
* Are we currently transitioning from lockscreen to the full shade?
@@ -150,15 +145,13 @@
public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler,
QSTileHost qsTileHost,
StatusBarStateController statusBarStateController, CommandQueue commandQueue,
- QSDetailDisplayer qsDetailDisplayer, @Named(QS_PANEL) MediaHost qsMediaHost,
+ @Named(QS_PANEL) MediaHost qsMediaHost,
@Named(QUICK_QS_PANEL) MediaHost qqsMediaHost,
KeyguardBypassController keyguardBypassController,
QSFragmentComponent.Factory qsComponentFactory,
QSFragmentDisableFlagsLogger qsFragmentDisableFlagsLogger,
FalsingManager falsingManager, DumpManager dumpManager) {
mRemoteInputQuickSettingsDisabler = remoteInputQsDisabler;
- mCommandQueue = commandQueue;
- mQsDetailDisplayer = qsDetailDisplayer;
mQsMediaHost = qsMediaHost;
mQqsMediaHost = qqsMediaHost;
mQsComponentFactory = qsComponentFactory;
@@ -209,19 +202,15 @@
mScrollListener.onQsPanelScrollChanged(scrollY);
}
});
- mQSDetail = view.findViewById(R.id.qs_detail);
mHeader = view.findViewById(R.id.header);
mQSPanelController.setHeaderContainer(view.findViewById(R.id.header_text_container));
mFooter = qsFragmentComponent.getQSFooter();
- mQsDetailDisplayer.setQsPanelController(mQSPanelController);
-
mQSContainerImplController = qsFragmentComponent.getQSContainerImplController();
mQSContainerImplController.init();
mContainer = mQSContainerImplController.getView();
mDumpManager.registerDumpable(mContainer.getClass().getName(), mContainer);
- mQSDetail.setQsPanel(mQSPanelController, mHeader, mFooter, mFalsingManager);
mQSAnimator = qsFragmentComponent.getQSAnimator();
mQSSquishinessController = qsFragmentComponent.getQSSquishinessController();
@@ -237,7 +226,6 @@
mQSPanelController.getTileLayout().restoreInstanceState(savedInstanceState);
}
}
- setHost(mHost);
mStatusBarStateController.addCallback(this);
onStateChanged(mStatusBarStateController.getState());
view.addOnLayoutChangeListener(
@@ -271,7 +259,6 @@
setListening(false);
}
mQSCustomizerController.setQs(null);
- mQsDetailDisplayer.setQsPanelController(null);
mScrollListener = null;
mDumpManager.unregisterDumpable(mContainer.getClass().getName());
}
@@ -352,7 +339,6 @@
@Override
public void setContainerController(QSContainerController controller) {
mQSCustomizerController.setContainerController(controller);
- mQSDetail.setContainerController(controller);
}
@Override
@@ -360,10 +346,6 @@
return mQSCustomizerController.isCustomizing();
}
- public void setHost(QSTileHost qsh) {
- mQSDetail.setHost(qsh);
- }
-
@Override
public void disable(int displayId, int state1, int state2, boolean animate) {
if (displayId != getContext().getDisplayId()) {
@@ -392,7 +374,6 @@
final boolean expandVisually = expanded || mStackScrollerOverscrolling
|| mHeaderAnimating;
mQSPanelController.setExpanded(expanded);
- mQSDetail.setExpanded(expanded);
boolean keyguardShowing = isKeyguardState();
mHeader.setVisibility((expanded || !keyguardShowing || mHeaderAnimating
|| mShowCollapsedOnKeyguard)
@@ -439,12 +420,11 @@
public void setBrightnessMirrorController(
BrightnessMirrorController brightnessMirrorController) {
mQSPanelController.setBrightnessMirror(brightnessMirrorController);
- mQuickQSPanelController.setBrightnessMirror(brightnessMirrorController);
}
@Override
public boolean isShowingDetail() {
- return mQSCustomizerController.isCustomizing() || mQSDetail.isShowingDetail();
+ return mQSCustomizerController.isCustomizing();
}
@Override
@@ -573,7 +553,6 @@
if (fullyCollapsed) {
mQSPanelScrollView.setScrollY(0);
}
- mQSDetail.setFullyExpanded(fullyExpanded);
if (!fullyExpanded) {
// Set bounds on the QS panel so it doesn't run over the header when animating.
@@ -732,14 +711,7 @@
if (mQSCustomizerController.isCustomizing()) {
return getView().getHeight();
}
- if (mQSDetail.isClosingDetail()) {
- LayoutParams layoutParams = (LayoutParams) mQSPanelScrollView.getLayoutParams();
- int panelHeight = layoutParams.topMargin + layoutParams.bottomMargin +
- + mQSPanelScrollView.getMeasuredHeight();
- return panelHeight + getView().getPaddingBottom();
- } else {
- return getView().getMeasuredHeight();
- }
+ return getView().getMeasuredHeight();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 7c04cd4..0c854df 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -41,10 +41,8 @@
import com.android.internal.logging.UiEventLogger;
import com.android.internal.widget.RemeasuringLinearLayout;
import com.android.systemui.R;
-import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.settings.brightness.BrightnessSliderController;
-import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
@@ -80,7 +78,6 @@
protected boolean mExpanded;
protected boolean mListening;
- private QSDetail.Callback mCallback;
protected QSTileHost mHost;
private final List<OnConfigurationChangedListener> mOnConfigurationChangedListeners =
new ArrayList<>();
@@ -100,9 +97,6 @@
private int mContentMarginEnd;
private boolean mUsingHorizontalLayout;
- private Record mDetailRecord;
-
- private BrightnessMirrorController mBrightnessMirrorController;
private LinearLayout mHorizontalLinearLayout;
protected LinearLayout mHorizontalContentContainer;
@@ -315,24 +309,12 @@
view.setVisibility(TunerService.parseIntegerSwitch(newValue, true) ? VISIBLE : GONE);
}
- /** */
- public void openDetails(QSTile tile) {
- // If there's no tile with that name (as defined in QSFactoryImpl or other QSFactory),
- // QSFactory will not be able to create a tile and getTile will return null
- if (tile != null) {
- showDetailAdapter(true, tile.getDetailAdapter(), new int[]{getWidth() / 2, 0});
- }
- }
@Nullable
View getBrightnessView() {
return mBrightnessView;
}
- public void setCallback(QSDetail.Callback callback) {
- mCallback = callback;
- }
-
/**
* Links the footer's page indicator, which is used in landscape orientation to save space.
*
@@ -519,25 +501,6 @@
mListening = listening;
}
- public void showDetailAdapter(boolean show, DetailAdapter adapter, int[] locationInWindow) {
- int xInWindow = locationInWindow[0];
- int yInWindow = locationInWindow[1];
- ((View) getParent()).getLocationInWindow(locationInWindow);
-
- Record r = new Record();
- r.detailAdapter = adapter;
- r.x = xInWindow - locationInWindow[0];
- r.y = yInWindow - locationInWindow[1];
-
- locationInWindow[0] = xInWindow;
- locationInWindow[1] = yInWindow;
-
- showDetail(show, r);
- }
-
- protected void showDetail(boolean show, Record r) {
- mHandler.obtainMessage(H.SHOW_DETAIL, show ? 1 : 0, 0, r).sendToTarget();
- }
protected void drawTile(QSPanelControllerBase.TileRecord r, QSTile.State state) {
r.tileView.onStateChanged(state);
@@ -565,30 +528,6 @@
public void onStateChanged(QSTile.State state) {
drawTile(tileRecord, state);
}
-
- @Override
- public void onShowDetail(boolean show) {
- // Both the collapsed and full QS panels get this callback, this check determines
- // which one should handle showing the detail.
- if (shouldShowDetail()) {
- QSPanel.this.showDetail(show, tileRecord);
- }
- }
-
- @Override
- public void onToggleStateChanged(boolean state) {
- if (mDetailRecord == tileRecord) {
- fireToggleStateChanged(state);
- }
- }
-
- @Override
- public void onScanStateChanged(boolean state) {
- tileRecord.scanState = state;
- if (mDetailRecord == tileRecord) {
- fireScanStateChanged(tileRecord.scanState);
- }
- }
};
tileRecord.tile.addCallback(callback);
@@ -605,72 +544,10 @@
mTileLayout.removeTile(tileRecord);
}
- void closeDetail() {
- showDetail(false, mDetailRecord);
- }
-
public int getGridHeight() {
return getMeasuredHeight();
}
- protected void handleShowDetail(Record r, boolean show) {
- if (r instanceof QSPanelControllerBase.TileRecord) {
- handleShowDetailTile((QSPanelControllerBase.TileRecord) r, show);
- } else {
- int x = 0;
- int y = 0;
- if (r != null) {
- x = r.x;
- y = r.y;
- }
- handleShowDetailImpl(r, show, x, y);
- }
- }
-
- private void handleShowDetailTile(QSPanelControllerBase.TileRecord r, boolean show) {
- if ((mDetailRecord != null) == show && mDetailRecord == r) return;
-
- if (show) {
- r.detailAdapter = r.tile.getDetailAdapter();
- if (r.detailAdapter == null) return;
- }
- r.tile.setDetailListening(show);
- int x = r.tileView.getLeft() + r.tileView.getWidth() / 2;
- int y = r.tileView.getDetailY() + mTileLayout.getOffsetTop(r) + getTop();
- handleShowDetailImpl(r, show, x, y);
- }
-
- private void handleShowDetailImpl(Record r, boolean show, int x, int y) {
- setDetailRecord(show ? r : null);
- fireShowingDetail(show ? r.detailAdapter : null, x, y);
- }
-
- protected void setDetailRecord(Record r) {
- if (r == mDetailRecord) return;
- mDetailRecord = r;
- final boolean scanState = mDetailRecord instanceof QSPanelControllerBase.TileRecord
- && ((QSPanelControllerBase.TileRecord) mDetailRecord).scanState;
- fireScanStateChanged(scanState);
- }
-
- private void fireShowingDetail(DetailAdapter detail, int x, int y) {
- if (mCallback != null) {
- mCallback.onShowingDetail(detail, x, y);
- }
- }
-
- private void fireToggleStateChanged(boolean state) {
- if (mCallback != null) {
- mCallback.onToggleStateChanged(state);
- }
- }
-
- private void fireScanStateChanged(boolean state) {
- if (mCallback != null) {
- mCallback.onScanStateChanged(state);
- }
- }
-
QSTileLayout getTileLayout() {
return mTileLayout;
}
@@ -774,26 +651,16 @@
}
private class H extends Handler {
- private static final int SHOW_DETAIL = 1;
- private static final int SET_TILE_VISIBILITY = 2;
- private static final int ANNOUNCE_FOR_ACCESSIBILITY = 3;
+ private static final int ANNOUNCE_FOR_ACCESSIBILITY = 1;
@Override
public void handleMessage(Message msg) {
- if (msg.what == SHOW_DETAIL) {
- handleShowDetail((Record) msg.obj, msg.arg1 != 0);
- } else if (msg.what == ANNOUNCE_FOR_ACCESSIBILITY) {
+ if (msg.what == ANNOUNCE_FOR_ACCESSIBILITY) {
announceForAccessibility((CharSequence) msg.obj);
}
}
}
- protected static class Record {
- DetailAdapter detailAdapter;
- int x;
- int y;
- }
-
public interface QSTileLayout {
/** */
default void saveInstanceState(Bundle outState) {}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
index 418c4ae..9834129 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
@@ -36,15 +36,12 @@
import com.android.systemui.media.MediaHierarchyManager;
import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.plugins.qs.DetailAdapter;
-import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.settings.brightness.BrightnessController;
import com.android.systemui.settings.brightness.BrightnessMirrorHandler;
import com.android.systemui.settings.brightness.BrightnessSliderController;
-import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.Utils;
@@ -57,7 +54,6 @@
*/
@QSScope
public class QSPanelController extends QSPanelControllerBase<QSPanel> {
- public static final String QS_REMOVE_LABELS = "sysui_remove_labels";
private final QSFgsManagerFooter mQSFgsManagerFooter;
private final QSSecurityFooter mQsSecurityFooter;
@@ -65,7 +61,6 @@
private final QSCustomizerController mQsCustomizerController;
private final QSTileRevealController.Factory mQsTileRevealControllerFactory;
private final FalsingManager mFalsingManager;
- private final CommandQueue mCommandQueue;
private final BrightnessController mBrightnessController;
private final BrightnessSliderController mBrightnessSliderController;
private final BrightnessMirrorHandler mBrightnessMirrorHandler;
@@ -107,7 +102,7 @@
DumpManager dumpManager, MetricsLogger metricsLogger, UiEventLogger uiEventLogger,
QSLogger qsLogger, BrightnessController.Factory brightnessControllerFactory,
BrightnessSliderController.Factory brightnessSliderFactory,
- FalsingManager falsingManager, CommandQueue commandQueue, FeatureFlags featureFlags) {
+ FalsingManager falsingManager, FeatureFlags featureFlags) {
super(view, qstileHost, qsCustomizerController, usingMediaPlayer, mediaHost,
metricsLogger, uiEventLogger, qsLogger, dumpManager);
mQSFgsManagerFooter = qsFgsManagerFooter;
@@ -116,7 +111,6 @@
mQsCustomizerController = qsCustomizerController;
mQsTileRevealControllerFactory = qsTileRevealControllerFactory;
mFalsingManager = falsingManager;
- mCommandQueue = commandQueue;
mBrightnessSliderController = brightnessSliderFactory.create(getContext(), mView);
mView.setBrightnessView(mBrightnessSliderController.getRootView());
@@ -193,7 +187,9 @@
/** */
public void setListening(boolean listening, boolean expanded) {
- setListening(listening && expanded);
+ // TODO(218268829): checking for split shade is workaround but when proper fix lands
+ // "|| mShouldUseSplitNotificationShade" should be removed
+ setListening(listening && (expanded || mShouldUseSplitNotificationShade));
if (mView.isListening()) {
refreshAllTiles();
}
@@ -221,15 +217,6 @@
return mHost;
}
-
- /** Open the details for a specific tile.. */
- public void openDetails(String subPanel) {
- QSTile tile = getTile(subPanel);
- if (tile != null) {
- mView.openDetails(tile);
- }
- }
-
/** Show the device monitoring dialog. */
public void showDeviceMonitoringDialog() {
mQsSecurityFooter.showDeviceMonitoringDialog();
@@ -261,11 +248,6 @@
}
/** */
- public void setCallback(QSDetail.Callback qsPanelCallback) {
- mView.setCallback(qsPanelCallback);
- }
-
- /** */
public void setGridContentVisibility(boolean visible) {
int newVis = visible ? View.VISIBLE : View.INVISIBLE;
setVisibility(newVis);
@@ -294,19 +276,6 @@
}
/** */
- public void showDetailAdapter(DetailAdapter detailAdapter, int x, int y) {
- // TODO(b/199296365)
- // Workaround for opening detail from QQS, when there might not be enough space to
- // display e.g. in case of multiuser detail from split shade. Currently showing detail works
- // only for QS (mView below) and that's why expanding panel (thus showing QS instead of QQS)
- // makes it displayed correctly.
- if (!isExpanded()) {
- mCommandQueue.animateExpandSettingsPanel(null);
- }
- mView.showDetailAdapter(true, detailAdapter, new int[]{x, y});
- }
-
- /** */
public void setFooterPageIndicator(PageIndicator pageIndicator) {
mView.setFooterPageIndicator(pageIndicator);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index d4d6da8..0bff722 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -298,21 +298,8 @@
mQsCustomizerController.hide();
return;
}
- mView.closeDetail();
}
- /** */
- public void openDetails(String subPanel) {
- QSTile tile = getTile(subPanel);
- // If there's no tile with that name (as defined in QSFactoryImpl or other QSFactory),
- // QSFactory will not be able to create a tile and getTile will return null
- if (tile != null) {
- mView.showDetailAdapter(
- true, tile.getDetailAdapter(), new int[]{mView.getWidth() / 2, 0});
- }
- }
-
-
void setListening(boolean listening) {
mView.setListening(listening);
@@ -429,7 +416,7 @@
}
/** */
- public static final class TileRecord extends QSPanel.Record {
+ public static final class TileRecord {
public TileRecord(QSTile tile, com.android.systemui.plugins.qs.QSTileView tileView) {
this.tile = tile;
this.tileView = tileView;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSBrightnessController.kt b/packages/SystemUI/src/com/android/systemui/qs/QuickQSBrightnessController.kt
deleted file mode 100644
index 65889d7..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSBrightnessController.kt
+++ /dev/null
@@ -1,102 +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.systemui.qs
-
-import androidx.annotation.VisibleForTesting
-import com.android.systemui.settings.brightness.BrightnessController
-import com.android.systemui.settings.brightness.BrightnessSliderController
-import com.android.systemui.settings.brightness.MirroredBrightnessController
-import com.android.systemui.statusbar.policy.BrightnessMirrorController
-import javax.inject.Inject
-
-/**
- * Controls brightness slider in QQS, which is visible only in split shade. It's responsible for
- * showing/hiding it when appropriate and (un)registering listeners
- */
-class QuickQSBrightnessController @VisibleForTesting constructor(
- private val brightnessControllerFactory: () -> BrightnessController
-) : MirroredBrightnessController {
-
- @Inject constructor(
- brightnessControllerFactory: BrightnessController.Factory,
- brightnessSliderControllerFactory: BrightnessSliderController.Factory,
- quickQSPanel: QuickQSPanel
- ) : this(brightnessControllerFactory = {
- val slider = brightnessSliderControllerFactory.create(quickQSPanel.context,
- quickQSPanel)
- slider.init()
- quickQSPanel.setBrightnessView(slider.rootView)
- brightnessControllerFactory.create(slider)
- })
-
- private var isListening = false
- private var brightnessController: BrightnessController? = null
- private var mirrorController: BrightnessMirrorController? = null
-
- fun init(shouldUseSplitNotificationShade: Boolean) {
- refreshVisibility(shouldUseSplitNotificationShade)
- }
-
- /**
- * Starts/Stops listening for brightness changing events.
- * It's fine to call this function even if slider is not visible (which would be the case for
- * all small screen devices), it will just do nothing in that case
- */
- fun setListening(listening: Boolean) {
- if (listening) {
- // controller can be null when slider was never shown
- if (!isListening && brightnessController != null) {
- brightnessController?.registerCallbacks()
- isListening = true
- }
- } else {
- brightnessController?.unregisterCallbacks()
- isListening = false
- }
- }
-
- fun checkRestrictionAndSetEnabled() {
- brightnessController?.checkRestrictionAndSetEnabled()
- }
-
- fun refreshVisibility(shouldUseSplitNotificationShade: Boolean) {
- if (shouldUseSplitNotificationShade) {
- showBrightnessSlider()
- } else {
- hideBrightnessSlider()
- }
- }
-
- override fun setMirror(controller: BrightnessMirrorController) {
- mirrorController = controller
- mirrorController?.let { brightnessController?.setMirror(it) }
- }
-
- private fun hideBrightnessSlider() {
- brightnessController?.hideSlider()
- }
-
- private fun showBrightnessSlider() {
- if (brightnessController == null) {
- brightnessController = brightnessControllerFactory()
- mirrorController?.also { brightnessController?.setMirror(it) }
- brightnessController?.registerCallbacks()
- isListening = true
- }
- brightnessController?.showSlider()
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
index a3af0e5..b2e008b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
@@ -33,8 +33,6 @@
import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.qs.logging.QSLogger;
-import com.android.systemui.settings.brightness.BrightnessMirrorHandler;
-import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.util.leak.RotationUtils;
import java.util.ArrayList;
@@ -55,10 +53,6 @@
}
};
- // brightness is visible only in split shade
- private final QuickQSBrightnessController mBrightnessController;
- private final BrightnessMirrorHandler mBrightnessMirrorHandler;
-
private final MediaFlags mMediaFlags;
private final boolean mUsingCollapsedLandscapeMedia;
@@ -70,13 +64,10 @@
@Named(QS_USING_COLLAPSED_LANDSCAPE_MEDIA) boolean usingCollapsedLandscapeMedia,
MediaFlags mediaFlags,
MetricsLogger metricsLogger, UiEventLogger uiEventLogger, QSLogger qsLogger,
- DumpManager dumpManager,
- QuickQSBrightnessController quickQSBrightnessController
+ DumpManager dumpManager
) {
super(view, qsTileHost, qsCustomizerController, usingMediaPlayer, mediaHost, metricsLogger,
uiEventLogger, qsLogger, dumpManager);
- mBrightnessController = quickQSBrightnessController;
- mBrightnessMirrorHandler = new BrightnessMirrorHandler(mBrightnessController);
mUsingCollapsedLandscapeMedia = usingCollapsedLandscapeMedia;
mMediaFlags = mediaFlags;
}
@@ -87,7 +78,6 @@
updateMediaExpansion();
mMediaHost.setShowsOnlyActiveMedia(true);
mMediaHost.init(MediaHierarchyManager.LOCATION_QQS);
- mBrightnessController.init(mShouldUseSplitNotificationShade);
}
private void updateMediaExpansion() {
@@ -111,20 +101,17 @@
protected void onViewAttached() {
super.onViewAttached();
mView.addOnConfigurationChangedListener(mOnConfigurationChangedListener);
- mBrightnessMirrorHandler.onQsPanelAttached();
}
@Override
protected void onViewDetached() {
super.onViewDetached();
mView.removeOnConfigurationChangedListener(mOnConfigurationChangedListener);
- mBrightnessMirrorHandler.onQsPanelDettached();
}
@Override
void setListening(boolean listening) {
super.setListening(listening);
- mBrightnessController.setListening(listening);
}
public boolean isListening() {
@@ -137,14 +124,7 @@
}
@Override
- public void refreshAllTiles() {
- mBrightnessController.checkRestrictionAndSetEnabled();
- super.refreshAllTiles();
- }
-
- @Override
protected void onConfigurationChanged() {
- mBrightnessController.refreshVisibility(mShouldUseSplitNotificationShade);
updateMediaExpansion();
}
@@ -168,8 +148,4 @@
public int getNumQuickTiles() {
return mView.getNumQuickTiles();
}
-
- public void setBrightnessMirror(BrightnessMirrorController brightnessMirrorController) {
- mBrightnessMirrorHandler.setController(brightnessMirrorController);
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index d3f8db3..8c08873 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -39,7 +39,6 @@
import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.battery.BatteryMeterView;
-import com.android.systemui.qs.QSDetail.Callback;
import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider;
import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
import com.android.systemui.statusbar.phone.StatusIconContainer;
@@ -548,10 +547,6 @@
post(() -> setClickable(!mExpanded));
}
- public void setCallback(Callback qsPanelCallback) {
- mHeaderQsPanel.setCallback(qsPanelCallback);
- }
-
private void setContentMargins(View view, int marginStart, int marginEnd) {
MarginLayoutParams lp = (MarginLayoutParams) view.getLayoutParams();
lp.setMarginStart(marginStart);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index b29687f..32a7916 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -205,15 +205,6 @@
finished();
}
}
-
- @Override
- public void onShowDetail(boolean show) {}
-
- @Override
- public void onToggleStateChanged(boolean state) {}
-
- @Override
- public void onScanStateChanged(boolean state) {}
}
private void addPackageTiles(final QSTileHost host) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceRequestController.kt b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceRequestController.kt
index 73d6b97..237b66e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceRequestController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceRequestController.kt
@@ -21,6 +21,7 @@
import android.content.ComponentName
import android.content.DialogInterface
import android.graphics.drawable.Icon
+import android.os.RemoteException
import android.util.Log
import androidx.annotation.VisibleForTesting
import com.android.internal.statusbar.IAddTileResultCallback
@@ -32,6 +33,7 @@
import com.android.systemui.R
import com.android.systemui.statusbar.CommandQueue
import java.io.PrintWriter
+import java.util.concurrent.atomic.AtomicBoolean
import java.util.function.Consumer
import javax.inject.Inject
@@ -67,7 +69,11 @@
callback: IAddTileResultCallback
) {
requestTileAdd(componentName, appName, label, icon) {
- callback.onTileRequest(it)
+ try {
+ callback.onTileRequest(it)
+ } catch (e: RemoteException) {
+ Log.e(TAG, "Couldn't respond to request", e)
+ }
}
}
@@ -105,7 +111,7 @@
eventLogger.logTileAlreadyAdded(packageName, instanceId)
return
}
- val dialogResponse = Consumer<Int> { response ->
+ val dialogResponse = SingleShotConsumer<Int> { response ->
if (response == ADD_TILE) {
addTile(componentName)
}
@@ -127,7 +133,7 @@
private fun createDialog(
tileData: TileRequestDialog.TileData,
- responseHandler: Consumer<Int>
+ responseHandler: SingleShotConsumer<Int>
): SystemUIDialog {
val dialogClickListener = DialogInterface.OnClickListener { _, which ->
if (which == Dialog.BUTTON_POSITIVE) {
@@ -141,6 +147,10 @@
setShowForAllUsers(true)
setCanceledOnTouchOutside(true)
setOnCancelListener { responseHandler.accept(DISMISSED) }
+ // We want this in case the dialog is dismissed without it being cancelled (for example
+ // by going home or locking the device). We use a SingleShotConsumer so the response
+ // is only sent once, with the first value.
+ setOnDismissListener { responseHandler.accept(DISMISSED) }
setPositiveButton(R.string.qs_tile_request_dialog_add, dialogClickListener)
setNegativeButton(R.string.qs_tile_request_dialog_not_add, dialogClickListener)
}
@@ -169,6 +179,16 @@
}
}
+ private class SingleShotConsumer<T>(private val consumer: Consumer<T>) : Consumer<T> {
+ private val dispatched = AtomicBoolean(false)
+
+ override fun accept(t: T) {
+ if (dispatched.compareAndSet(false, true)) {
+ consumer.accept(t)
+ }
+ }
+ }
+
@SysUISingleton
class Builder @Inject constructor(
private val commandQueue: CommandQueue,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index 86fc4de..1488231 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -53,7 +53,6 @@
import com.android.systemui.qs.tiles.RotationLockTile;
import com.android.systemui.qs.tiles.ScreenRecordTile;
import com.android.systemui.qs.tiles.UiModeNightTile;
-import com.android.systemui.qs.tiles.UserTile;
import com.android.systemui.qs.tiles.WifiTile;
import com.android.systemui.qs.tiles.WorkModeTile;
import com.android.systemui.util.leak.GarbageMonitor;
@@ -82,7 +81,6 @@
private final Provider<LocationTile> mLocationTileProvider;
private final Provider<CastTile> mCastTileProvider;
private final Provider<HotspotTile> mHotspotTileProvider;
- private final Provider<UserTile> mUserTileProvider;
private final Provider<BatterySaverTile> mBatterySaverTileProvider;
private final Provider<DataSaverTile> mDataSaverTileProvider;
private final Provider<NightDisplayTile> mNightDisplayTileProvider;
@@ -119,7 +117,6 @@
Provider<LocationTile> locationTileProvider,
Provider<CastTile> castTileProvider,
Provider<HotspotTile> hotspotTileProvider,
- Provider<UserTile> userTileProvider,
Provider<BatterySaverTile> batterySaverTileProvider,
Provider<DataSaverTile> dataSaverTileProvider,
Provider<NightDisplayTile> nightDisplayTileProvider,
@@ -152,7 +149,6 @@
mLocationTileProvider = locationTileProvider;
mCastTileProvider = castTileProvider;
mHotspotTileProvider = hotspotTileProvider;
- mUserTileProvider = userTileProvider;
mBatterySaverTileProvider = batterySaverTileProvider;
mDataSaverTileProvider = dataSaverTileProvider;
mNightDisplayTileProvider = nightDisplayTileProvider;
@@ -212,8 +208,6 @@
return mCastTileProvider.get();
case "hotspot":
return mHotspotTileProvider.get();
- case "user":
- return mUserTileProvider.get();
case "battery":
return mBatterySaverTileProvider.get();
case "saver":
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 6d9d5b1..131589f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -60,7 +60,6 @@
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSIconView;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTile.State;
@@ -261,16 +260,6 @@
return new QSIconViewImpl(context);
}
- /** Returns corresponding DetailAdapter. */
- @Nullable
- public DetailAdapter getDetailAdapter() {
- return null; // optional
- }
-
- protected DetailAdapter createDetailAdapter() {
- throw new UnsupportedOperationException();
- }
-
/**
* Is a startup check whether this device currently supports this tile.
* Should not be used to conditionally hide tiles. Only checked on tile
@@ -337,10 +326,6 @@
.addTaggedData(FIELD_QS_POSITION, mHost.indexOf(mTileSpec));
}
- public void showDetail(boolean show) {
- mHandler.obtainMessage(H.SHOW_DETAIL, show ? 1 : 0, 0).sendToTarget();
- }
-
public void refreshState() {
refreshState(null);
}
@@ -353,14 +338,6 @@
mHandler.obtainMessage(H.USER_SWITCH, newUserId, 0).sendToTarget();
}
- public void fireToggleStateChanged(boolean state) {
- mHandler.obtainMessage(H.TOGGLE_STATE_CHANGED, state ? 1 : 0, 0).sendToTarget();
- }
-
- public void fireScanStateChanged(boolean state) {
- mHandler.obtainMessage(H.SCAN_STATE_CHANGED, state ? 1 : 0, 0).sendToTarget();
- }
-
public void destroy() {
mHandler.sendEmptyMessage(H.DESTROY);
}
@@ -462,29 +439,6 @@
}
}
- private void handleShowDetail(boolean show) {
- mShowingDetail = show;
- for (int i = 0; i < mCallbacks.size(); i++) {
- mCallbacks.get(i).onShowDetail(show);
- }
- }
-
- protected boolean isShowingDetail() {
- return mShowingDetail;
- }
-
- private void handleToggleStateChanged(boolean state) {
- for (int i = 0; i < mCallbacks.size(); i++) {
- mCallbacks.get(i).onToggleStateChanged(state);
- }
- }
-
- private void handleScanStateChanged(boolean state) {
- for (int i = 0; i < mCallbacks.size(); i++) {
- mCallbacks.get(i).onScanStateChanged(state);
- }
- }
-
protected void handleUserSwitch(int newUserId) {
handleRefreshState(null);
}
@@ -591,17 +545,14 @@
private static final int SECONDARY_CLICK = 3;
private static final int LONG_CLICK = 4;
private static final int REFRESH_STATE = 5;
- private static final int SHOW_DETAIL = 6;
- private static final int USER_SWITCH = 7;
- private static final int TOGGLE_STATE_CHANGED = 8;
- private static final int SCAN_STATE_CHANGED = 9;
- private static final int DESTROY = 10;
- private static final int REMOVE_CALLBACKS = 11;
- private static final int REMOVE_CALLBACK = 12;
- private static final int SET_LISTENING = 13;
+ private static final int USER_SWITCH = 6;
+ private static final int DESTROY = 7;
+ private static final int REMOVE_CALLBACKS = 8;
+ private static final int REMOVE_CALLBACK = 9;
+ private static final int SET_LISTENING = 10;
@VisibleForTesting
- protected static final int STALE = 14;
- private static final int INITIALIZE = 15;
+ protected static final int STALE = 11;
+ private static final int INITIALIZE = 12;
@VisibleForTesting
protected H(Looper looper) {
@@ -639,18 +590,9 @@
} else if (msg.what == REFRESH_STATE) {
name = "handleRefreshState";
handleRefreshState(msg.obj);
- } else if (msg.what == SHOW_DETAIL) {
- name = "handleShowDetail";
- handleShowDetail(msg.arg1 != 0);
} else if (msg.what == USER_SWITCH) {
name = "handleUserSwitch";
handleUserSwitch(msg.arg1);
- } else if (msg.what == TOGGLE_STATE_CHANGED) {
- name = "handleToggleStateChanged";
- handleToggleStateChanged(msg.arg1 != 0);
- } else if (msg.what == SCAN_STATE_CHANGED) {
- name = "handleScanStateChanged";
- handleScanStateChanged(msg.arg1 != 0);
} else if (msg.what == DESTROY) {
name = "handleDestroy";
handleDestroy();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 754f8e2..c61c18a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -19,7 +19,6 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
@@ -29,7 +28,6 @@
import android.service.quicksettings.Tile;
import android.text.TextUtils;
import android.view.View;
-import android.view.ViewGroup;
import android.widget.Switch;
import androidx.annotation.Nullable;
@@ -38,24 +36,18 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.Utils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.graph.BluetoothDeviceLayerDrawable;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSTile.BooleanState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.qs.QSDetailItems;
-import com.android.systemui.qs.QSDetailItems.Item;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.statusbar.policy.BluetoothController;
-import java.util.ArrayList;
-import java.util.Collection;
import java.util.List;
import javax.inject.Inject;
@@ -65,7 +57,6 @@
private static final Intent BLUETOOTH_SETTINGS = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
private final BluetoothController mController;
- private final BluetoothDetailAdapter mDetailAdapter;
@Inject
public BluetoothTile(
@@ -82,16 +73,10 @@
super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
statusBarStateController, activityStarter, qsLogger);
mController = bluetoothController;
- mDetailAdapter = (BluetoothDetailAdapter) createDetailAdapter();
mController.observe(getLifecycle(), mCallback);
}
@Override
- public DetailAdapter getDetailAdapter() {
- return mDetailAdapter;
- }
-
- @Override
public BooleanState newTileState() {
return new BooleanState();
}
@@ -117,7 +102,6 @@
new Intent(Settings.ACTION_BLUETOOTH_SETTINGS), 0);
return;
}
- showDetail(true);
if (!mState.value) {
mController.setBluetoothEnabled(true);
}
@@ -251,53 +235,14 @@
@Override
public void onBluetoothStateChange(boolean enabled) {
refreshState();
- if (isShowingDetail()) {
- mDetailAdapter.updateItems();
- fireToggleStateChanged(mDetailAdapter.getToggleState());
- }
}
@Override
public void onBluetoothDevicesChanged() {
refreshState();
- if (isShowingDetail()) {
- mDetailAdapter.updateItems();
- }
}
};
- @Override
- protected DetailAdapter createDetailAdapter() {
- return new BluetoothDetailAdapter();
- }
-
- /**
- * Bluetooth icon wrapper for Quick Settings with a battery indicator that reflects the
- * connected device's battery level. This is used instead of
- * {@link com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon} in order to use a context
- * that reflects dark/light theme attributes.
- */
- private class BluetoothBatteryTileIcon extends Icon {
- private int mBatteryLevel;
- private float mIconScale;
-
- BluetoothBatteryTileIcon(int batteryLevel, float iconScale) {
- mBatteryLevel = batteryLevel;
- mIconScale = iconScale;
- }
-
- @Override
- public Drawable getDrawable(Context context) {
- // This method returns Pair<Drawable, String> while first value is the drawable
- return BluetoothDeviceLayerDrawable.createLayerDrawable(
- context,
- R.drawable.ic_bluetooth_connected,
- mBatteryLevel,
- mIconScale);
- }
- }
-
-
/**
* Bluetooth icon wrapper (when connected with no battery indicator) for Quick Settings. This is
* used instead of {@link com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon} in order to
@@ -315,129 +260,4 @@
return context.getDrawable(R.drawable.ic_bluetooth_connected);
}
}
-
- protected class BluetoothDetailAdapter implements DetailAdapter, QSDetailItems.Callback {
- // We probably won't ever have space in the UI for more than 20 devices, so don't
- // get info for them.
- private static final int MAX_DEVICES = 20;
- @Nullable
- private QSDetailItems mItems;
-
- @Override
- public CharSequence getTitle() {
- return mContext.getString(R.string.quick_settings_bluetooth_label);
- }
-
- @Override
- public Boolean getToggleState() {
- return mState.value;
- }
-
- @Override
- public boolean getToggleEnabled() {
- return mController.getBluetoothState() == BluetoothAdapter.STATE_OFF
- || mController.getBluetoothState() == BluetoothAdapter.STATE_ON;
- }
-
- @Override
- public Intent getSettingsIntent() {
- return BLUETOOTH_SETTINGS;
- }
-
- @Override
- public void setToggleState(boolean state) {
- MetricsLogger.action(mContext, MetricsEvent.QS_BLUETOOTH_TOGGLE, state);
- mController.setBluetoothEnabled(state);
- }
-
- @Override
- public int getMetricsCategory() {
- return MetricsEvent.QS_BLUETOOTH_DETAILS;
- }
-
- @Override
- public View createDetailView(Context context, View convertView, ViewGroup parent) {
- mItems = QSDetailItems.convertOrInflate(context, convertView, parent);
- mItems.setTagSuffix("Bluetooth");
- mItems.setCallback(this);
- updateItems();
- setItemsVisible(mState.value);
- return mItems;
- }
-
- public void setItemsVisible(boolean visible) {
- if (mItems == null) return;
- mItems.setItemsVisible(visible);
- }
-
- private void updateItems() {
- if (mItems == null) return;
- if (mController.isBluetoothEnabled()) {
- mItems.setEmptyState(R.drawable.ic_qs_bluetooth_detail_empty,
- R.string.quick_settings_bluetooth_detail_empty_text);
- } else {
- mItems.setEmptyState(R.drawable.ic_qs_bluetooth_detail_empty,
- R.string.bt_is_off);
- }
- ArrayList<Item> items = new ArrayList<Item>();
- final Collection<CachedBluetoothDevice> devices = mController.getDevices();
- if (devices != null) {
- int connectedDevices = 0;
- int count = 0;
- for (CachedBluetoothDevice device : devices) {
- if (mController.getBondState(device) == BluetoothDevice.BOND_NONE) continue;
- final Item item =
- new Item(
- com.android.internal.R.drawable.ic_qs_bluetooth,
- device.getName(),
- device);
- int state = device.getMaxConnectionState();
- if (state == BluetoothProfile.STATE_CONNECTED) {
- item.iconResId = R.drawable.ic_bluetooth_connected;
- int batteryLevel = device.getBatteryLevel();
- if (batteryLevel > BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
- item.icon = new BluetoothBatteryTileIcon(batteryLevel,1 /* iconScale */);
- item.line2 = mContext.getString(
- R.string.quick_settings_connected_battery_level,
- Utils.formatPercentage(batteryLevel));
- } else {
- item.line2 = mContext.getString(R.string.quick_settings_connected);
- }
- item.canDisconnect = true;
- items.add(connectedDevices, item);
- connectedDevices++;
- } else if (state == BluetoothProfile.STATE_CONNECTING) {
- item.iconResId = R.drawable.ic_qs_bluetooth_connecting;
- item.line2 = mContext.getString(R.string.quick_settings_connecting);
- items.add(connectedDevices, item);
- } else {
- items.add(item);
- }
- if (++count == MAX_DEVICES) {
- break;
- }
- }
- }
- mItems.setItems(items.toArray(new Item[items.size()]));
- }
-
- @Override
- public void onDetailItemClick(Item item) {
- if (item == null || item.tag == null) return;
- final CachedBluetoothDevice device = (CachedBluetoothDevice) item.tag;
- if (device != null && device.getMaxConnectionState()
- == BluetoothProfile.STATE_DISCONNECTED) {
- mController.connect(device);
- }
- }
-
- @Override
- public void onDetailItemDisconnect(Item item) {
- if (item == null || item.tag == null) return;
- final CachedBluetoothDevice device = (CachedBluetoothDevice) item.tag;
- if (device != null) {
- mController.disconnect(device);
- }
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 76c84f9..e8d27ec 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -20,7 +20,6 @@
import android.annotation.NonNull;
import android.app.Dialog;
-import android.content.Context;
import android.content.Intent;
import android.media.MediaRouter.RouteInfo;
import android.os.Handler;
@@ -29,8 +28,6 @@
import android.service.quicksettings.Tile;
import android.util.Log;
import android.view.View;
-import android.view.View.OnAttachStateChangeListener;
-import android.view.ViewGroup;
import android.widget.Button;
import androidx.annotation.Nullable;
@@ -44,11 +41,8 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSTile.BooleanState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.qs.QSDetailItems;
-import com.android.systemui.qs.QSDetailItems.Item;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
@@ -62,7 +56,6 @@
import com.android.systemui.statusbar.policy.KeyguardStateController;
import java.util.ArrayList;
-import java.util.LinkedHashMap;
import java.util.List;
import javax.inject.Inject;
@@ -73,7 +66,6 @@
new Intent(Settings.ACTION_CAST_SETTINGS);
private final CastController mController;
- private final CastDetailAdapter mDetailAdapter;
private final KeyguardStateController mKeyguard;
private final NetworkController mNetworkController;
private final DialogLaunchAnimator mDialogLaunchAnimator;
@@ -100,7 +92,6 @@
super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
statusBarStateController, activityStarter, qsLogger);
mController = castController;
- mDetailAdapter = new CastDetailAdapter();
mKeyguard = keyguardStateController;
mNetworkController = networkController;
mDialogLaunchAnimator = dialogLaunchAnimator;
@@ -111,11 +102,6 @@
}
@Override
- public DetailAdapter getDetailAdapter() {
- return mDetailAdapter;
- }
-
- @Override
public BooleanState newTileState() {
BooleanState state = new BooleanState();
state.handlesLongClick = false;
@@ -154,14 +140,14 @@
}
List<CastDevice> activeDevices = getActiveDevices();
- if (willPopDetail()) {
+ if (willPopDialog()) {
if (!mKeyguard.isShowing()) {
- showDetail(view);
+ showDialog(view);
} else {
mActivityStarter.postQSRunnableDismissingKeyguard(() -> {
// Dismissing the keyguard will collapse the shade, so we don't animate from the
// view here as it would not look good.
- showDetail(null /* view */);
+ showDialog(null /* view */);
});
}
} else {
@@ -173,7 +159,7 @@
// (neither routes nor projection), or if we have an active route. In other cases, we assume
// that a projection is active. This is messy, but this tile never correctly handled the
// case where multiple devices were active :-/.
- private boolean willPopDetail() {
+ private boolean willPopDialog() {
List<CastDevice> activeDevices = getActiveDevices();
return activeDevices.isEmpty() || (activeDevices.get(0).tag instanceof RouteInfo);
}
@@ -190,11 +176,6 @@
return activeDevices;
}
- @Override
- public void showDetail(boolean show) {
- showDetail(null /* view */);
- }
-
private static class DialogHolder {
private Dialog mDialog;
@@ -203,7 +184,7 @@
}
}
- private void showDetail(@Nullable View view) {
+ private void showDialog(@Nullable View view) {
mUiHandler.post(() -> {
final DialogHolder holder = new DialogHolder();
final Dialog dialog = MediaRouteDialogPresenter.createDialog(
@@ -218,7 +199,7 @@
holder.init(dialog);
SystemUIDialog.setShowForAllUsers(dialog, true);
SystemUIDialog.registerDismissListener(dialog);
- SystemUIDialog.setWindowOnTop(dialog);
+ SystemUIDialog.setWindowOnTop(dialog, mKeyguard.isShowing());
mUiHandler.post(() -> {
if (view != null) {
@@ -268,10 +249,8 @@
if (!state.value) {
state.secondaryLabel = "";
}
- state.contentDescription = state.contentDescription + ","
- + mContext.getString(R.string.accessibility_quick_settings_open_details);
state.expandedAccessibilityClassName = Button.class.getName();
- state.forceExpandIcon = willPopDetail();
+ state.forceExpandIcon = willPopDialog();
} else {
state.state = Tile.STATE_UNAVAILABLE;
String noWifi = mContext.getString(R.string.quick_settings_cast_no_wifi);
@@ -279,7 +258,6 @@
state.forceExpandIcon = false;
}
state.stateDescription = state.stateDescription + ", " + state.secondaryLabel;
- mDetailAdapter.updateItems(devices);
}
@Override
@@ -339,118 +317,4 @@
refreshState();
}
};
-
- private final class CastDetailAdapter implements DetailAdapter, QSDetailItems.Callback {
- private final LinkedHashMap<String, CastDevice> mVisibleOrder = new LinkedHashMap<>();
-
- private QSDetailItems mItems;
-
- @Override
- public CharSequence getTitle() {
- return mContext.getString(R.string.quick_settings_cast_title);
- }
-
- @Override
- public Boolean getToggleState() {
- return null;
- }
-
- @Override
- public Intent getSettingsIntent() {
- return CAST_SETTINGS;
- }
-
- @Override
- public void setToggleState(boolean state) {
- // noop
- }
-
- @Override
- public int getMetricsCategory() {
- return MetricsEvent.QS_CAST_DETAILS;
- }
-
- @Override
- public View createDetailView(Context context, View convertView, ViewGroup parent) {
- mItems = QSDetailItems.convertOrInflate(context, convertView, parent);
- mItems.setTagSuffix("Cast");
- if (convertView == null) {
- if (DEBUG) Log.d(TAG, "addOnAttachStateChangeListener");
- mItems.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
- @Override
- public void onViewAttachedToWindow(View v) {
- if (DEBUG) Log.d(TAG, "onViewAttachedToWindow");
- }
-
- @Override
- public void onViewDetachedFromWindow(View v) {
- if (DEBUG) Log.d(TAG, "onViewDetachedFromWindow");
- mVisibleOrder.clear();
- }
- });
- }
- mItems.setEmptyState(R.drawable.ic_qs_cast_detail_empty,
- R.string.quick_settings_cast_detail_empty_text);
- mItems.setCallback(this);
- updateItems(mController.getCastDevices());
- mController.setDiscovering(true);
- return mItems;
- }
-
- private void updateItems(List<CastDevice> devices) {
- if (mItems == null) return;
- Item[] items = null;
- if (devices != null && !devices.isEmpty()) {
- // if we are connected, simply show that device
- for (CastDevice device : devices) {
- if (device.state == CastDevice.STATE_CONNECTED) {
- final Item item =
- new Item(
- R.drawable.ic_cast_connected,
- getDeviceName(device),
- device);
- item.line2 = mContext.getString(R.string.quick_settings_connected);
- item.canDisconnect = true;
- items = new Item[] { item };
- break;
- }
- }
- // otherwise list all available devices, and don't move them around
- if (items == null) {
- for (CastDevice device : devices) {
- mVisibleOrder.put(device.id, device);
- }
- items = new Item[devices.size()];
- int i = 0;
- for (String id : mVisibleOrder.keySet()) {
- final CastDevice device = mVisibleOrder.get(id);
- if (!devices.contains(device)) continue;
- final Item item =
- new Item(R.drawable.ic_cast, getDeviceName(device), device);
- if (device.state == CastDevice.STATE_CONNECTING) {
- item.line2 = mContext.getString(R.string.quick_settings_connecting);
- }
- items[i++] = item;
- }
- }
- }
- mItems.setItems(items);
- }
-
- @Override
- public void onDetailItemClick(Item item) {
- if (item == null || item.tag == null) return;
- MetricsLogger.action(mContext, MetricsEvent.QS_CAST_SELECT);
- final CastDevice device = (CastDevice) item.tag;
- mController.startCasting(device);
- }
-
- @Override
- public void onDetailItemDisconnect(Item item) {
- if (item == null || item.tag == null) return;
- MetricsLogger.action(mContext, MetricsEvent.QS_CAST_DISCONNECT);
- final CastDevice device = (CastDevice) item.tag;
- mController.stopCasting(device);
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 698a253..04a25fc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -32,9 +32,7 @@
import android.telephony.SubscriptionManager;
import android.text.Html;
import android.text.TextUtils;
-import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewGroup;
import android.view.WindowManager.LayoutParams;
import android.widget.Switch;
@@ -49,7 +47,6 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSIconView;
import com.android.systemui.plugins.qs.QSTile.SignalState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -62,6 +59,7 @@
import com.android.systemui.statusbar.connectivity.NetworkController;
import com.android.systemui.statusbar.connectivity.SignalCallback;
import com.android.systemui.statusbar.phone.SystemUIDialog;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import javax.inject.Inject;
@@ -71,8 +69,7 @@
private final NetworkController mController;
private final DataUsageController mDataController;
- private final CellularDetailAdapter mDetailAdapter;
-
+ private final KeyguardStateController mKeyguard;
private final CellSignalCallback mSignalCallback = new CellSignalCallback();
@Inject
@@ -85,13 +82,15 @@
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
QSLogger qsLogger,
- NetworkController networkController
+ NetworkController networkController,
+ KeyguardStateController keyguardStateController
+
) {
super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
statusBarStateController, activityStarter, qsLogger);
mController = networkController;
+ mKeyguard = keyguardStateController;
mDataController = mController.getMobileDataController();
- mDetailAdapter = new CellularDetailAdapter();
mController.observe(getLifecycle(), mSignalCallback);
}
@@ -106,11 +105,6 @@
}
@Override
- public DetailAdapter getDetailAdapter() {
- return mDetailAdapter;
- }
-
- @Override
public Intent getLongClickIntent() {
if (getState().state == Tile.STATE_UNAVAILABLE) {
return new Intent(Settings.ACTION_WIRELESS_SETTINGS);
@@ -155,18 +149,13 @@
dialog.getWindow().setType(LayoutParams.TYPE_KEYGUARD_DIALOG);
SystemUIDialog.setShowForAllUsers(dialog, true);
SystemUIDialog.registerDismissListener(dialog);
- SystemUIDialog.setWindowOnTop(dialog);
+ SystemUIDialog.setWindowOnTop(dialog, mKeyguard.isShowing());
dialog.show();
}
@Override
protected void handleSecondaryClick(@Nullable View view) {
- if (mDataController.isMobileDataSupported()) {
- showDetail(true);
- } else {
- mActivityStarter
- .postStartActivityDismissingKeyguard(getCellularSettingIntent(),0 /* delay */);
- }
+ handleLongClick(view);
}
@Override
@@ -298,11 +287,6 @@
mInfo.airplaneModeEnabled = icon.visible;
refreshState(mInfo);
}
-
- @Override
- public void setMobileDataEnabled(boolean enabled) {
- mDetailAdapter.setMobileDataEnabled(enabled);
- }
}
static Intent getCellularSettingIntent() {
@@ -314,53 +298,4 @@
}
return intent;
}
-
- private final class CellularDetailAdapter implements DetailAdapter {
-
- @Override
- public CharSequence getTitle() {
- return mContext.getString(R.string.quick_settings_cellular_detail_title);
- }
-
- @Nullable
- @Override
- public Boolean getToggleState() {
- return mDataController.isMobileDataSupported()
- ? mDataController.isMobileDataEnabled()
- : null;
- }
-
- @Override
- public Intent getSettingsIntent() {
- return getCellularSettingIntent();
- }
-
- @Override
- public void setToggleState(boolean state) {
- MetricsLogger.action(mContext, MetricsEvent.QS_CELLULAR_TOGGLE, state);
- mDataController.setMobileDataEnabled(state);
- }
-
- @Override
- public int getMetricsCategory() {
- return MetricsEvent.QS_DATAUSAGEDETAIL;
- }
-
- @Override
- public View createDetailView(Context context, View convertView, ViewGroup parent) {
- final DataUsageDetailView v = (DataUsageDetailView) (convertView != null
- ? convertView
- : LayoutInflater.from(mContext).inflate(R.layout.data_usage, parent, false));
- final DataUsageController.DataUsageInfo info = mDataController.getDataUsageInfo();
- if (info == null) return v;
- v.bind(info);
- v.findViewById(R.id.roaming_text).setVisibility(mSignalCallback.mInfo.roaming
- ? View.VISIBLE : View.INVISIBLE);
- return v;
- }
-
- public void setMobileDataEnabled(boolean enabled) {
- fireToggleStateChanged(enabled);
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index a06dc8b..6cff4cd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -25,8 +25,6 @@
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
@@ -34,16 +32,10 @@
import android.provider.Settings;
import android.provider.Settings.Global;
import android.service.notification.ZenModeConfig;
-import android.service.notification.ZenModeConfig.ZenRule;
import android.service.quicksettings.Tile;
import android.text.TextUtils;
-import android.util.Slog;
-import android.view.LayoutInflater;
import android.view.View;
-import android.view.View.OnAttachStateChangeListener;
-import android.view.ViewGroup;
import android.widget.Switch;
-import android.widget.Toast;
import androidx.annotation.Nullable;
@@ -52,23 +44,21 @@
import com.android.settingslib.notification.EnableZenModeDialog;
import com.android.systemui.Prefs;
import com.android.systemui.R;
-import com.android.systemui.SysUIToast;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSTile.BooleanState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.SettingObserver;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.qs.tiles.dialog.QSZenModeDialogMetricsLogger;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.util.settings.SecureSettings;
-import com.android.systemui.volume.ZenModePanel;
import javax.inject.Inject;
@@ -82,13 +72,12 @@
new Intent(Settings.ACTION_ZEN_MODE_PRIORITY_SETTINGS);
private final ZenModeController mController;
- private final DndDetailAdapter mDetailAdapter;
private final SharedPreferences mSharedPreferences;
private final SettingObserver mSettingZenDuration;
private final DialogLaunchAnimator mDialogLaunchAnimator;
+ private final QSZenModeDialogMetricsLogger mQSZenDialogMetricsLogger;
private boolean mListening;
- private boolean mShowingDetail;
@Inject
public DndTile(
@@ -109,7 +98,6 @@
statusBarStateController, activityStarter, qsLogger);
mController = zenModeController;
mSharedPreferences = sharedPreferences;
- mDetailAdapter = new DndDetailAdapter();
mController.observe(getLifecycle(), mZenCallback);
mDialogLaunchAnimator = dialogLaunchAnimator;
mSettingZenDuration = new SettingObserver(secureSettings, mUiHandler,
@@ -119,6 +107,7 @@
refreshState();
}
};
+ mQSZenDialogMetricsLogger = new QSZenModeDialogMetricsLogger(mContext);
}
public static void setVisible(Context context, boolean visible) {
@@ -139,11 +128,6 @@
}
@Override
- public DetailAdapter getDetailAdapter() {
- return mDetailAdapter;
- }
-
- @Override
public BooleanState newTileState() {
return new BooleanState();
}
@@ -211,7 +195,8 @@
private Dialog makeZenModeDialog() {
AlertDialog dialog = new EnableZenModeDialog(mContext, R.style.Theme_SystemUI_Dialog,
- true /* cancelIsNeutral */).createDialog();
+ true /* cancelIsNeutral */,
+ mQSZenDialogMetricsLogger).createDialog();
SystemUIDialog.applyFlags(dialog);
SystemUIDialog.setShowForAllUsers(dialog, true);
SystemUIDialog.registerDismissListener(dialog);
@@ -221,28 +206,7 @@
@Override
protected void handleSecondaryClick(@Nullable View view) {
- if (mController.isVolumeRestricted()) {
- // Collapse the panels, so the user can see the toast.
- mHost.collapsePanels();
- SysUIToast.makeText(mContext, mContext.getString(
- com.android.internal.R.string.error_message_change_not_allowed),
- Toast.LENGTH_LONG).show();
- return;
- }
- if (!mState.value) {
- // Because of the complexity of the zen panel, it needs to be shown after
- // we turn on zen below.
- mController.addCallback(new ZenModeController.Callback() {
- @Override
- public void onZenChanged(int zen) {
- mController.removeCallback(this);
- showDetail(true);
- }
- });
- mController.setZen(Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, TAG);
- } else {
- showDetail(true);
- }
+ handleLongClick(view);
}
@Override
@@ -291,9 +255,6 @@
R.string.accessibility_quick_settings_dnd);
break;
}
- if (valueChanged) {
- fireToggleStateChanged(state.value);
- }
state.dualLabelContentDescription = mContext.getResources().getString(
R.string.accessibility_quick_settings_open_settings, getTileLabel());
state.expandedAccessibilityClassName = Switch.class.getName();
@@ -345,146 +306,6 @@
private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
public void onZenChanged(int zen) {
refreshState(zen);
- if (isShowingDetail()) {
- mDetailAdapter.updatePanel();
- }
- }
-
- @Override
- public void onConfigChanged(ZenModeConfig config) {
- if (isShowingDetail()) {
- mDetailAdapter.updatePanel();
- }
- }
- };
-
- private final class DndDetailAdapter implements DetailAdapter, OnAttachStateChangeListener {
-
- @Nullable
- private ZenModePanel mZenPanel;
- private boolean mAuto;
-
- @Override
- public CharSequence getTitle() {
- return mContext.getString(R.string.quick_settings_dnd_label);
- }
-
- @Override
- public Boolean getToggleState() {
- return mState.value;
- }
-
- @Override
- public Intent getSettingsIntent() {
- return ZEN_SETTINGS;
- }
-
- @Override
- public void setToggleState(boolean state) {
- MetricsLogger.action(mContext, MetricsEvent.QS_DND_TOGGLE, state);
- if (!state) {
- mController.setZen(ZEN_MODE_OFF, null, TAG);
- mAuto = false;
- } else {
- mController.setZen(Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, TAG);
- }
- }
-
- @Override
- public int getMetricsCategory() {
- return MetricsEvent.QS_DND_DETAILS;
- }
-
- @Override
- public View createDetailView(Context context, View convertView, ViewGroup parent) {
- mZenPanel = convertView != null ? (ZenModePanel) convertView
- : (ZenModePanel) LayoutInflater.from(context).inflate(
- R.layout.zen_mode_panel, parent, false);
- if (convertView == null) {
- mZenPanel.init(mController);
- mZenPanel.addOnAttachStateChangeListener(this);
- mZenPanel.setCallback(mZenModePanelCallback);
- mZenPanel.setEmptyState(R.drawable.ic_qs_dnd_detail_empty, R.string.dnd_is_off);
- }
- updatePanel();
- return mZenPanel;
- }
-
- private void updatePanel() {
- if (mZenPanel == null) return;
- mAuto = false;
- if (mController.getZen() == ZEN_MODE_OFF) {
- mZenPanel.setState(ZenModePanel.STATE_OFF);
- } else {
- ZenModeConfig config = mController.getConfig();
- String summary = "";
- if (config.manualRule != null && config.manualRule.enabler != null) {
- summary = getOwnerCaption(config.manualRule.enabler);
- }
- for (ZenRule automaticRule : config.automaticRules.values()) {
- if (automaticRule.isAutomaticActive()) {
- if (summary.isEmpty()) {
- summary = mContext.getString(R.string.qs_dnd_prompt_auto_rule,
- automaticRule.name);
- } else {
- summary = mContext.getString(R.string.qs_dnd_prompt_auto_rule_app);
- }
- }
- }
- if (summary.isEmpty()) {
- mZenPanel.setState(ZenModePanel.STATE_MODIFY);
- } else {
- mAuto = true;
- mZenPanel.setState(ZenModePanel.STATE_AUTO_RULE);
- mZenPanel.setAutoText(summary);
- }
- }
- }
-
- private String getOwnerCaption(String owner) {
- final PackageManager pm = mContext.getPackageManager();
- try {
- final ApplicationInfo info = pm.getApplicationInfo(owner, 0);
- if (info != null) {
- final CharSequence seq = info.loadLabel(pm);
- if (seq != null) {
- final String str = seq.toString().trim();
- return mContext.getString(R.string.qs_dnd_prompt_app, str);
- }
- }
- } catch (Throwable e) {
- Slog.w(TAG, "Error loading owner caption", e);
- }
- return "";
- }
-
- @Override
- public void onViewAttachedToWindow(View v) {
- mShowingDetail = true;
- }
-
- @Override
- public void onViewDetachedFromWindow(View v) {
- mShowingDetail = false;
- mZenPanel = null;
- }
- }
-
- private final ZenModePanel.Callback mZenModePanelCallback = new ZenModePanel.Callback() {
- @Override
- public void onPrioritySettings() {
- mActivityStarter.postStartActivityDismissingKeyguard(
- ZEN_PRIORITY_SETTINGS, 0);
- }
-
- @Override
- public void onInteraction() {
- // noop
- }
-
- @Override
- public void onExpanded(boolean expanded) {
- // noop
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
index 9df942d..cd7021e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
@@ -411,10 +411,6 @@
}
boolean wifiConnected = cb.mEnabled && (cb.mWifiSignalIconId > 0) && (cb.mSsid != null);
boolean wifiNotConnected = (cb.mWifiSignalIconId > 0) && (cb.mSsid == null);
- boolean enabledChanging = state.value != cb.mEnabled;
- if (enabledChanging) {
- fireToggleStateChanged(cb.mEnabled);
- }
if (state.slash == null) {
state.slash = new SlashState();
state.slash.rotation = 6;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java
index 0be0619..f4dd415 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java
@@ -36,7 +36,6 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSHost;
@@ -134,12 +133,6 @@
return new Intent(Settings.ACTION_PRIVACY_SETTINGS);
}
- @Nullable
- @Override
- public DetailAdapter getDetailAdapter() {
- return super.getDetailAdapter();
- }
-
@Override
public void onSensorBlockedChanged(int sensor, boolean blocked) {
if (sensor == getSensorId()) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
index 076ef35..5840a3d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
@@ -150,6 +150,6 @@
}
protected int getFontSizeDimen() {
- return R.dimen.qs_detail_item_secondary_text_size;
+ return R.dimen.qs_tile_text_size;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
deleted file mode 100644
index db1b6e6..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2015 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.qs.tiles;
-
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.os.Looper;
-import android.provider.Settings;
-import android.util.Pair;
-import android.view.View;
-
-import androidx.annotation.Nullable;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.dagger.qualifiers.Background;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.plugins.qs.DetailAdapter;
-import com.android.systemui.plugins.qs.QSTile;
-import com.android.systemui.plugins.qs.QSTile.State;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.qs.QSHost;
-import com.android.systemui.qs.logging.QSLogger;
-import com.android.systemui.qs.tileimpl.QSTileImpl;
-import com.android.systemui.statusbar.policy.UserInfoController;
-import com.android.systemui.statusbar.policy.UserSwitcherController;
-
-import javax.inject.Inject;
-
-public class UserTile extends QSTileImpl<State> implements UserInfoController.OnUserInfoChangedListener {
-
- private final UserSwitcherController mUserSwitcherController;
- private final UserInfoController mUserInfoController;
- @Nullable
- private Pair<String, Drawable> mLastUpdate;
-
- @Inject
- public UserTile(
- QSHost host,
- @Background Looper backgroundLooper,
- @Main Handler mainHandler,
- FalsingManager falsingManager,
- MetricsLogger metricsLogger,
- StatusBarStateController statusBarStateController,
- ActivityStarter activityStarter,
- QSLogger qsLogger,
- UserSwitcherController userSwitcherController,
- UserInfoController userInfoController
- ) {
- super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
- statusBarStateController, activityStarter, qsLogger);
- mUserSwitcherController = userSwitcherController;
- mUserInfoController = userInfoController;
- mUserInfoController.observe(getLifecycle(), this);
- }
-
- @Override
- public State newTileState() {
- return new QSTile.State();
- }
-
- @Override
- public Intent getLongClickIntent() {
- return new Intent(Settings.ACTION_USER_SETTINGS);
- }
-
- @Override
- protected void handleClick(@Nullable View view) {
- showDetail(true);
- }
-
- @Override
- public DetailAdapter getDetailAdapter() {
- return mUserSwitcherController.mUserDetailAdapter;
- }
-
- @Override
- public int getMetricsCategory() {
- return MetricsEvent.QS_USER_TILE;
- }
-
- @Override
- public CharSequence getTileLabel() {
- return getState().label;
- }
-
- @Override
- protected void handleUpdateState(State state, Object arg) {
- final Pair<String, Drawable> p = arg != null ? (Pair<String, Drawable>) arg : mLastUpdate;
- if (p != null) {
- state.label = p.first;
- // TODO: Better content description.
- state.contentDescription = p.first;
- state.icon = new Icon() {
- @Override
- public Drawable getDrawable(Context context) {
- return p.second;
- }
- };
- } else {
- // TODO: Default state.
- }
- }
-
- @Override
- public void onUserInfoChanged(String name, Drawable picture, String userAccount) {
- mLastUpdate = new Pair<>(name, picture);
- refreshState(mLastUpdate);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index c82ff34..b2be56c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -28,27 +28,22 @@
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
-import android.view.ViewGroup;
import android.widget.Switch;
import androidx.annotation.Nullable;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.settingslib.wifi.AccessPoint;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSIconView;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTile.SignalState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.AlphaControlledSignalTileView;
-import com.android.systemui.qs.QSDetailItems;
-import com.android.systemui.qs.QSDetailItems.Item;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSIconViewImpl;
@@ -58,9 +53,6 @@
import com.android.systemui.statusbar.connectivity.SignalCallback;
import com.android.systemui.statusbar.connectivity.WifiIcons;
import com.android.systemui.statusbar.connectivity.WifiIndicators;
-import com.android.wifitrackerlib.WifiEntry;
-
-import java.util.List;
import javax.inject.Inject;
@@ -70,7 +62,6 @@
protected final NetworkController mController;
private final AccessPointController mWifiController;
- private final WifiDetailAdapter mDetailAdapter;
private final QSTile.SignalState mStateBeforeClick = newTileState();
protected final WifiSignalCallback mSignalCallback = new WifiSignalCallback();
@@ -93,7 +84,6 @@
statusBarStateController, activityStarter, qsLogger);
mController = networkController;
mWifiController = accessPointController;
- mDetailAdapter = (WifiDetailAdapter) createDetailAdapter();
mController.observe(getLifecycle(), mSignalCallback);
mStateBeforeClick.spec = "wifi";
}
@@ -104,25 +94,6 @@
}
@Override
- public void setDetailListening(boolean listening) {
- if (listening) {
- mWifiController.addAccessPointCallback(mDetailAdapter);
- } else {
- mWifiController.removeAccessPointCallback(mDetailAdapter);
- }
- }
-
- @Override
- public DetailAdapter getDetailAdapter() {
- return mDetailAdapter;
- }
-
- @Override
- protected DetailAdapter createDetailAdapter() {
- return new WifiDetailAdapter();
- }
-
- @Override
public QSIconView createTileView(Context context) {
return new AlphaControlledSignalTileView(context);
}
@@ -158,7 +129,6 @@
new Intent(Settings.ACTION_WIFI_SETTINGS), 0);
return;
}
- showDetail(true);
if (!mState.value) {
mController.setWifiEnabled(true);
}
@@ -185,11 +155,6 @@
&& (cb.ssid != null || cb.wifiSignalIconId != WifiIcons.QS_WIFI_NO_NETWORK);
boolean wifiNotConnected = (cb.ssid == null)
&& (cb.wifiSignalIconId == WifiIcons.QS_WIFI_NO_NETWORK);
- boolean enabledChanging = state.value != cb.enabled;
- if (enabledChanging) {
- mDetailAdapter.setItemsVisible(cb.enabled);
- fireToggleStateChanged(cb.enabled);
- }
if (state.slash == null) {
state.slash = new SlashState();
state.slash.rotation = 6;
@@ -315,150 +280,7 @@
mInfo.wifiSignalContentDescription = indicators.qsIcon.contentDescription;
mInfo.isTransient = indicators.isTransient;
mInfo.statusLabel = indicators.statusLabel;
- if (isShowingDetail()) {
- mDetailAdapter.updateItems();
- }
refreshState();
}
}
-
- protected class WifiDetailAdapter implements DetailAdapter,
- AccessPointController.AccessPointCallback, QSDetailItems.Callback {
-
- @Nullable
- private QSDetailItems mItems;
- @Nullable
- private WifiEntry[] mAccessPoints;
-
- @Override
- public CharSequence getTitle() {
- return mContext.getString(R.string.quick_settings_wifi_label);
- }
-
- public Intent getSettingsIntent() {
- return WIFI_SETTINGS;
- }
-
- @Override
- public Boolean getToggleState() {
- return mState.value;
- }
-
- @Override
- public void setToggleState(boolean state) {
- if (DEBUG) Log.d(TAG, "setToggleState " + state);
- MetricsLogger.action(mContext, MetricsEvent.QS_WIFI_TOGGLE, state);
- mController.setWifiEnabled(state);
- }
-
- @Override
- public int getMetricsCategory() {
- return MetricsEvent.QS_WIFI_DETAILS;
- }
-
- @Override
- public View createDetailView(Context context, View convertView, ViewGroup parent) {
- if (DEBUG) Log.d(TAG, "createDetailView convertView=" + (convertView != null));
- mAccessPoints = null;
- mItems = QSDetailItems.convertOrInflate(context, convertView, parent);
- mItems.setTagSuffix("Wifi");
- mItems.setCallback(this);
- mWifiController.scanForAccessPoints(); // updates APs and items
- setItemsVisible(mState.value);
- return mItems;
- }
-
- @Override
- public void onAccessPointsChanged(final List<WifiEntry> accessPoints) {
- mAccessPoints = filterUnreachableAPs(accessPoints);
-
- updateItems();
- }
-
- /** Filter unreachable APs from mAccessPoints */
- private WifiEntry[] filterUnreachableAPs(List<WifiEntry> unfiltered) {
- int numReachable = 0;
- for (WifiEntry ap : unfiltered) {
- if (isWifiEntryReachable(ap)) numReachable++;
- }
- if (numReachable != unfiltered.size()) {
- WifiEntry[] accessPoints = new WifiEntry[numReachable];
- int i = 0;
- for (WifiEntry ap : unfiltered) {
- if (isWifiEntryReachable(ap)) accessPoints[i++] = ap;
- }
- return accessPoints;
- }
- return unfiltered.toArray(new WifiEntry[0]);
- }
-
- @Override
- public void onSettingsActivityTriggered(Intent settingsIntent) {
- mActivityStarter.postStartActivityDismissingKeyguard(settingsIntent, 0);
- }
-
- @Override
- public void onDetailItemClick(Item item) {
- if (item == null || item.tag == null) return;
- final WifiEntry ap = (WifiEntry) item.tag;
- if (ap.getConnectedState() == WifiEntry.CONNECTED_STATE_DISCONNECTED) {
- if (mWifiController.connect(ap)) {
- mHost.collapsePanels();
- }
- }
- showDetail(false);
- }
-
- @Override
- public void onDetailItemDisconnect(Item item) {
- // noop
- }
-
- public void setItemsVisible(boolean visible) {
- if (mItems == null) return;
- mItems.setItemsVisible(visible);
- }
-
- private void updateItems() {
- if (mItems == null) return;
- if ((mAccessPoints != null && mAccessPoints.length > 0)
- || !mSignalCallback.mInfo.enabled) {
- fireScanStateChanged(false);
- } else {
- fireScanStateChanged(true);
- }
-
- // Wi-Fi is off
- if (!mSignalCallback.mInfo.enabled) {
- mItems.setEmptyState(WifiIcons.QS_WIFI_NO_NETWORK,
- R.string.wifi_is_off);
- mItems.setItems(null);
- return;
- }
-
- // No available access points
- mItems.setEmptyState(WifiIcons.QS_WIFI_NO_NETWORK,
- R.string.quick_settings_wifi_detail_empty_text);
-
- // Build the list
- Item[] items = null;
- if (mAccessPoints != null) {
- items = new Item[mAccessPoints.length];
- for (int i = 0; i < mAccessPoints.length; i++) {
- final WifiEntry ap = mAccessPoints[i];
- final Item item = new Item(mWifiController.getIcon(ap), ap.getSsid(), ap);
- item.line2 = ap.getSummary();
- item.icon2 = ap.getSecurity() != AccessPoint.SECURITY_NONE
- ? R.drawable.qs_ic_wifi_lock
- : -1;
- items[i] = item;
- }
- }
- mItems.setItems(items);
- }
- }
-
- private static boolean isWifiEntryReachable(WifiEntry ap) {
- return ap.getLevel() != WifiEntry.WIFI_LEVEL_UNREACHABLE;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
index 8e01942..8b6ddb4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
@@ -65,6 +65,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.phone.SystemUIDialog;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.wifitrackerlib.WifiEntry;
import java.util.List;
@@ -130,6 +131,7 @@
private Button mDoneButton;
private Button mAirplaneModeButton;
private Drawable mBackgroundOn;
+ private KeyguardStateController mKeyguard;
@Nullable
private Drawable mBackgroundOff = null;
private int mDefaultDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -159,7 +161,8 @@
public InternetDialog(Context context, InternetDialogFactory internetDialogFactory,
InternetDialogController internetDialogController, boolean canConfigMobileData,
boolean canConfigWifi, boolean aboveStatusBar, UiEventLogger uiEventLogger,
- @Main Handler handler, @Background Executor executor) {
+ @Main Handler handler, @Background Executor executor,
+ KeyguardStateController keyguardStateController) {
super(context);
if (DEBUG) {
Log.d(TAG, "Init InternetDialog");
@@ -177,6 +180,7 @@
mWifiManager = mInternetDialogController.getWifiManager();
mCanConfigMobileData = canConfigMobileData;
mCanConfigWifi = canConfigWifi;
+ mKeyguard = keyguardStateController;
mUiEventLogger = uiEventLogger;
mAdapter = new InternetAdapter(mInternetDialogController);
@@ -615,7 +619,7 @@
mAlertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
SystemUIDialog.setShowForAllUsers(mAlertDialog, true);
SystemUIDialog.registerDismissListener(mAlertDialog);
- SystemUIDialog.setWindowOnTop(mAlertDialog);
+ SystemUIDialog.setWindowOnTop(mAlertDialog, mKeyguard.isShowing());
mAlertDialog.show();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt
index 79f7ac3..4386169 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt
@@ -24,6 +24,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.statusbar.policy.KeyguardStateController
import java.util.concurrent.Executor
import javax.inject.Inject
@@ -40,7 +41,8 @@
private val internetDialogController: InternetDialogController,
private val context: Context,
private val uiEventLogger: UiEventLogger,
- private val dialogLaunchAnimator: DialogLaunchAnimator
+ private val dialogLaunchAnimator: DialogLaunchAnimator,
+ private val keyguardStateController: KeyguardStateController
) {
companion object {
var internetDialog: InternetDialog? = null
@@ -61,7 +63,7 @@
} else {
internetDialog = InternetDialog(context, this, internetDialogController,
canConfigMobileData, canConfigWifi, aboveStatusBar, uiEventLogger, handler,
- executor)
+ executor, keyguardStateController)
if (view != null) {
dialogLaunchAnimator.showFromView(internetDialog!!, view,
animateBackgroundBoundsChange = true)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/QSZenModeDialogMetricsLogger.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/QSZenModeDialogMetricsLogger.java
new file mode 100644
index 0000000..1b81a99
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/QSZenModeDialogMetricsLogger.java
@@ -0,0 +1,71 @@
+/*
+ * 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.systemui.qs.tiles.dialog;
+
+import android.content.Context;
+
+import com.android.internal.logging.UiEventLogger;
+import com.android.settingslib.notification.ZenModeDialogMetricsLogger;
+import com.android.systemui.qs.QSDndEvent;
+import com.android.systemui.qs.QSEvents;
+
+/**
+ * Logs ui events for the DND dialog that may appear from tapping the QS DND tile.
+ * To see the dialog from QS:
+ * Settings > Notifications > Do Not Disturb > Duration for Quick Settings > Ask every time
+ *
+ * Other names for DND (Do Not Disturb) include "Zen" and "Priority only".
+ */
+public class QSZenModeDialogMetricsLogger extends ZenModeDialogMetricsLogger {
+ private final UiEventLogger mUiEventLogger = QSEvents.INSTANCE.getQsUiEventsLogger();
+
+ public QSZenModeDialogMetricsLogger(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void logOnEnableZenModeForever() {
+ super.logOnEnableZenModeForever();
+ mUiEventLogger.log(QSDndEvent.QS_DND_DIALOG_ENABLE_FOREVER);
+ }
+
+ @Override
+ public void logOnEnableZenModeUntilAlarm() {
+ super.logOnEnableZenModeUntilAlarm();
+ mUiEventLogger.log(QSDndEvent.QS_DND_DIALOG_ENABLE_UNTIL_ALARM);
+ }
+
+ @Override
+ public void logOnEnableZenModeUntilCountdown() {
+ super.logOnEnableZenModeUntilCountdown();
+ mUiEventLogger.log(QSDndEvent.QS_DND_DIALOG_ENABLE_UNTIL_COUNTDOWN);
+ }
+
+ @Override
+ public void logOnConditionSelected() {
+ super.logOnConditionSelected();
+ mUiEventLogger.log(QSDndEvent.QS_DND_CONDITION_SELECT);
+ }
+
+ @Override
+ public void logOnClickTimeButton(boolean up) {
+ super.logOnClickTimeButton(up);
+ mUiEventLogger.log(up
+ ? QSDndEvent.QS_DND_TIME_UP : QSDndEvent.QS_DND_TIME_DOWN);
+ }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt b/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt
index 7c8f4b1..8c8c5c8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt
@@ -24,11 +24,13 @@
import android.view.LayoutInflater
import android.view.View
import androidx.annotation.VisibleForTesting
+import com.android.internal.logging.UiEventLogger
import com.android.systemui.R
import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.qs.QSUserSwitcherEvent
import com.android.systemui.qs.tiles.UserDetailView
import com.android.systemui.statusbar.phone.SystemUIDialog
import javax.inject.Inject
@@ -43,6 +45,7 @@
private val activityStarter: ActivityStarter,
private val falsingManager: FalsingManager,
private val dialogLaunchAnimator: DialogLaunchAnimator,
+ private val uiEventLogger: UiEventLogger,
private val dialogFactory: (Context) -> SystemUIDialog
) {
@@ -51,12 +54,14 @@
userDetailViewAdapterProvider: Provider<UserDetailView.Adapter>,
activityStarter: ActivityStarter,
falsingManager: FalsingManager,
- dialogLaunchAnimator: DialogLaunchAnimator
+ dialogLaunchAnimator: DialogLaunchAnimator,
+ uiEventLogger: UiEventLogger
) : this(
userDetailViewAdapterProvider,
activityStarter,
falsingManager,
dialogLaunchAnimator,
+ uiEventLogger,
{ SystemUIDialog(it) }
)
@@ -76,10 +81,13 @@
setCanceledOnTouchOutside(true)
setTitle(R.string.qs_user_switch_dialog_title)
- setPositiveButton(R.string.quick_settings_done, null)
+ setPositiveButton(R.string.quick_settings_done) { _, _ ->
+ uiEventLogger.log(QSUserSwitcherEvent.QS_USER_DETAIL_CLOSE)
+ }
setNeutralButton(R.string.quick_settings_more_user_settings) { _, _ ->
if (!falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
dialogLaunchAnimator.disableAllCurrentDialogsExitAnimations()
+ uiEventLogger.log(QSUserSwitcherEvent.QS_USER_MORE_SETTINGS)
activityStarter.postStartActivityDismissingKeyguard(
USER_SETTINGS_INTENT,
0
@@ -95,6 +103,7 @@
adapter.linkToViewGroup(gridFrame.findViewById(R.id.grid))
dialogLaunchAnimator.showFromView(this, view)
+ uiEventLogger.log(QSUserSwitcherEvent.QS_USER_DETAIL_OPEN)
adapter.injectDialogShower(DialogShowerImpl(this, dialogLaunchAnimator))
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 30456a8..50765f2 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -51,7 +51,9 @@
import android.graphics.Insets;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
-import android.media.MediaActionSound;
+import android.media.AudioAttributes;
+import android.media.AudioSystem;
+import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
@@ -93,6 +95,7 @@
import com.google.common.util.concurrent.ListenableFuture;
+import java.io.File;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
@@ -248,7 +251,7 @@
private final WindowManager mWindowManager;
private final WindowManager.LayoutParams mWindowLayoutParams;
private final AccessibilityManager mAccessibilityManager;
- private final MediaActionSound mCameraSound;
+ private final MediaPlayer mCameraSound;
private final ScrollCaptureClient mScrollCaptureClient;
private final PhoneWindow mWindow;
private final DisplayManager mDisplayManager;
@@ -331,8 +334,13 @@
reloadAssets();
// Setup the Camera shutter sound
- mCameraSound = new MediaActionSound();
- mCameraSound.load(MediaActionSound.SHUTTER_CLICK);
+ mCameraSound = MediaPlayer.create(mContext,
+ Uri.fromFile(new File(mContext.getResources().getString(
+ com.android.internal.R.string.config_cameraShutterSound))), null,
+ new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .build(), AudioSystem.newAudioSessionId());
mCopyBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -430,7 +438,9 @@
void releaseContext() {
mContext.unregisterReceiver(mCopyBroadcastReceiver);
mContext.release();
- mCameraSound.release();
+ if (mCameraSound != null) {
+ mCameraSound.release();
+ }
mBgExecutor.shutdownNow();
}
@@ -806,7 +816,9 @@
*/
private void saveScreenshotAndToast(Consumer<Uri> finisher) {
// Play the shutter sound to notify that we've taken a screenshot
- mCameraSound.play(MediaActionSound.SHUTTER_CLICK);
+ if (mCameraSound != null) {
+ mCameraSound.start();
+ }
saveScreenshotInWorkerThread(
/* onComplete */ finisher,
@@ -840,7 +852,9 @@
mScreenshotView.createScreenshotDropInAnimation(screenRect, showFlash);
// Play the shutter sound to notify that we've taken a screenshot
- mCameraSound.play(MediaActionSound.SHUTTER_CLICK);
+ if (mCameraSound != null) {
+ mCameraSound.start();
+ }
if (DEBUG_ANIM) {
Log.d(TAG, "starting post-screenshot animation");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 2f5eaa6..b355b05 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -453,7 +453,9 @@
/** @see IStatusBar#updateMediaTapToTransferReceiverDisplay */
default void updateMediaTapToTransferReceiverDisplay(
@StatusBarManager.MediaTransferReceiverState int displayState,
- @NonNull MediaRoute2Info routeInfo) {}
+ @NonNull MediaRoute2Info routeInfo,
+ @Nullable Icon appIcon,
+ @Nullable CharSequence appName) {}
}
public CommandQueue(Context context) {
@@ -1208,10 +1210,14 @@
@Override
public void updateMediaTapToTransferReceiverDisplay(
int displayState,
- MediaRoute2Info routeInfo) {
+ @NonNull MediaRoute2Info routeInfo,
+ @Nullable Icon appIcon,
+ @Nullable CharSequence appName) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = displayState;
args.arg2 = routeInfo;
+ args.arg3 = appIcon;
+ args.arg4 = appName;
mHandler.obtainMessage(MSG_MEDIA_TRANSFER_RECEIVER_STATE, args).sendToTarget();
}
@@ -1629,9 +1635,11 @@
args = (SomeArgs) msg.obj;
int receiverDisplayState = (int) args.arg1;
MediaRoute2Info receiverRouteInfo = (MediaRoute2Info) args.arg2;
+ Icon appIcon = (Icon) args.arg3;
+ appName = (CharSequence) args.arg4;
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).updateMediaTapToTransferReceiverDisplay(
- receiverDisplayState, receiverRouteInfo);
+ receiverDisplayState, receiverRouteInfo, appIcon, appName);
}
args.recycle();
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
index 8e6cf36..4d933d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
@@ -31,6 +31,8 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry.OnSensitivityChangedListener;
+import java.util.ArrayList;
+
/**
* The view in the statusBar that contains part of the heads-up information
@@ -161,8 +163,8 @@
return mIconDrawingRect;
}
- public void onDarkChanged(Rect area, float darkIntensity, int tint) {
- mTextView.setTextColor(DarkIconDispatcher.getTint(area, this, tint));
+ public void onDarkChanged(ArrayList<Rect> areas, float darkIntensity, int tint) {
+ mTextView.setTextColor(DarkIconDispatcher.getTint(areas, this, tint));
}
public void setOnDrawingRectChangedListener(Runnable onDrawingRectChangedListener) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index eccf27e..0509a7c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -73,6 +73,7 @@
import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.KeyguardIndication;
@@ -132,6 +133,7 @@
private final DevicePolicyManager mDevicePolicyManager;
private final UserManager mUserManager;
protected final @Main DelayableExecutor mExecutor;
+ protected final @Background DelayableExecutor mBackgroundExecutor;
private final LockPatternUtils mLockPatternUtils;
private final IActivityManager mIActivityManager;
private final FalsingManager mFalsingManager;
@@ -203,6 +205,7 @@
IBatteryStats iBatteryStats,
UserManager userManager,
@Main DelayableExecutor executor,
+ @Background DelayableExecutor bgExecutor,
FalsingManager falsingManager,
LockPatternUtils lockPatternUtils,
ScreenLifecycle screenLifecycle,
@@ -220,6 +223,7 @@
mBatteryInfo = iBatteryStats;
mUserManager = userManager;
mExecutor = executor;
+ mBackgroundExecutor = bgExecutor;
mLockPatternUtils = lockPatternUtils;
mIActivityManager = iActivityManager;
mFalsingManager = falsingManager;
@@ -328,15 +332,22 @@
private void updateDisclosure() {
if (mOrganizationOwnedDevice) {
- final CharSequence organizationName = getOrganizationOwnedDeviceOrganizationName();
- final CharSequence disclosure = getDisclosureText(organizationName);
- mRotateTextViewController.updateIndication(
- INDICATION_TYPE_DISCLOSURE,
- new KeyguardIndication.Builder()
- .setMessage(disclosure)
- .setTextColor(mInitialTextColorState)
- .build(),
- /* updateImmediately */ false);
+ mBackgroundExecutor.execute(() -> {
+ final CharSequence organizationName = getOrganizationOwnedDeviceOrganizationName();
+ final CharSequence disclosure = getDisclosureText(organizationName);
+
+ mExecutor.execute(() -> {
+ if (mKeyguardStateController.isShowing()) {
+ mRotateTextViewController.updateIndication(
+ INDICATION_TYPE_DISCLOSURE,
+ new KeyguardIndication.Builder()
+ .setMessage(disclosure)
+ .setTextColor(mInitialTextColorState)
+ .build(),
+ /* updateImmediately */ false);
+ }
+ });
+ });
} else {
mRotateTextViewController.hideIndication(INDICATION_TYPE_DISCLOSURE);
}
@@ -364,26 +375,35 @@
}
private void updateOwnerInfo() {
- String info = mLockPatternUtils.getDeviceOwnerInfo();
- if (info == null) {
- // Use the current user owner information if enabled.
- final boolean ownerInfoEnabled = mLockPatternUtils.isOwnerInfoEnabled(
- KeyguardUpdateMonitor.getCurrentUser());
- if (ownerInfoEnabled) {
- info = mLockPatternUtils.getOwnerInfo(KeyguardUpdateMonitor.getCurrentUser());
+ // Check device owner info on a bg thread.
+ // It makes multiple IPCs that could block the thread it's run on.
+ mBackgroundExecutor.execute(() -> {
+ String info = mLockPatternUtils.getDeviceOwnerInfo();
+ if (info == null) {
+ // Use the current user owner information if enabled.
+ final boolean ownerInfoEnabled = mLockPatternUtils.isOwnerInfoEnabled(
+ KeyguardUpdateMonitor.getCurrentUser());
+ if (ownerInfoEnabled) {
+ info = mLockPatternUtils.getOwnerInfo(KeyguardUpdateMonitor.getCurrentUser());
+ }
}
- }
- if (!TextUtils.isEmpty(info)) {
- mRotateTextViewController.updateIndication(
- INDICATION_TYPE_OWNER_INFO,
- new KeyguardIndication.Builder()
- .setMessage(info)
- .setTextColor(mInitialTextColorState)
- .build(),
- false);
- } else {
- mRotateTextViewController.hideIndication(INDICATION_TYPE_OWNER_INFO);
- }
+
+ // Update the UI on the main thread.
+ final String finalInfo = info;
+ mExecutor.execute(() -> {
+ if (!TextUtils.isEmpty(finalInfo) && mKeyguardStateController.isShowing()) {
+ mRotateTextViewController.updateIndication(
+ INDICATION_TYPE_OWNER_INFO,
+ new KeyguardIndication.Builder()
+ .setMessage(finalInfo)
+ .setTextColor(mInitialTextColorState)
+ .build(),
+ false);
+ } else {
+ mRotateTextViewController.hideIndication(INDICATION_TYPE_OWNER_INFO);
+ }
+ });
+ });
}
private void updateBattery(boolean animate) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
index e19fd7a..01bdb40 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
@@ -29,7 +29,9 @@
import android.service.notification.StatusBarNotification;
import android.util.Log;
+import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.dagger.StatusBarModule;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.phone.NotificationListenerWithPlugins;
@@ -42,10 +44,13 @@
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.Executor;
+import javax.inject.Inject;
+
/**
* This class handles listening to notification updates and passing them along to
* NotificationPresenter to be displayed to the user.
*/
+@SysUISingleton
@SuppressLint("OverrideAbstract")
public class NotificationListener extends NotificationListenerWithPlugins {
private static final String TAG = "NotificationListener";
@@ -66,11 +71,14 @@
/**
* Injected constructor. See {@link StatusBarModule}.
*/
+ @Inject
public NotificationListener(
Context context,
NotificationManager notificationManager,
SystemClock systemClock,
- @Main Executor mainExecutor) {
+ @Main Executor mainExecutor,
+ PluginManager pluginManager) {
+ super(pluginManager);
mContext = context;
mNotificationManager = notificationManager;
mSystemClock = systemClock;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index ff9fc30..3dd717d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar;
-import static com.android.systemui.statusbar.phone.NotificationIconContainer.MAX_ICONS_ON_LOCKSCREEN;
-
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -41,6 +39,7 @@
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
+import com.android.systemui.statusbar.notification.row.NotificationBackgroundView;
import com.android.systemui.statusbar.notification.stack.AmbientState;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
@@ -48,7 +47,6 @@
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm;
import com.android.systemui.statusbar.notification.stack.ViewState;
import com.android.systemui.statusbar.phone.NotificationIconContainer;
-import com.android.systemui.util.Utils;
/**
* A notification shelf view that is placed inside the notification scroller. It manages the
@@ -85,7 +83,7 @@
private int mIndexOfFirstViewInShelf = -1;
private float mCornerAnimationDistance;
private NotificationShelfController mController;
- private int mActualWidth = -1;
+ private float mActualWidth = -1;
/** Fraction of lockscreen to shade animation (on lockscreen swipe down). */
private float mFractionToShade;
@@ -211,10 +209,6 @@
final float stackEnd = ambientState.getStackY() + ambientState.getStackHeight();
viewState.yTranslation = stackEnd - viewState.height;
-
- final int shortestWidth = mShelfIcons.calculateWidthFor(MAX_ICONS_ON_LOCKSCREEN);
- final float fraction = Interpolators.STANDARD.getInterpolation(mFractionToShade);
- updateStateWidth(viewState, fraction, shortestWidth);
} else {
viewState.hidden = true;
viewState.location = ExpandableViewState.LOCATION_GONE;
@@ -223,15 +217,23 @@
}
/**
- * @param shelfState View state for NotificationShelf
- * @param fraction Fraction of lockscreen to shade transition
+ * @param fractionToShade Fraction of lockscreen to shade transition
* @param shortestWidth Shortest width to use for lockscreen shelf
*/
@VisibleForTesting
- public void updateStateWidth(ShelfState shelfState, float fraction, int shortestWidth) {
- shelfState.actualWidth = mAmbientState.isOnKeyguard()
- ? (int) MathUtils.lerp(shortestWidth, getWidth(), fraction)
+ public void updateActualWidth(float fractionToShade, float shortestWidth) {
+ final float actualWidth = mAmbientState.isOnKeyguard()
+ ? MathUtils.lerp(shortestWidth, getWidth(), fractionToShade)
: getWidth();
+ ActivatableNotificationView anv = (ActivatableNotificationView) this;
+ NotificationBackgroundView bg = anv.getBackgroundNormal();
+ if (bg != null) {
+ anv.getBackgroundNormal().setActualWidth((int) actualWidth);
+ }
+ if (mShelfIcons != null) {
+ mShelfIcons.setActualLayoutWidth((int) actualWidth);
+ }
+ mActualWidth = actualWidth;
}
/**
@@ -245,7 +247,7 @@
* @return Actual width of shelf, accounting for possible ongoing width animation
*/
public int getActualWidth() {
- return mActualWidth > -1 ? mActualWidth : getWidth();
+ return mActualWidth > -1 ? (int) mActualWidth : getWidth();
}
/**
@@ -412,6 +414,10 @@
|| !mShowNotificationShelf
|| numViewsInShelf < 1f;
+ final float fractionToShade = Interpolators.STANDARD.getInterpolation(mFractionToShade);
+ final float shortestWidth = mShelfIcons.calculateWidthFor(numViewsInShelf);
+ updateActualWidth(fractionToShade, shortestWidth);
+
// TODO(b/172289889) transition last icon in shelf to notification icon and vice versa.
setVisibility(isHidden ? View.INVISIBLE : View.VISIBLE);
setBackgroundTop(backgroundTop);
@@ -921,30 +927,17 @@
public class ShelfState extends ExpandableViewState {
private boolean hasItemsInStableShelf;
private ExpandableView firstViewInShelf;
- public int actualWidth = -1;
-
- private void updateShelfWidth(View view) {
- if (actualWidth < 0) {
- return;
- }
- mActualWidth = actualWidth;
- ActivatableNotificationView anv = (ActivatableNotificationView) view;
- anv.getBackgroundNormal().setActualWidth(actualWidth);
- mShelfIcons.setActualLayoutWidth(actualWidth);
- }
@Override
public void applyToView(View view) {
if (!mShowNotificationShelf) {
return;
}
-
super.applyToView(view);
setIndexOfFirstViewInShelf(firstViewInShelf);
updateAppearance();
setHasItemsInStableShelf(hasItemsInStableShelf);
mShelfIcons.setAnimationsEnabled(mAnimationsEnabled);
- updateShelfWidth(view);
}
@Override
@@ -952,13 +945,11 @@
if (!mShowNotificationShelf) {
return;
}
-
super.animateTo(view, properties);
setIndexOfFirstViewInShelf(firstViewInShelf);
updateAppearance();
setHasItemsInStableShelf(hasItemsInStableShelf);
mShelfIcons.setAnimationsEnabled(mAnimationsEnabled);
- updateShelfWidth(view);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 4a7606c..72c4ce8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -37,6 +37,7 @@
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.Parcelable;
+import android.os.Trace;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
@@ -60,6 +61,7 @@
import com.android.systemui.util.drawable.DrawableSize;
import java.text.NumberFormat;
+import java.util.ArrayList;
import java.util.Arrays;
public class StatusBarIconView extends AnimatedImageView implements StatusIconDisplayable {
@@ -370,10 +372,13 @@
}
Drawable drawable;
try {
+ Trace.beginSection("StatusBarIconView#updateDrawable()");
drawable = getIcon(mIcon);
} catch (OutOfMemoryError e) {
Log.w(TAG, "OOM while inflating " + mIcon.icon + " for slot " + mSlot);
return false;
+ } finally {
+ Trace.endSection();
}
if (drawable == null) {
@@ -961,8 +966,8 @@
}
@Override
- public void onDarkChanged(Rect area, float darkIntensity, int tint) {
- int areaTint = getTint(area, this, tint);
+ public void onDarkChanged(ArrayList<Rect> areas, float darkIntensity, int tint) {
+ int areaTint = getTint(areas, this, tint);
ColorStateList color = ColorStateList.valueOf(areaTint);
setImageTintList(color);
setDecorColor(areaTint);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
index 68dcdd9..465ab93 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
@@ -17,7 +17,7 @@
package com.android.systemui.statusbar;
import static com.android.systemui.plugins.DarkIconDispatcher.getTint;
-import static com.android.systemui.plugins.DarkIconDispatcher.isInArea;
+import static com.android.systemui.plugins.DarkIconDispatcher.isInAreas;
import static com.android.systemui.statusbar.StatusBarIconView.STATE_DOT;
import static com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN;
import static com.android.systemui.statusbar.StatusBarIconView.STATE_ICON;
@@ -40,6 +40,8 @@
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
+import java.util.ArrayList;
+
public class StatusBarMobileView extends FrameLayout implements DarkReceiver,
StatusIconDisplayable {
private static final String TAG = "StatusBarMobileView";
@@ -222,11 +224,11 @@
}
@Override
- public void onDarkChanged(Rect area, float darkIntensity, int tint) {
- float intensity = isInArea(area, this) ? darkIntensity : 0;
+ public void onDarkChanged(ArrayList<Rect> areas, float darkIntensity, int tint) {
+ float intensity = isInAreas(areas, this) ? darkIntensity : 0;
mMobileDrawable.setTintList(
ColorStateList.valueOf(mDualToneHandler.getSingleColor(intensity)));
- ColorStateList color = ColorStateList.valueOf(getTint(area, this, tint));
+ ColorStateList color = ColorStateList.valueOf(getTint(areas, this, tint));
mIn.setImageTintList(color);
mOut.setImageTintList(color);
mMobileType.setImageTintList(color);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index ee12cc5..7811401 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -336,6 +336,9 @@
}
private void setDozeAmountInternal(float dozeAmount) {
+ if (Float.compare(dozeAmount, mDozeAmount) == 0) {
+ return;
+ }
mDozeAmount = dozeAmount;
float interpolatedAmount = mDozeInterpolator.getInterpolation(dozeAmount);
synchronized (mListeners) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
index 6dbcc44..a6986d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar;
import static com.android.systemui.plugins.DarkIconDispatcher.getTint;
-import static com.android.systemui.plugins.DarkIconDispatcher.isInArea;
import static com.android.systemui.statusbar.StatusBarIconView.STATE_DOT;
import static com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN;
import static com.android.systemui.statusbar.StatusBarIconView.STATE_ICON;
@@ -37,6 +36,8 @@
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
+import java.util.ArrayList;
+
/**
* Start small: StatusBarWifiView will be able to layout from a WifiIconState
*/
@@ -235,8 +236,8 @@
}
@Override
- public void onDarkChanged(Rect area, float darkIntensity, int tint) {
- int areaTint = getTint(area, this, tint);
+ public void onDarkChanged(ArrayList<Rect> areas, float darkIntensity, int tint) {
+ int areaTint = getTint(areas, this, tint);
ColorStateList color = ColorStateList.valueOf(areaTint);
mWifiIcon.setImageTintList(color);
mIn.setImageTintList(color);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StartStatusBarModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StartStatusBarModule.kt
new file mode 100644
index 0000000..46c1abb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StartStatusBarModule.kt
@@ -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.systemui.statusbar.dagger
+
+import com.android.systemui.CoreStartable
+import com.android.systemui.statusbar.phone.StatusBar
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+
+@Module
+interface StartStatusBarModule {
+ /** Start the StatusBar */
+ @Binds
+ @IntoMap
+ @ClassKey(StatusBar::class)
+ abstract fun bindsStatusBar(statusBar: StatusBar): CoreStartable
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
index e3d0d98..c687e82 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.dagger;
import android.app.IActivityManager;
-import android.app.NotificationManager;
import android.content.Context;
import android.os.Handler;
import android.service.dreams.IDreamManager;
@@ -38,7 +37,6 @@
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.MediaArtworkProcessor;
import com.android.systemui.statusbar.NotificationClickNotifier;
-import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -167,18 +165,6 @@
/** */
@SysUISingleton
@Provides
- static NotificationListener provideNotificationListener(
- Context context,
- NotificationManager notificationManager,
- SystemClock systemClock,
- @Main Executor mainExecutor) {
- return new NotificationListener(
- context, notificationManager, systemClock, mainExecutor);
- }
-
- /** */
- @SysUISingleton
- @Provides
static SmartReplyController provideSmartReplyController(
DumpManager dumpManager,
NotificationVisibilityProvider visibilityProvider,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
index 962c7fa..1401423 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
@@ -92,6 +92,8 @@
private val views: Sequence<View>
get() = if (!this::tl.isInitialized) sequenceOf() else sequenceOf(tl, tr, br, bl)
+ private var showingListener: ShowingListener? = null
+
init {
contentInsetsProvider.addCallback(object : StatusBarContentInsetsChangedListener {
override fun onStatusBarContentInsetsChanged() {
@@ -132,6 +134,10 @@
uiExecutor = e
}
+ fun setShowingListener(l: ShowingListener) {
+ showingListener = l
+ }
+
fun setQsExpanded(expanded: Boolean) {
dlog("setQsExpanded $expanded")
synchronized(lock) {
@@ -176,15 +182,20 @@
.setDuration(DURATION)
.setInterpolator(Interpolators.ALPHA_OUT)
.alpha(0f)
- .withEndAction { dot.visibility = View.INVISIBLE }
+ .withEndAction {
+ dot.visibility = View.INVISIBLE
+ showingListener?.onPrivacyDotHidden(dot)
+ }
.start()
} else {
dot.visibility = View.INVISIBLE
+ showingListener?.onPrivacyDotHidden(dot)
}
}
@UiThread
private fun showDotView(dot: View, animate: Boolean) {
+ showingListener?.onPrivacyDotShown(dot)
dot.clearAnimation()
if (animate) {
dot.visibility = View.VISIBLE
@@ -320,6 +331,7 @@
@UiThread
private fun updateDesignatedCorner(newCorner: View?, shouldShowDot: Boolean) {
if (shouldShowDot) {
+ showingListener?.onPrivacyDotShown(newCorner)
newCorner?.apply {
clearAnimation()
visibility = View.VISIBLE
@@ -336,6 +348,11 @@
private fun setCornerVisibilities(vis: Int) {
views.forEach { corner ->
corner.visibility = vis
+ if (vis == View.VISIBLE) {
+ showingListener?.onPrivacyDotShown(corner)
+ } else {
+ showingListener?.onPrivacyDotHidden(corner)
+ }
}
}
@@ -555,6 +572,11 @@
)
}
}
+
+ public interface ShowingListener {
+ fun onPrivacyDotShown(v: View?)
+ fun onPrivacyDotHidden(v: View?)
+ }
}
private fun dlog(s: String) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index e739b9f..e3ebef9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -204,7 +204,7 @@
static VisualStabilityManager provideVisualStabilityManager(
NotificationEntryManager notificationEntryManager,
VisualStabilityProvider visualStabilityProvider,
- Handler handler,
+ @Main Handler handler,
StatusBarStateController statusBarStateController,
WakefulnessLifecycle wakefulnessLifecycle,
DumpManager dumpManager) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt
index 06651f2..50a6207 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt
@@ -46,4 +46,5 @@
})
}
}
-const val TAG = "HeadsUpViewBinder"
\ No newline at end of file
+
+private const val TAG = "HeadsUpViewBinder"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt
new file mode 100644
index 0000000..c991376
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt
@@ -0,0 +1,216 @@
+/*
+ * 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.systemui.statusbar.notification.interruption
+
+import android.service.notification.StatusBarNotification
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel.DEBUG
+import com.android.systemui.log.LogLevel.INFO
+import com.android.systemui.log.dagger.NotificationHeadsUpLog
+import com.android.systemui.log.dagger.NotificationLog
+import javax.inject.Inject
+
+class NotificationInterruptLogger @Inject constructor(
+ @NotificationLog val notifBuffer: LogBuffer,
+ @NotificationHeadsUpLog val hunBuffer: LogBuffer
+) {
+ fun logHeadsUpFeatureChanged(useHeadsUp: Boolean) {
+ hunBuffer.log(TAG, INFO, {
+ bool1 = useHeadsUp
+ }, {
+ "heads up is enabled=$bool1"
+ })
+ }
+
+ fun logWillDismissAll() {
+ hunBuffer.log(TAG, INFO, {
+ }, {
+ "dismissing any existing heads up notification on disable event"
+ })
+ }
+
+ fun logNoBubbleNotAllowed(sbn: StatusBarNotification) {
+ notifBuffer.log(TAG, DEBUG, {
+ str1 = sbn.key
+ }, {
+ "No bubble up: not allowed to bubble: $str1"
+ })
+ }
+
+ fun logNoBubbleNoMetadata(sbn: StatusBarNotification) {
+ notifBuffer.log(TAG, DEBUG, {
+ str1 = sbn.key
+ }, {
+ "No bubble up: notification: $str1 doesn't have valid metadata"
+ })
+ }
+
+ fun logNoHeadsUpFeatureDisabled() {
+ hunBuffer.log(TAG, DEBUG, {
+ }, {
+ "No heads up: no huns"
+ })
+ }
+
+ fun logNoHeadsUpPackageSnoozed(sbn: StatusBarNotification) {
+ hunBuffer.log(TAG, DEBUG, {
+ str1 = sbn.key
+ }, {
+ "No alerting: snoozed package: $str1"
+ })
+ }
+
+ fun logNoHeadsUpAlreadyBubbled(sbn: StatusBarNotification) {
+ hunBuffer.log(TAG, DEBUG, {
+ str1 = sbn.key
+ }, {
+ "No heads up: in unlocked shade where notification is shown as a bubble: $str1"
+ })
+ }
+
+ fun logNoHeadsUpSuppressedByDnd(sbn: StatusBarNotification) {
+ hunBuffer.log(TAG, DEBUG, {
+ str1 = sbn.key
+ }, {
+ "No heads up: suppressed by DND: $str1"
+ })
+ }
+
+ fun logNoHeadsUpNotImportant(sbn: StatusBarNotification) {
+ hunBuffer.log(TAG, DEBUG, {
+ str1 = sbn.key
+ }, {
+ "No heads up: unimportant notification: $str1"
+ })
+ }
+
+ fun logNoHeadsUpNotInUse(sbn: StatusBarNotification) {
+ hunBuffer.log(TAG, DEBUG, {
+ str1 = sbn.key
+ }, {
+ "No heads up: not in use: $str1"
+ })
+ }
+
+ fun logNoHeadsUpSuppressedBy(
+ sbn: StatusBarNotification,
+ suppressor: NotificationInterruptSuppressor
+ ) {
+ hunBuffer.log(TAG, DEBUG, {
+ str1 = sbn.key
+ str2 = suppressor.name
+ }, {
+ "No heads up: aborted by suppressor: $str2 sbnKey=$str1"
+ })
+ }
+
+ fun logHeadsUp(sbn: StatusBarNotification) {
+ hunBuffer.log(TAG, DEBUG, {
+ str1 = sbn.key
+ }, {
+ "Heads up: $str1"
+ })
+ }
+
+ fun logNoAlertingFilteredOut(sbn: StatusBarNotification) {
+ hunBuffer.log(TAG, DEBUG, {
+ str1 = sbn.key
+ }, {
+ "No alerting: filtered notification: $str1"
+ })
+ }
+
+ fun logNoAlertingGroupAlertBehavior(sbn: StatusBarNotification) {
+ hunBuffer.log(TAG, DEBUG, {
+ str1 = sbn.key
+ }, {
+ "No alerting: suppressed due to group alert behavior: $str1"
+ })
+ }
+
+ fun logNoAlertingSuppressedBy(
+ sbn: StatusBarNotification,
+ suppressor: NotificationInterruptSuppressor,
+ awake: Boolean
+ ) {
+ hunBuffer.log(TAG, DEBUG, {
+ str1 = sbn.key
+ str2 = suppressor.name
+ bool1 = awake
+ }, {
+ "No alerting: aborted by suppressor: $str2 awake=$bool1 sbnKey=$str1"
+ })
+ }
+
+ fun logNoAlertingRecentFullscreen(sbn: StatusBarNotification) {
+ hunBuffer.log(TAG, DEBUG, {
+ str1 = sbn.key
+ }, {
+ "No alerting: recent fullscreen: $str1"
+ })
+ }
+
+ fun logNoPulsingSettingDisabled(sbn: StatusBarNotification) {
+ hunBuffer.log(TAG, DEBUG, {
+ str1 = sbn.key
+ }, {
+ "No pulsing: disabled by setting: $str1"
+ })
+ }
+
+ fun logNoPulsingBatteryDisabled(sbn: StatusBarNotification) {
+ hunBuffer.log(TAG, DEBUG, {
+ str1 = sbn.key
+ }, {
+ "No pulsing: disabled by battery saver: $str1"
+ })
+ }
+
+ fun logNoPulsingNoAlert(sbn: StatusBarNotification) {
+ hunBuffer.log(TAG, DEBUG, {
+ str1 = sbn.key
+ }, {
+ "No pulsing: notification shouldn't alert: $str1"
+ })
+ }
+
+ fun logNoPulsingNoAmbientEffect(sbn: StatusBarNotification) {
+ hunBuffer.log(TAG, DEBUG, {
+ str1 = sbn.key
+ }, {
+ "No pulsing: ambient effect suppressed: $str1"
+ })
+ }
+
+ fun logNoPulsingNotImportant(sbn: StatusBarNotification) {
+ hunBuffer.log(TAG, DEBUG, {
+ str1 = sbn.key
+ }, {
+ "No pulsing: not important enough: $str1"
+ })
+ }
+
+ fun logPulsing(sbn: StatusBarNotification) {
+ hunBuffer.log(TAG, DEBUG, {
+ str1 = sbn.key
+ }, {
+ "Pulsing: $str1"
+ })
+ }
+}
+
+private const val TAG = "InterruptionStateProvider"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
index 2b4bc91..7ed2699 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
@@ -40,7 +40,6 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.util.Compile;
import java.util.ArrayList;
import java.util.List;
@@ -53,8 +52,6 @@
@SysUISingleton
public class NotificationInterruptStateProviderImpl implements NotificationInterruptStateProvider {
private static final String TAG = "InterruptionStateProvider";
- private static final boolean DEBUG = Compile.IS_DEBUG;
- private static final boolean DEBUG_HEADS_UP = Compile.IS_DEBUG;
private static final boolean ENABLE_HEADS_UP = true;
private static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
@@ -67,7 +64,8 @@
private final AmbientDisplayConfiguration mAmbientDisplayConfiguration;
private final BatteryController mBatteryController;
private final ContentObserver mHeadsUpObserver;
- private HeadsUpManager mHeadsUpManager;
+ private final HeadsUpManager mHeadsUpManager;
+ private final NotificationInterruptLogger mLogger;
@VisibleForTesting
protected boolean mUseHeadsUp = false;
@@ -82,6 +80,7 @@
BatteryController batteryController,
StatusBarStateController statusBarStateController,
HeadsUpManager headsUpManager,
+ NotificationInterruptLogger logger,
@Main Handler mainHandler) {
mContentResolver = contentResolver;
mPowerManager = powerManager;
@@ -91,6 +90,7 @@
mNotificationFilter = notificationFilter;
mStatusBarStateController = statusBarStateController;
mHeadsUpManager = headsUpManager;
+ mLogger = logger;
mHeadsUpObserver = new ContentObserver(mainHandler) {
@Override
public void onChange(boolean selfChange) {
@@ -100,11 +100,10 @@
mContentResolver,
Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
Settings.Global.HEADS_UP_OFF);
- Log.d(TAG, "heads up is " + (mUseHeadsUp ? "enabled" : "disabled"));
+ mLogger.logHeadsUpFeatureChanged(mUseHeadsUp);
if (wasUsing != mUseHeadsUp) {
if (!mUseHeadsUp) {
- Log.d(TAG, "dismissing any existing heads up notification on "
- + "disable event");
+ mLogger.logWillDismissAll();
mHeadsUpManager.releaseAllImmediately();
}
}
@@ -141,19 +140,14 @@
}
if (!entry.canBubble()) {
- if (DEBUG) {
- Log.d(TAG, "No bubble up: not allowed to bubble: " + sbn.getKey());
- }
+ mLogger.logNoBubbleNotAllowed(sbn);
return false;
}
if (entry.getBubbleMetadata() == null
|| (entry.getBubbleMetadata().getShortcutId() == null
&& entry.getBubbleMetadata().getIntent() == null)) {
- if (DEBUG) {
- Log.d(TAG, "No bubble up: notification: " + sbn.getKey()
- + " doesn't have valid metadata");
- }
+ mLogger.logNoBubbleNoMetadata(sbn);
return false;
}
@@ -185,9 +179,7 @@
StatusBarNotification sbn = entry.getSbn();
if (!mUseHeadsUp) {
- if (DEBUG_HEADS_UP) {
- Log.d(TAG, "No heads up: no huns");
- }
+ mLogger.logNoHeadsUpFeatureDisabled();
return false;
}
@@ -200,32 +192,23 @@
}
if (isSnoozedPackage(sbn)) {
- if (DEBUG_HEADS_UP) {
- Log.d(TAG, "No alerting: snoozed package: " + sbn.getKey());
- }
+ mLogger.logNoHeadsUpPackageSnoozed(sbn);
return false;
}
boolean inShade = mStatusBarStateController.getState() == SHADE;
if (entry.isBubble() && inShade) {
- if (DEBUG_HEADS_UP) {
- Log.d(TAG, "No heads up: in unlocked shade where notification is shown as a "
- + "bubble: " + sbn.getKey());
- }
+ mLogger.logNoHeadsUpAlreadyBubbled(sbn);
return false;
}
if (entry.shouldSuppressPeek()) {
- if (DEBUG_HEADS_UP) {
- Log.d(TAG, "No heads up: suppressed by DND: " + sbn.getKey());
- }
+ mLogger.logNoHeadsUpSuppressedByDnd(sbn);
return false;
}
if (entry.getImportance() < NotificationManager.IMPORTANCE_HIGH) {
- if (DEBUG_HEADS_UP) {
- Log.d(TAG, "No heads up: unimportant notification: " + sbn.getKey());
- }
+ mLogger.logNoHeadsUpNotImportant(sbn);
return false;
}
@@ -238,21 +221,17 @@
boolean inUse = mPowerManager.isScreenOn() && !isDreaming;
if (!inUse) {
- if (DEBUG_HEADS_UP) {
- Log.d(TAG, "No heads up: not in use: " + sbn.getKey());
- }
+ mLogger.logNoHeadsUpNotInUse(sbn);
return false;
}
for (int i = 0; i < mSuppressors.size(); i++) {
if (mSuppressors.get(i).suppressAwakeHeadsUp(entry)) {
- if (DEBUG_HEADS_UP) {
- Log.d(TAG, "No heads up: aborted by suppressor: "
- + mSuppressors.get(i).getName() + " sbnKey=" + sbn.getKey());
- }
+ mLogger.logNoHeadsUpSuppressedBy(sbn, mSuppressors.get(i));
return false;
}
}
+ mLogger.logHeadsUp(sbn);
return true;
}
@@ -267,39 +246,30 @@
StatusBarNotification sbn = entry.getSbn();
if (!mAmbientDisplayConfiguration.pulseOnNotificationEnabled(UserHandle.USER_CURRENT)) {
- if (DEBUG_HEADS_UP) {
- Log.d(TAG, "No pulsing: disabled by setting: " + sbn.getKey());
- }
+ mLogger.logNoPulsingSettingDisabled(sbn);
return false;
}
if (mBatteryController.isAodPowerSave()) {
- if (DEBUG_HEADS_UP) {
- Log.d(TAG, "No pulsing: disabled by battery saver: " + sbn.getKey());
- }
+ mLogger.logNoPulsingBatteryDisabled(sbn);
return false;
}
if (!canAlertCommon(entry)) {
- if (DEBUG_HEADS_UP) {
- Log.d(TAG, "No pulsing: notification shouldn't alert: " + sbn.getKey());
- }
+ mLogger.logNoPulsingNoAlert(sbn);
return false;
}
if (entry.shouldSuppressAmbient()) {
- if (DEBUG_HEADS_UP) {
- Log.d(TAG, "No pulsing: ambient effect suppressed: " + sbn.getKey());
- }
+ mLogger.logNoPulsingNoAmbientEffect(sbn);
return false;
}
if (entry.getImportance() < NotificationManager.IMPORTANCE_DEFAULT) {
- if (DEBUG_HEADS_UP) {
- Log.d(TAG, "No pulsing: not important enough: " + sbn.getKey());
- }
+ mLogger.logNoPulsingNotImportant(sbn);
return false;
}
+ mLogger.logPulsing(sbn);
return true;
}
@@ -313,34 +283,25 @@
StatusBarNotification sbn = entry.getSbn();
if (mNotificationFilter.shouldFilterOut(entry)) {
- if (DEBUG || DEBUG_HEADS_UP) {
- Log.d(TAG, "No alerting: filtered notification: " + sbn.getKey());
- }
+ mLogger.logNoAlertingFilteredOut(sbn);
return false;
}
// Don't alert notifications that are suppressed due to group alert behavior
if (sbn.isGroup() && sbn.getNotification().suppressAlertingDueToGrouping()) {
- if (DEBUG || DEBUG_HEADS_UP) {
- Log.d(TAG, "No alerting: suppressed due to group alert behavior");
- }
+ mLogger.logNoAlertingGroupAlertBehavior(sbn);
return false;
}
for (int i = 0; i < mSuppressors.size(); i++) {
if (mSuppressors.get(i).suppressInterruptions(entry)) {
- if (DEBUG_HEADS_UP) {
- Log.d(TAG, "No alerting: aborted by suppressor: "
- + mSuppressors.get(i).getName() + " sbnKey=" + sbn.getKey());
- }
+ mLogger.logNoAlertingSuppressedBy(sbn, mSuppressors.get(i), /* awake */ false);
return false;
}
}
if (entry.hasJustLaunchedFullScreenIntent()) {
- if (DEBUG_HEADS_UP) {
- Log.d(TAG, "No alerting: recent fullscreen: " + sbn.getKey());
- }
+ mLogger.logNoAlertingRecentFullscreen(sbn);
return false;
}
@@ -358,10 +319,7 @@
for (int i = 0; i < mSuppressors.size(); i++) {
if (mSuppressors.get(i).suppressAwakeInterruptions(entry)) {
- if (DEBUG_HEADS_UP) {
- Log.d(TAG, "No alerting: aborted by suppressor: "
- + mSuppressors.get(i).getName() + " sbnKey=" + sbn.getKey());
- }
+ mLogger.logNoAlertingSuppressedBy(sbn, mSuppressors.get(i), /* awake */ true);
return false;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index e1116f8..d1c63e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -290,11 +290,11 @@
@Override
public void onThemeChanged() {
- updateShowEmptyShadeView();
mView.updateCornerRadius();
mView.updateBgColor();
mView.updateDecorViews();
mView.reinflateViews();
+ updateShowEmptyShadeView();
updateFooter();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index e24cd3e..3a3f581 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -376,6 +376,11 @@
final float stackHeight = ambientState.getStackHeight() - shelfHeight - scrimPadding;
final float stackEndHeight = ambientState.getStackEndHeight() - shelfHeight - scrimPadding;
+ if (stackEndHeight == 0f) {
+ // This should not happen, since even when the shade is empty we show EmptyShadeView
+ // but check just in case, so we don't return infinity or NaN.
+ return 0f;
+ }
return stackHeight / stackEndHeight;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 6a78370..d5d1cea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -19,7 +19,6 @@
import static android.app.StatusBarManager.SESSION_KEYGUARD;
import android.annotation.IntDef;
-import android.content.Context;
import android.content.res.Resources;
import android.hardware.biometrics.BiometricSourceType;
import android.hardware.fingerprint.FingerprintManager;
@@ -45,6 +44,7 @@
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.KeyguardViewController;
import com.android.systemui.Dumpable;
+import com.android.systemui.R;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
@@ -163,7 +163,7 @@
private final KeyguardStateController mKeyguardStateController;
private final NotificationShadeWindowController mNotificationShadeWindowController;
private final SessionTracker mSessionTracker;
- private final Context mContext;
+ private final int mConsecutiveFpFailureThreshold;
private final int mWakeUpDelay;
private int mMode;
private BiometricSourceType mBiometricType;
@@ -266,7 +266,7 @@
private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
@Inject
- public BiometricUnlockController(Context context, DozeScrimController dozeScrimController,
+ public BiometricUnlockController(DozeScrimController dozeScrimController,
KeyguardViewMediator keyguardViewMediator, ScrimController scrimController,
ShadeController shadeController,
NotificationShadeWindowController notificationShadeWindowController,
@@ -284,7 +284,6 @@
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
SessionTracker sessionTracker,
LatencyTracker latencyTracker) {
- mContext = context;
mPowerManager = powerManager;
mShadeController = shadeController;
mUpdateMonitor = keyguardUpdateMonitor;
@@ -302,6 +301,8 @@
mKeyguardStateController = keyguardStateController;
mHandler = handler;
mWakeUpDelay = resources.getInteger(com.android.internal.R.integer.config_wakeUpDelayDoze);
+ mConsecutiveFpFailureThreshold = resources.getInteger(
+ R.integer.fp_consecutive_failure_time_ms);
mKeyguardBypassController = keyguardBypassController;
mKeyguardBypassController.setUnlockController(this);
mMetricsLogger = metricsLogger;
@@ -666,8 +667,7 @@
if (biometricSourceType == BiometricSourceType.FINGERPRINT
&& mUpdateMonitor.isUdfpsSupported()) {
long currUptimeMillis = SystemClock.uptimeMillis();
- if (currUptimeMillis - mLastFpFailureUptimeMillis
- < (mStatusBarStateController.isDozing() ? 3500 : 2000)) {
+ if (currUptimeMillis - mLastFpFailureUptimeMillis < mConsecutiveFpFailureThreshold) {
mNumConsecutiveFpFailures += 1;
} else {
mNumConsecutiveFpFailures = 1;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java
index d06de75..150da16 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java
@@ -30,6 +30,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
import javax.inject.Inject;
@@ -40,7 +41,7 @@
LightBarTransitionsController.DarkIntensityApplier {
private final LightBarTransitionsController mTransitionsController;
- private final Rect mTintArea = new Rect();
+ private final ArrayList<Rect> mTintAreas = new ArrayList<>();
private final ArrayMap<Object, DarkReceiver> mReceivers = new ArrayMap<>();
private int mIconTint = DEFAULT_ICON_TINT;
@@ -69,14 +70,14 @@
public void addDarkReceiver(DarkReceiver receiver) {
mReceivers.put(receiver, receiver);
- receiver.onDarkChanged(mTintArea, mDarkIntensity, mIconTint);
+ receiver.onDarkChanged(mTintAreas, mDarkIntensity, mIconTint);
}
public void addDarkReceiver(ImageView imageView) {
DarkReceiver receiver = (area, darkIntensity, tint) -> imageView.setImageTintList(
- ColorStateList.valueOf(getTint(mTintArea, imageView, mIconTint)));
+ ColorStateList.valueOf(getTint(mTintAreas, imageView, mIconTint)));
mReceivers.put(imageView, receiver);
- receiver.onDarkChanged(mTintArea, mDarkIntensity, mIconTint);
+ receiver.onDarkChanged(mTintAreas, mDarkIntensity, mIconTint);
}
public void removeDarkReceiver(DarkReceiver object) {
@@ -88,23 +89,23 @@
}
public void applyDark(DarkReceiver object) {
- mReceivers.get(object).onDarkChanged(mTintArea, mDarkIntensity, mIconTint);
+ mReceivers.get(object).onDarkChanged(mTintAreas, mDarkIntensity, mIconTint);
}
/**
* Sets the dark area so {@link #applyDark} only affects the icons in the specified area.
*
- * @param darkArea the area in which icons should change it's tint, in logical screen
- * coordinates
+ * @param darkAreas the areas in which icons should change it's tint, in logical screen
+ * coordinates
*/
- public void setIconsDarkArea(Rect darkArea) {
- if (darkArea == null && mTintArea.isEmpty()) {
+ public void setIconsDarkArea(ArrayList<Rect> darkAreas) {
+ if (darkAreas == null && mTintAreas.isEmpty()) {
return;
}
- if (darkArea == null) {
- mTintArea.setEmpty();
- } else {
- mTintArea.set(darkArea);
+
+ mTintAreas.clear();
+ if (darkAreas != null) {
+ mTintAreas.addAll(darkAreas);
}
applyIconTint();
}
@@ -124,7 +125,7 @@
private void applyIconTint() {
for (int i = 0; i < mReceivers.size(); i++) {
- mReceivers.valueAt(i).onDarkChanged(mTintArea, mDarkIntensity, mIconTint);
+ mReceivers.valueAt(i).onDarkChanged(mTintAreas, mDarkIntensity, mIconTint);
}
}
@@ -133,6 +134,6 @@
pw.println("DarkIconDispatcher: ");
pw.println(" mIconTint: 0x" + Integer.toHexString(mIconTint));
pw.println(" mDarkIntensity: " + mDarkIntensity + "f");
- pw.println(" mTintArea: " + mTintArea);
+ pw.println(" mTintAreas: " + mTintAreas);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index ee51efb..6dbbf0d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -315,14 +315,14 @@
}
@Override
- public void onDarkChanged(Rect area, float darkIntensity, int tint) {
- setColor(DarkIconDispatcher.getTint(area, mStatusIcons, tint));
+ public void onDarkChanged(ArrayList<Rect> areas, float darkIntensity, int tint) {
+ setColor(DarkIconDispatcher.getTint(areas, mStatusIcons, tint));
if (mWifiView != null) {
- mWifiView.onDarkChanged(area, darkIntensity, tint);
+ mWifiView.onDarkChanged(areas, darkIntensity, tint);
}
for (StatusBarMobileView view : mMobileViews) {
- view.onDarkChanged(area, darkIntensity, tint);
+ view.onDarkChanged(areas, darkIntensity, tint);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index f421d23..9863a0e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -16,34 +16,37 @@
package com.android.systemui.statusbar.phone;
+import static com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentModule.OPERATOR_NAME_FRAME_VIEW;
+
import android.graphics.Rect;
import android.view.View;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.widget.ViewClippingUtil;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.dagger.qualifiers.RootView;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.HeadsUpStatusBarView;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentScope;
+import com.android.systemui.statusbar.policy.Clock;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.util.ViewController;
+import java.util.Optional;
+import java.util.ArrayList;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import javax.inject.Inject;
+import javax.inject.Named;
/**
* Controls the appearance of heads up notifications in the icon area and the header itself.
@@ -69,8 +72,8 @@
private final CommandQueue mCommandQueue;
private final NotificationWakeUpCoordinator mWakeUpCoordinator;
- private View mClockView;
- private View mOperatorNameView;
+ private final View mClockView;
+ private final Optional<View> mOperatorNameViewOptional;
@VisibleForTesting
float mExpandedHeight;
@@ -86,45 +89,24 @@
}
};
private boolean mAnimationsEnabled = true;
- private KeyguardStateController mKeyguardStateController;
-
- @Inject
- public HeadsUpAppearanceController(
- NotificationIconAreaController notificationIconAreaController,
- HeadsUpManagerPhone headsUpManager,
- NotificationStackScrollLayoutController notificationStackScrollLayoutController,
- SysuiStatusBarStateController statusBarStateController,
- KeyguardBypassController keyguardBypassController,
- KeyguardStateController keyguardStateController,
- NotificationWakeUpCoordinator wakeUpCoordinator, CommandQueue commandQueue,
- NotificationPanelViewController notificationPanelViewController,
- @RootView PhoneStatusBarView statusBarView) {
- this(notificationIconAreaController, headsUpManager, statusBarStateController,
- keyguardBypassController, wakeUpCoordinator, keyguardStateController,
- commandQueue, notificationStackScrollLayoutController,
- notificationPanelViewController,
- // TODO(b/205609837): We should have the StatusBarFragmentComponent provide these
- // four views, and then we can delete this constructor and just use the one below
- // (which also removes the undesirable @VisibleForTesting).
- statusBarView.findViewById(R.id.heads_up_status_bar_view),
- statusBarView.findViewById(R.id.clock),
- statusBarView.findViewById(R.id.operator_name_frame));
- }
+ private final KeyguardStateController mKeyguardStateController;
@VisibleForTesting
+ @Inject
public HeadsUpAppearanceController(
NotificationIconAreaController notificationIconAreaController,
HeadsUpManagerPhone headsUpManager,
StatusBarStateController stateController,
KeyguardBypassController bypassController,
NotificationWakeUpCoordinator wakeUpCoordinator,
+ DarkIconDispatcher darkIconDispatcher,
KeyguardStateController keyguardStateController,
CommandQueue commandQueue,
NotificationStackScrollLayoutController stackScrollerController,
NotificationPanelViewController notificationPanelViewController,
HeadsUpStatusBarView headsUpStatusBarView,
- View clockView,
- View operatorNameView) {
+ Clock clockView,
+ @Named(OPERATOR_NAME_FRAME_VIEW) Optional<View> operatorNameViewOptional) {
super(headsUpStatusBarView);
mNotificationIconAreaController = notificationIconAreaController;
mHeadsUpManager = headsUpManager;
@@ -141,8 +123,8 @@
mNotificationPanelViewController = notificationPanelViewController;
mStackScrollerController.setHeadsUpAppearanceController(this);
mClockView = clockView;
- mOperatorNameView = operatorNameView;
- mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class);
+ mOperatorNameViewOptional = operatorNameViewOptional;
+ mDarkIconDispatcher = darkIconDispatcher;
mView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override
@@ -232,14 +214,10 @@
mView.setVisibility(View.VISIBLE);
show(mView);
hide(mClockView, View.INVISIBLE);
- if (mOperatorNameView != null) {
- hide(mOperatorNameView, View.INVISIBLE);
- }
+ mOperatorNameViewOptional.ifPresent(view -> hide(view, View.INVISIBLE));
} else {
show(mClockView);
- if (mOperatorNameView != null) {
- show(mOperatorNameView);
- }
+ mOperatorNameViewOptional.ifPresent(this::show);
hide(mView, View.GONE, () -> {
updateParentClipping(true /* shouldClip */);
});
@@ -392,8 +370,8 @@
}
@Override
- public void onDarkChanged(Rect area, float darkIntensity, int tint) {
- mView.onDarkChanged(area, darkIntensity, tint);
+ public void onDarkChanged(ArrayList<Rect> areas, float darkIntensity, int tint) {
+ mView.onDarkChanged(areas, darkIntensity, tint);
}
public void onStateChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 565b2d3..95a2a6e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -41,6 +41,7 @@
import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.systemui.DejankUtils;
import com.android.systemui.classifier.FalsingCollector;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -115,7 +116,7 @@
BouncerExpansionCallback expansionCallback,
KeyguardStateController keyguardStateController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
- KeyguardBypassController keyguardBypassController, Handler handler,
+ KeyguardBypassController keyguardBypassController, @Main Handler handler,
KeyguardSecurityModel keyguardSecurityModel,
KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory) {
mContext = context;
@@ -647,7 +648,7 @@
DismissCallbackRegistry dismissCallbackRegistry, FalsingCollector falsingCollector,
KeyguardStateController keyguardStateController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
- KeyguardBypassController keyguardBypassController, Handler handler,
+ KeyguardBypassController keyguardBypassController, @Main Handler handler,
KeyguardSecurityModel keyguardSecurityModel,
KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory) {
mContext = context;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java
index 817b86b..9bdefcd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java
@@ -20,7 +20,6 @@
import android.service.notification.StatusBarNotification;
import android.util.Log;
-import com.android.systemui.Dependency;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
@@ -33,13 +32,15 @@
private static final String TAG = "KeyguardEnvironmentImpl";
- private final NotificationLockscreenUserManager mLockscreenUserManager =
- Dependency.get(NotificationLockscreenUserManager.class);
- private final DeviceProvisionedController mDeviceProvisionedController =
- Dependency.get(DeviceProvisionedController.class);
+ private final NotificationLockscreenUserManager mLockscreenUserManager;
+ private final DeviceProvisionedController mDeviceProvisionedController;
@Inject
- public KeyguardEnvironmentImpl() {
+ public KeyguardEnvironmentImpl(
+ NotificationLockscreenUserManager notificationLockscreenUserManager,
+ DeviceProvisionedController deviceProvisionedController) {
+ mLockscreenUserManager = notificationLockscreenUserManager;
+ mDeviceProvisionedController = deviceProvisionedController;
}
@Override // NotificationEntryManager.KeyguardEnvironment
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index b8e9875..65173a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -50,6 +50,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
/**
* The header group on Keyguard.
@@ -60,7 +61,7 @@
private static final int LAYOUT_CUTOUT = 1;
private static final int LAYOUT_NO_CUTOUT = 2;
- private final Rect mEmptyRect = new Rect(0, 0, 0, 0);
+ private final ArrayList<Rect> mEmptyTintRect = new ArrayList<>();
private boolean mShowPercentAvailable;
private boolean mBatteryCharging;
@@ -476,14 +477,14 @@
iconManager.setTint(iconColor);
}
- applyDarkness(R.id.battery, mEmptyRect, intensity, iconColor);
- applyDarkness(R.id.clock, mEmptyRect, intensity, iconColor);
+ applyDarkness(R.id.battery, mEmptyTintRect, intensity, iconColor);
+ applyDarkness(R.id.clock, mEmptyTintRect, intensity, iconColor);
}
- private void applyDarkness(int id, Rect tintArea, float intensity, int color) {
+ private void applyDarkness(int id, ArrayList<Rect> tintAreas, float intensity, int color) {
View v = findViewById(id);
if (v instanceof DarkReceiver) {
- ((DarkReceiver) v).onDarkChanged(tintArea, intensity, color);
+ ((DarkReceiver) v).onDarkChanged(tintAreas, intensity, color);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
index 88ae0db..4082db7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
@@ -25,6 +25,7 @@
import android.content.Context;
import android.graphics.Color;
+import android.graphics.Rect;
import android.view.InsetsFlags;
import android.view.ViewDebug;
import android.view.WindowInsetsController.Appearance;
@@ -41,6 +42,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
import javax.inject.Inject;
@@ -214,27 +216,23 @@
private void updateStatus() {
final int numStacks = mAppearanceRegions.length;
- int numLightStacks = 0;
-
- // We can only have maximum one light stack.
- int indexLightStack = -1;
+ final ArrayList<Rect> lightBarBounds = new ArrayList<>();
for (int i = 0; i < numStacks; i++) {
- if (isLight(mAppearanceRegions[i].getAppearance(), mStatusBarMode,
- APPEARANCE_LIGHT_STATUS_BARS)) {
- numLightStacks++;
- indexLightStack = i;
+ final AppearanceRegion ar = mAppearanceRegions[i];
+ if (isLight(ar.getAppearance(), mStatusBarMode, APPEARANCE_LIGHT_STATUS_BARS)) {
+ lightBarBounds.add(ar.getBounds());
}
}
// If no one is light, all icons become white.
- if (numLightStacks == 0) {
+ if (lightBarBounds.isEmpty()) {
mStatusBarIconController.getTransitionsController().setIconsDark(
false, animateChange());
}
// If all stacks are light, all icons get dark.
- else if (numLightStacks == numStacks) {
+ else if (lightBarBounds.size() == numStacks) {
mStatusBarIconController.setIconsDarkArea(null);
mStatusBarIconController.getTransitionsController().setIconsDark(true, animateChange());
@@ -242,8 +240,7 @@
// Not the same for every stack, magic!
else {
- mStatusBarIconController.setIconsDarkArea(
- mAppearanceRegions[indexLightStack].getBounds());
+ mStatusBarIconController.setIconsDarkArea(lightBarBounds);
mStatusBarIconController.getTransitionsController().setIconsDark(true, animateChange());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java
index 357a12b..324d47e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java
@@ -29,9 +29,7 @@
import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.qs.FooterActionsView;
-import com.android.systemui.qs.QSDetailDisplayer;
import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.qs.user.UserSwitchDialogController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
@@ -44,7 +42,6 @@
public class MultiUserSwitchController extends ViewController<MultiUserSwitch> {
private final UserManager mUserManager;
private final UserSwitcherController mUserSwitcherController;
- private final QSDetailDisplayer mQsDetailDisplayer;
private final FalsingManager mFalsingManager;
private final UserSwitchDialogController mUserSwitchDialogController;
private final ActivityStarter mActivityStarter;
@@ -66,17 +63,8 @@
mActivityStarter.startActivity(intent, true /* dismissShade */,
ActivityLaunchAnimator.Controller.fromView(v, null),
true /* showOverlockscreenwhenlocked */);
- } else if (mFeatureFlags.isEnabled(Flags.NEW_USER_SWITCHER)) {
- mUserSwitchDialogController.showDialog(v);
} else {
- View center = mView.getChildCount() > 0 ? mView.getChildAt(0) : mView;
-
- int[] tmpInt = new int[2];
- center.getLocationInWindow(tmpInt);
- tmpInt[0] += center.getWidth() / 2;
- tmpInt[1] += center.getHeight() / 2;
-
- mQsDetailDisplayer.showDetailAdapter(getUserDetailAdapter(), tmpInt[0], tmpInt[1]);
+ mUserSwitchDialogController.showDialog(v);
}
}
};
@@ -85,7 +73,6 @@
public static class Factory {
private final UserManager mUserManager;
private final UserSwitcherController mUserSwitcherController;
- private final QSDetailDisplayer mQsDetailDisplayer;
private final FalsingManager mFalsingManager;
private final UserSwitchDialogController mUserSwitchDialogController;
private final ActivityStarter mActivityStarter;
@@ -93,12 +80,11 @@
@Inject
public Factory(UserManager userManager, UserSwitcherController userSwitcherController,
- QSDetailDisplayer qsDetailDisplayer, FalsingManager falsingManager,
+ FalsingManager falsingManager,
UserSwitchDialogController userSwitchDialogController, FeatureFlags featureFlags,
ActivityStarter activityStarter) {
mUserManager = userManager;
mUserSwitcherController = userSwitcherController;
- mQsDetailDisplayer = qsDetailDisplayer;
mFalsingManager = falsingManager;
mUserSwitchDialogController = userSwitchDialogController;
mActivityStarter = activityStarter;
@@ -107,20 +93,19 @@
public MultiUserSwitchController create(FooterActionsView view) {
return new MultiUserSwitchController(view.findViewById(R.id.multi_user_switch),
- mUserManager, mUserSwitcherController, mQsDetailDisplayer,
+ mUserManager, mUserSwitcherController,
mFalsingManager, mUserSwitchDialogController, mFeatureFlags,
mActivityStarter);
}
}
private MultiUserSwitchController(MultiUserSwitch view, UserManager userManager,
- UserSwitcherController userSwitcherController, QSDetailDisplayer qsDetailDisplayer,
+ UserSwitcherController userSwitcherController,
FalsingManager falsingManager, UserSwitchDialogController userSwitchDialogController,
FeatureFlags featureFlags, ActivityStarter activityStarter) {
super(view);
mUserManager = userManager;
mUserSwitcherController = userSwitcherController;
- mQsDetailDisplayer = qsDetailDisplayer;
mFalsingManager = falsingManager;
mUserSwitchDialogController = userSwitchDialogController;
mFeatureFlags = featureFlags;
@@ -143,10 +128,6 @@
mView.setOnClickListener(null);
}
- protected DetailAdapter getUserDetailAdapter() {
- return mUserSwitcherController.mUserDetailAdapter;
- }
-
private void registerListener() {
if (mUserManager.isUserSwitcherEnabled() && mUserListener == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
index 8bababf..ca6e67e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
@@ -28,7 +28,7 @@
import android.util.Log;
import com.android.internal.statusbar.NotificationVisibility;
-import com.android.systemui.Dependency;
+import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
@@ -48,11 +48,14 @@
import java.util.List;
import java.util.Objects;
+import javax.inject.Inject;
+
/**
* A helper class dealing with the alert interactions between {@link NotificationGroupManagerLegacy}
* and {@link HeadsUpManager}. In particular, this class deals with keeping
* the correct notification in a group alerting based off the group suppression and alertOverride.
*/
+@SysUISingleton
public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedListener,
StateListener {
@@ -74,8 +77,7 @@
private HeadsUpManager mHeadsUpManager;
private final RowContentBindStage mRowContentBindStage;
- private final NotificationGroupManagerLegacy mGroupManager =
- Dependency.get(NotificationGroupManagerLegacy.class);
+ private final NotificationGroupManagerLegacy mGroupManager;
private NotificationEntryManager mEntryManager;
@@ -84,9 +86,14 @@
/**
* Injected constructor. See {@link StatusBarPhoneModule}.
*/
- public NotificationGroupAlertTransferHelper(RowContentBindStage bindStage) {
- Dependency.get(StatusBarStateController.class).addCallback(this);
+ @Inject
+ public NotificationGroupAlertTransferHelper(
+ RowContentBindStage bindStage,
+ StatusBarStateController statusBarStateController,
+ NotificationGroupManagerLegacy notificationGroupManagerLegacy) {
mRowContentBindStage = bindStage;
+ mGroupManager = notificationGroupManagerLegacy;
+ statusBarStateController.addCallback(this);
}
/** Causes the TransferHelper to register itself as a listener to the appropriate classes. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index c361300..e70c81d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -83,7 +83,7 @@
private NotificationIconContainer mNotificationIcons;
private NotificationIconContainer mShelfIcons;
private NotificationIconContainer mAodIcons;
- private final Rect mTintArea = new Rect();
+ private final ArrayList<Rect> mTintAreas = new ArrayList<>();
private Context mContext;
private final DemoModeController mDemoModeController;
@@ -240,17 +240,14 @@
* See {@link com.android.systemui.statusbar.policy.DarkIconDispatcher#setIconsDarkArea}.
* Sets the color that should be used to tint any icons in the notification area.
*
- * @param tintArea the area in which to tint the icons, specified in screen coordinates
+ * @param tintAreas the areas in which to tint the icons, specified in screen coordinates
* @param darkIntensity
*/
- public void onDarkChanged(Rect tintArea, float darkIntensity, int iconTint) {
- if (tintArea == null) {
- mTintArea.setEmpty();
- } else {
- mTintArea.set(tintArea);
- }
+ public void onDarkChanged(ArrayList<Rect> tintAreas, float darkIntensity, int iconTint) {
+ mTintAreas.clear();
+ mTintAreas.addAll(tintAreas);
- if (DarkIconDispatcher.isInArea(tintArea, mNotificationIconArea)) {
+ if (DarkIconDispatcher.isInAreas(tintAreas, mNotificationIconArea)) {
mIconTint = iconTint;
}
@@ -489,7 +486,7 @@
int color = StatusBarIconView.NO_COLOR;
boolean colorize = !isPreL || NotificationUtils.isGrayscale(v, mContrastColorUtil);
if (colorize) {
- color = DarkIconDispatcher.getTint(mTintArea, v, tint);
+ color = DarkIconDispatcher.getTint(mTintAreas, v, tint);
}
v.setStaticDrawableColor(color);
v.setDecorColor(tint);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index ebfed1a..034b751 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -387,16 +387,18 @@
}
/**
- * @return Width of shelf for the given number of icons and overflow dot
+ * @return Width of shelf for the given number of icons
*/
- public int calculateWidthFor(int numMaxIcons) {
+ public float calculateWidthFor(float numIcons) {
if (getChildCount() == 0) {
- return 0;
+ return 0f;
}
- return (int) (getActualPaddingStart()
- + numMaxIcons * mIconSize
- + mOverflowWidth
- + getActualPaddingEnd());
+ final float contentWidth = numIcons <= MAX_ICONS_ON_LOCKSCREEN + 1
+ ? numIcons * mIconSize
+ : MAX_ICONS_ON_LOCKSCREEN * mIconSize + (float) mOverflowWidth;
+ return getActualPaddingStart()
+ + contentWidth
+ + getActualPaddingEnd();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationListenerWithPlugins.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationListenerWithPlugins.java
index c68d39b..3811689 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationListenerWithPlugins.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationListenerWithPlugins.java
@@ -22,7 +22,6 @@
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
-import com.android.systemui.Dependency;
import com.android.systemui.plugins.NotificationListenerController;
import com.android.systemui.plugins.NotificationListenerController.NotificationProvider;
import com.android.systemui.plugins.PluginListener;
@@ -30,6 +29,8 @@
import java.util.ArrayList;
+import javax.inject.Inject;
+
/**
* A version of NotificationListenerService that passes all info to
* any plugins connected. Also allows those plugins the chance to cancel
@@ -40,19 +41,25 @@
private ArrayList<NotificationListenerController> mPlugins = new ArrayList<>();
private boolean mConnected;
+ private PluginManager mPluginManager;
+
+ @Inject
+ public NotificationListenerWithPlugins(PluginManager pluginManager) {
+ super();
+ mPluginManager = pluginManager;
+ }
@Override
public void registerAsSystemService(Context context, ComponentName componentName,
int currentUser) throws RemoteException {
super.registerAsSystemService(context, componentName, currentUser);
- Dependency.get(PluginManager.class).addPluginListener(this,
- NotificationListenerController.class);
+ mPluginManager.addPluginListener(this, NotificationListenerController.class);
}
@Override
public void unregisterAsSystemService() throws RemoteException {
super.unregisterAsSystemService();
- Dependency.get(PluginManager.class).removePluginListener(this);
+ mPluginManager.removePluginListener(this);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 62a96ad..d93c013 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -113,7 +113,6 @@
import com.android.keyguard.dagger.KeyguardStatusViewComponent;
import com.android.keyguard.dagger.KeyguardUserSwitcherComponent;
import com.android.systemui.DejankUtils;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.Interpolators;
@@ -147,12 +146,10 @@
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.FalsingManager.FalsingTapListener;
-import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.qrcodescanner.controller.QRCodeScannerController;
-import com.android.systemui.qs.QSDetailDisplayer;
import com.android.systemui.screenrecord.RecordingController;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.CommandQueue;
@@ -326,7 +323,6 @@
private final KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory;
private final KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory;
private final IdleViewComponent.Factory mIdleViewComponentFactory;
- private final QSDetailDisplayer mQSDetailDisplayer;
private final FragmentService mFragmentService;
private final ScrimController mScrimController;
private final PrivacyDotViewController mPrivacyDotViewController;
@@ -774,7 +770,6 @@
CommunalViewComponent.Factory communalViewComponentFactory,
IdleViewComponent.Factory idleViewComponentFactory,
LockscreenShadeTransitionController lockscreenShadeTransitionController,
- QSDetailDisplayer qsDetailDisplayer,
NotificationGroupManagerLegacy groupManager,
NotificationIconAreaController notificationIconAreaController,
AuthController authController,
@@ -804,6 +799,7 @@
ControlsComponent controlsComponent,
InteractionJankMonitor interactionJankMonitor,
QsFrameTranslateController qsFrameTranslateController,
+ SysUiState sysUiState,
KeyguardUnlockAnimationController keyguardUnlockAnimationController) {
super(view,
falsingManager,
@@ -848,7 +844,6 @@
mContentResolver = contentResolver;
mKeyguardQsUserSwitchComponentFactory = keyguardQsUserSwitchComponentFactory;
mKeyguardUserSwitcherComponentFactory = keyguardUserSwitcherComponentFactory;
- mQSDetailDisplayer = qsDetailDisplayer;
mFragmentService = fragmentService;
mSettingsChangeObserver = new SettingsChangeObserver(handler);
mShouldUseSplitNotificationShade =
@@ -876,8 +871,7 @@
mUiExecutor = uiExecutor;
mSecureSettings = secureSettings;
mInteractionJankMonitor = interactionJankMonitor;
- // TODO: inject via dagger instead of Dependency
- mSysUiState = Dependency.get(SysUiState.class);
+ mSysUiState = sysUiState;
pulseExpansionHandler.setPulseExpandAbortListener(() -> {
if (mQs != null) {
mQs.animateHeaderSlidingOut();
@@ -1137,7 +1131,6 @@
mKeyguardQsUserSwitchComponentFactory.build(userAvatarView);
mKeyguardQsUserSwitchController =
userSwitcherComponent.getKeyguardQsUserSwitchController();
- mKeyguardQsUserSwitchController.setNotificationPanelViewController(this);
mKeyguardQsUserSwitchController.init();
mKeyguardStatusBarViewController.setKeyguardUserSwitcherEnabled(true);
} else if (keyguardUserSwitcherView != null) {
@@ -1849,18 +1842,6 @@
}
}
- public void expandWithQsDetail(DetailAdapter qsDetailAdapter) {
- traceQsJank(true /* startTracing */, false /* wasCancelled */);
- flingSettings(0 /* velocity */, FLING_EXPAND);
- // When expanding with a panel, there's no meaningful touch point to correspond to. Set the
- // origin to somewhere above the screen. This is used for animations.
- int x = mQsFrame.getWidth() / 2;
- mQSDetailDisplayer.showDetailAdapter(qsDetailAdapter, x, -getHeight());
- if (mAccessibilityManager.isEnabled()) {
- mView.setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
- }
- }
-
public void expandWithoutQs() {
if (isQsExpanded()) {
flingSettings(0 /* velocity */, FLING_COLLAPSE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 716e8c7..f13334e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1110,6 +1110,12 @@
}
private void onFoldedStateChanged(boolean isFolded, boolean willGoToSleep) {
+ Trace.beginSection("StatusBar#onFoldedStateChanged");
+ onFoldedStateChangedInternal(isFolded, willGoToSleep);
+ Trace.endSection();
+ }
+
+ private void onFoldedStateChangedInternal(boolean isFolded, boolean willGoToSleep) {
// Folded state changes are followed by a screen off event.
// By default turning off the screen also closes the shade.
// We want to make sure that the shade status is kept after
@@ -3672,6 +3678,7 @@
@Override
public void onScreenTurnedOff() {
+ Trace.beginSection("StatusBar#onScreenTurnedOff");
mFalsingCollector.onScreenOff();
mScrimController.onScreenTurnedOff();
if (mCloseQsBeforeScreenOff) {
@@ -3679,6 +3686,7 @@
mCloseQsBeforeScreenOff = false;
}
updateIsKeyguard();
+ Trace.endSection();
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java
index cf9a5db..4081962 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java
@@ -235,11 +235,6 @@
// Settings are not available in setup
if (!mDeviceProvisionedController.isCurrentUserSetup()) return;
-
- QSPanelController qsPanelController = mStatusBar.getQSPanelController();
- if (subPanel != null && qsPanelController != null) {
- qsPanelController.openDetails(subPanel);
- }
mNotificationPanelViewController.expandWithQs();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
index 88a7dc7..c5d3937 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -27,7 +27,6 @@
import android.view.ViewGroup;
import com.android.internal.statusbar.StatusBarIcon;
-import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
@@ -74,17 +73,19 @@
Context context,
CommandQueue commandQueue,
DemoModeController demoModeController,
+ ConfigurationController configurationController,
+ TunerService tunerService,
DumpManager dumpManager) {
super(context.getResources().getStringArray(
com.android.internal.R.array.config_statusBarIcons));
- Dependency.get(ConfigurationController.class).addCallback(this);
+ configurationController.addCallback(this);
mContext = context;
loadDimens();
commandQueue.addCallback(this);
- Dependency.get(TunerService.class).addTunable(this, ICON_HIDE_LIST);
+ tunerService.addTunable(this, ICON_HIDE_LIST);
demoModeController.addCallback(this);
dumpManager.registerDumpable(getClass().getSimpleName(), this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
index d6fc0a4..6e1ec9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -43,7 +43,6 @@
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
/**
* Base class for dialogs that should appear over panels and keyguard.
@@ -220,10 +219,13 @@
}
}
- public static void setWindowOnTop(Dialog dialog) {
+ /**
+ * Ensure the window type is set properly to show over all other screens
+ */
+ public static void setWindowOnTop(Dialog dialog, boolean isKeyguardShowing) {
final Window window = dialog.getWindow();
window.setType(LayoutParams.TYPE_STATUS_BAR_SUB_PANEL);
- if (Dependency.get(KeyguardStateController.class).isShowing()) {
+ if (isKeyguardShowing) {
window.getAttributes().setFitInsetsTypes(
window.getAttributes().getFitInsetsTypes() & ~Type.statusBars());
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneDependenciesModule.java
deleted file mode 100644
index 79d72b3..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneDependenciesModule.java
+++ /dev/null
@@ -1,42 +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 com.android.systemui.statusbar.phone.dagger;
-
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.statusbar.notification.row.RowContentBindStage;
-import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper;
-import com.android.systemui.statusbar.phone.StatusBar;
-
-import dagger.Module;
-import dagger.Provides;
-
-/**
- * This module provides instances needed to construct {@link StatusBar}. These are moved to this
- * separate from {@link StatusBarPhoneModule} module so that components that wish to build their own
- * version of StatusBar can include just dependencies, without injecting StatusBar itself.
- */
-@Module
-public interface StatusBarPhoneDependenciesModule {
-
- /** */
- @SysUISingleton
- @Provides
- static NotificationGroupAlertTransferHelper provideNotificationGroupAlertTransferHelper(
- RowContentBindStage bindStage) {
- return new NotificationGroupAlertTransferHelper(bindStage);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index d3ff4a7..83bdd1b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -129,7 +129,7 @@
/**
* Dagger Module providing {@link StatusBar}.
*/
-@Module(includes = {StatusBarPhoneDependenciesModule.class})
+@Module
public interface StatusBarPhoneModule {
/**
* Provides our instance of StatusBar which is considered optional.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java
index e2dc905..d5f5362 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java
@@ -21,6 +21,7 @@
import com.android.systemui.R;
import com.android.systemui.battery.BatteryMeterView;
import com.android.systemui.dagger.qualifiers.RootView;
+import com.android.systemui.statusbar.HeadsUpStatusBarView;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.PhoneStatusBarTransitions;
import com.android.systemui.statusbar.phone.PhoneStatusBarView;
@@ -32,6 +33,8 @@
import com.android.systemui.statusbar.policy.Clock;
import com.android.systemui.statusbar.window.StatusBarWindowController;
+import java.util.Optional;
+
import javax.inject.Named;
import dagger.Binds;
@@ -44,6 +47,7 @@
String LIGHTS_OUT_NOTIF_VIEW = "lights_out_notif_view";
String OPERATOR_NAME_VIEW = "operator_name_view";
+ String OPERATOR_NAME_FRAME_VIEW = "operator_name_frame_view";
/** */
@Provides
@@ -80,6 +84,14 @@
/** */
@Provides
@StatusBarFragmentScope
+ @Named(OPERATOR_NAME_FRAME_VIEW)
+ static Optional<View> provideOperatorFrameNameView(@RootView PhoneStatusBarView view) {
+ return Optional.ofNullable(view.findViewById(R.id.operator_name_frame));
+ }
+
+ /** */
+ @Provides
+ @StatusBarFragmentScope
static Clock provideClock(@RootView PhoneStatusBarView view) {
return view.findViewById(R.id.clock);
}
@@ -119,4 +131,11 @@
) {
return new PhoneStatusBarTransitions(view, statusBarWindowController.getBackgroundView());
}
+
+ /** */
+ @Provides
+ @StatusBarFragmentScope
+ static HeadsUpStatusBarView providesHeasdUpStatusBarView(@RootView PhoneStatusBarView view) {
+ return view.findViewById(R.id.heads_up_status_bar_view);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserInfoTracker.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserInfoTracker.kt
index 2dbc19c..b0f7629 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserInfoTracker.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserInfoTracker.kt
@@ -19,12 +19,19 @@
import android.graphics.drawable.Drawable
import android.os.UserManager
-import com.android.systemui.DejankUtils.whitelistIpcs
+import com.android.systemui.Dumpable
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dump.DumpManager
import com.android.systemui.statusbar.policy.CallbackController
import com.android.systemui.statusbar.policy.UserInfoController
import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener
+import java.io.FileDescriptor
+import java.io.PrintWriter
+import java.util.concurrent.Executor
+
import javax.inject.Inject
/**
@@ -34,8 +41,11 @@
@SysUISingleton
class StatusBarUserInfoTracker @Inject constructor(
private val userInfoController: UserInfoController,
- private val userManager: UserManager
-) : CallbackController<CurrentUserChipInfoUpdatedListener> {
+ private val userManager: UserManager,
+ private val dumpManager: DumpManager,
+ @Main private val mainExecutor: Executor,
+ @Background private val backgroundExecutor: Executor
+) : CallbackController<CurrentUserChipInfoUpdatedListener>, Dumpable {
var currentUserName: String? = null
private set
var currentUserAvatar: Drawable? = null
@@ -53,7 +63,7 @@
}
init {
- startListening()
+ dumpManager.registerDumpable(TAG, this)
}
override fun addCallback(listener: CurrentUserChipInfoUpdatedListener) {
@@ -96,27 +106,33 @@
userInfoController.removeCallback(userInfoChangedListener)
}
- private fun checkUserSwitcherEnabled() {
- whitelistIpcs {
- userSwitcherEnabled = userManager.isUserSwitcherEnabled
- }
- }
-
/**
* Force a check to [UserManager.isUserSwitcherEnabled], and update listeners if the value has
* changed
*/
fun checkEnabled() {
- val wasEnabled = userSwitcherEnabled
- checkUserSwitcherEnabled()
+ backgroundExecutor.execute {
+ // Check on a background thread to avoid main thread Binder calls
+ val wasEnabled = userSwitcherEnabled
+ userSwitcherEnabled = userManager.isUserSwitcherEnabled
- if (wasEnabled != userSwitcherEnabled) {
- notifyListenersSettingChanged()
+ if (wasEnabled != userSwitcherEnabled) {
+ mainExecutor.execute {
+ notifyListenersSettingChanged()
+ }
+ }
}
}
+
+ override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
+ pw.println(" userSwitcherEnabled=$userSwitcherEnabled")
+ pw.println(" listening=$listening")
+ }
}
interface CurrentUserChipInfoUpdatedListener {
fun onCurrentUserChipInfoUpdated()
fun onStatusBarUserSwitcherSettingChanged(enabled: Boolean) {}
}
+
+private const val TAG = "StatusBarUserInfoTracker"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt
index a124753..909261f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt
@@ -16,9 +16,15 @@
package com.android.systemui.statusbar.phone.userswitcher
+import android.content.Intent
import android.view.View
+import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.qs.user.UserSwitchDialogController
+import com.android.systemui.user.UserSwitcherActivity
import com.android.systemui.util.ViewController
import javax.inject.Inject
@@ -30,7 +36,9 @@
view: StatusBarUserSwitcherContainer,
private val tracker: StatusBarUserInfoTracker,
private val featureController: StatusBarUserSwitcherFeatureController,
- private val userSwitcherDialogController: UserSwitchDialogController
+ private val userSwitcherDialogController: UserSwitchDialogController,
+ private val featureFlags: FeatureFlags,
+ private val activityStarter: ActivityStarter
) : ViewController<StatusBarUserSwitcherContainer>(view),
StatusBarUserSwitcherController {
private val listener = object : CurrentUserChipInfoUpdatedListener {
@@ -52,8 +60,17 @@
override fun onViewAttached() {
tracker.addCallback(listener)
featureController.addCallback(featureFlagListener)
- mView.setOnClickListener {
- userSwitcherDialogController.showDialog(it)
+ mView.setOnClickListener { view: View ->
+ if (featureFlags.isEnabled(Flags.FULL_SCREEN_USER_SWITCHER)) {
+ val intent = Intent(context, UserSwitcherActivity::class.java)
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
+
+ activityStarter.startActivity(intent, true /* dismissShade */,
+ ActivityLaunchAnimator.Controller.fromView(view, null),
+ true /* showOverlockscreenwhenlocked */)
+ } else {
+ userSwitcherDialogController.showDialog(view)
+ }
}
updateEnabled()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index 97d344a..562816f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -56,6 +56,7 @@
import com.android.systemui.tuner.TunerService.Tunable;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Calendar;
import java.util.Locale;
import java.util.TimeZone;
@@ -314,8 +315,8 @@
}
@Override
- public void onDarkChanged(Rect area, float darkIntensity, int tint) {
- mNonAdaptedColor = DarkIconDispatcher.getTint(area, this, tint);
+ public void onDarkChanged(ArrayList<Rect> areas, float darkIntensity, int tint) {
+ mNonAdaptedColor = DarkIconDispatcher.getTint(areas, this, tint);
setTextColor(mNonAdaptedColor);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
index d903639..1d414745 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
@@ -21,6 +21,7 @@
import android.annotation.Nullable;
import android.hardware.devicestate.DeviceStateManager;
+import android.os.Trace;
import android.util.Log;
import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
@@ -117,11 +118,16 @@
private void updateDeviceState(int state) {
Log.v(TAG, "updateDeviceState [state=" + state + "]");
- if (mDeviceState == state) {
- return;
- }
+ Trace.beginSection("updateDeviceState [state=" + state + "]");
+ try {
+ if (mDeviceState == state) {
+ return;
+ }
- readPersistedSetting(state);
+ readPersistedSetting(state);
+ } finally {
+ Trace.endSection();
+ }
}
private void readPersistedSetting(int state) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
index b591545..7e2488f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
@@ -37,12 +37,9 @@
import com.android.systemui.R;
import com.android.systemui.communal.CommunalStateController;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.qs.tiles.UserDetailView;
import com.android.systemui.qs.user.UserSwitchDialogController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.AnimatableProperty;
@@ -51,13 +48,11 @@
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
-import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.phone.UserAvatarView;
import com.android.systemui.util.ViewController;
import javax.inject.Inject;
-import javax.inject.Provider;
/**
* Manages the user switch on the Keyguard that is used for opening the QS user panel.
@@ -81,11 +76,8 @@
protected final SysuiStatusBarStateController mStatusBarStateController;
private final ConfigurationController mConfigurationController;
private final KeyguardVisibilityHelper mKeyguardVisibilityHelper;
- private final KeyguardUserDetailAdapter mUserDetailAdapter;
- private final FeatureFlags mFeatureFlags;
private final UserSwitchDialogController mUserSwitchDialogController;
private final UiEventLogger mUiEventLogger;
- private NotificationPanelViewController mNotificationPanelViewController;
private UserAvatarView mUserAvatarView;
UserSwitcherController.UserRecord mCurrentUser;
@@ -133,9 +125,7 @@
ConfigurationController configurationController,
SysuiStatusBarStateController statusBarStateController,
DozeParameters dozeParameters,
- Provider<UserDetailView.Adapter> userDetailViewAdapterProvider,
ScreenOffAnimationController screenOffAnimationController,
- FeatureFlags featureFlags,
UserSwitchDialogController userSwitchDialogController,
UiEventLogger uiEventLogger) {
super(view);
@@ -152,8 +142,6 @@
keyguardStateController, dozeParameters,
screenOffAnimationController, /* animateYPos= */ false,
/* visibleOnCommunal= */ false);
- mUserDetailAdapter = new KeyguardUserDetailAdapter(context, userDetailViewAdapterProvider);
- mFeatureFlags = featureFlags;
mUserSwitchDialogController = userSwitchDialogController;
mUiEventLogger = uiEventLogger;
}
@@ -182,11 +170,7 @@
mUiEventLogger.log(
LockscreenGestureLogger.LockscreenUiEvent.LOCKSCREEN_SWITCH_USER_TAP);
- if (mFeatureFlags.isEnabled(Flags.NEW_USER_SWITCHER)) {
- mUserSwitchDialogController.showDialog(mView);
- } else {
- openQsUserPanel();
- }
+ mUserSwitchDialogController.showDialog(mView);
});
mUserAvatarView.setAccessibilityDelegate(new View.AccessibilityDelegate() {
@@ -331,40 +315,4 @@
private boolean isListAnimating() {
return mKeyguardVisibilityHelper.isVisibilityAnimating();
}
-
- private void openQsUserPanel() {
- mNotificationPanelViewController.expandWithQsDetail(mUserDetailAdapter);
- }
-
- public void setNotificationPanelViewController(
- NotificationPanelViewController notificationPanelViewController) {
- mNotificationPanelViewController = notificationPanelViewController;
- }
-
- class KeyguardUserDetailAdapter extends UserSwitcherController.UserDetailAdapter {
- KeyguardUserDetailAdapter(Context context,
- Provider<UserDetailView.Adapter> userDetailViewAdapterProvider) {
- super(context, userDetailViewAdapterProvider);
- }
-
- @Override
- public boolean shouldAnimate() {
- return false;
- }
-
- @Override
- public int getDoneText() {
- return R.string.quick_settings_close_user_panel;
- }
-
- @Override
- public boolean onDoneButtonClicked() {
- if (mNotificationPanelViewController != null) {
- mNotificationPanelViewController.animateCloseQs(true /* animateAway */);
- return true;
- } else {
- return false;
- }
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 3ece240..f4e53e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -25,7 +25,6 @@
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.IActivityManager;
-import android.app.IActivityTaskManager;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -39,18 +38,17 @@
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.drawable.Drawable;
-import android.os.AsyncTask;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.telephony.TelephonyCallback;
+import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.view.View;
-import android.view.ViewGroup;
import android.view.WindowManagerGlobal;
import android.widget.BaseAdapter;
@@ -59,7 +57,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.UiEventLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.LatencyTracker;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.systemui.Dumpable;
@@ -76,16 +73,17 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.qs.QSUserSwitcherEvent;
-import com.android.systemui.qs.tiles.UserDetailView;
import com.android.systemui.qs.user.UserSwitchDialogController.DialogShower;
import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.user.CreateUserActivity;
import com.android.systemui.util.settings.SecureSettings;
+import dagger.Lazy;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
@@ -95,7 +93,6 @@
import java.util.concurrent.atomic.AtomicBoolean;
import javax.inject.Inject;
-import javax.inject.Provider;
/**
* Keeps a list of all users on the device for user switching.
@@ -129,10 +126,10 @@
private final ActivityStarter mActivityStarter;
private final BroadcastDispatcher mBroadcastDispatcher;
private final TelephonyListenerManager mTelephonyListenerManager;
- private final IActivityTaskManager mActivityTaskManager;
private final InteractionJankMonitor mInteractionJankMonitor;
private final LatencyTracker mLatencyTracker;
private final DialogLaunchAnimator mDialogLaunchAnimator;
+ private final Lazy<ShadeController> mShadeController;
private ArrayList<UserRecord> mUsers = new ArrayList<>();
@VisibleForTesting
@@ -152,13 +149,14 @@
private SparseBooleanArray mForcePictureLoadForUserId = new SparseBooleanArray(2);
private final UiEventLogger mUiEventLogger;
private final IActivityManager mActivityManager;
- public final DetailAdapter mUserDetailAdapter;
private final Executor mBgExecutor;
+ private final Executor mUiExecutor;
private final boolean mGuestUserAutoCreated;
private final AtomicBoolean mGuestIsResetting;
private final AtomicBoolean mGuestCreationScheduled;
private FalsingManager mFalsingManager;
private View mView;
+ private String mCreateSupervisedUserPackage;
@Inject
public UserSwitcherController(Context context,
@@ -174,28 +172,27 @@
UiEventLogger uiEventLogger,
FalsingManager falsingManager,
TelephonyListenerManager telephonyListenerManager,
- IActivityTaskManager activityTaskManager,
- UserDetailAdapter userDetailAdapter,
SecureSettings secureSettings,
@Background Executor bgExecutor,
+ @Main Executor uiExecutor,
InteractionJankMonitor interactionJankMonitor,
LatencyTracker latencyTracker,
DumpManager dumpManager,
+ Lazy<ShadeController> shadeController,
DialogLaunchAnimator dialogLaunchAnimator) {
mContext = context;
mActivityManager = activityManager;
mUserTracker = userTracker;
mBroadcastDispatcher = broadcastDispatcher;
mTelephonyListenerManager = telephonyListenerManager;
- mActivityTaskManager = activityTaskManager;
mUiEventLogger = uiEventLogger;
mFalsingManager = falsingManager;
mInteractionJankMonitor = interactionJankMonitor;
mLatencyTracker = latencyTracker;
mGuestResumeSessionReceiver = new GuestResumeSessionReceiver(
this, mUserTracker, mUiEventLogger, secureSettings);
- mUserDetailAdapter = userDetailAdapter;
mBgExecutor = bgExecutor;
+ mUiExecutor = uiExecutor;
if (!UserManager.isGuestUserEphemeral()) {
mGuestResumeSessionReceiver.register(mBroadcastDispatcher);
}
@@ -210,6 +207,7 @@
mActivityStarter = activityStarter;
mUserManager = userManager;
mDialogLaunchAnimator = dialogLaunchAnimator;
+ mShadeController = shadeController;
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_ADDED);
@@ -255,6 +253,9 @@
keyguardStateController.addCallback(mCallback);
listenForCallState();
+ mCreateSupervisedUserPackage = mContext.getString(
+ com.android.internal.R.string.config_supervisedUserCreationPackage);
+
dumpManager.registerDumpable(getClass().getSimpleName(), this);
refreshUsers(UserHandle.USER_NULL);
@@ -292,115 +293,134 @@
mForcePictureLoadForUserId.clear();
final boolean addUsersWhenLocked = mAddUsersFromLockScreen;
- new AsyncTask<SparseArray<Bitmap>, Void, ArrayList<UserRecord>>() {
- @SuppressWarnings("unchecked")
- @Override
- protected ArrayList<UserRecord> doInBackground(SparseArray<Bitmap>... params) {
- final SparseArray<Bitmap> bitmaps = params[0];
- List<UserInfo> infos = mUserManager.getAliveUsers();
- if (infos == null) {
- return null;
- }
- ArrayList<UserRecord> records = new ArrayList<>(infos.size());
- int currentId = mUserTracker.getUserId();
- // Check user switchability of the foreground user since SystemUI is running in
- // User 0
- boolean canSwitchUsers = mUserManager.getUserSwitchability(
- UserHandle.of(mUserTracker.getUserId())) == SWITCHABILITY_STATUS_OK;
- UserInfo currentUserInfo = null;
- UserRecord guestRecord = null;
+ mBgExecutor.execute(() -> {
+ List<UserInfo> infos = mUserManager.getAliveUsers();
+ if (infos == null) {
+ return;
+ }
+ ArrayList<UserRecord> records = new ArrayList<>(infos.size());
+ int currentId = mUserTracker.getUserId();
+ // Check user switchability of the foreground user since SystemUI is running in
+ // User 0
+ boolean canSwitchUsers = mUserManager.getUserSwitchability(
+ UserHandle.of(mUserTracker.getUserId())) == SWITCHABILITY_STATUS_OK;
+ UserRecord guestRecord = null;
- for (UserInfo info : infos) {
- boolean isCurrent = currentId == info.id;
- if (isCurrent) {
- currentUserInfo = info;
- }
- boolean switchToEnabled = canSwitchUsers || isCurrent;
- if (info.isEnabled()) {
- if (info.isGuest()) {
- // Tapping guest icon triggers remove and a user switch therefore
- // the icon shouldn't be enabled even if the user is current
- guestRecord = new UserRecord(info, null /* picture */,
- true /* isGuest */, isCurrent, false /* isAddUser */,
- false /* isRestricted */, canSwitchUsers);
- } else if (info.supportsSwitchToByUser()) {
- Bitmap picture = bitmaps.get(info.id);
- if (picture == null) {
- picture = mUserManager.getUserIcon(info.id);
+ for (UserInfo info : infos) {
+ boolean isCurrent = currentId == info.id;
+ boolean switchToEnabled = canSwitchUsers || isCurrent;
+ if (info.isEnabled()) {
+ if (info.isGuest()) {
+ // Tapping guest icon triggers remove and a user switch therefore
+ // the icon shouldn't be enabled even if the user is current
+ guestRecord = new UserRecord(info, null /* picture */,
+ true /* isGuest */, isCurrent, false /* isAddUser */,
+ false /* isRestricted */, canSwitchUsers,
+ false /* isAddSupervisedUser */);
+ } else if (info.supportsSwitchToByUser()) {
+ Bitmap picture = bitmaps.get(info.id);
+ if (picture == null) {
+ picture = mUserManager.getUserIcon(info.id);
- if (picture != null) {
- int avatarSize = mContext.getResources()
- .getDimensionPixelSize(R.dimen.max_avatar_size);
- picture = Bitmap.createScaledBitmap(
- picture, avatarSize, avatarSize, true);
- }
+ if (picture != null) {
+ int avatarSize = mContext.getResources()
+ .getDimensionPixelSize(R.dimen.max_avatar_size);
+ picture = Bitmap.createScaledBitmap(
+ picture, avatarSize, avatarSize, true);
}
- records.add(new UserRecord(info, picture, false /* isGuest */,
- isCurrent, false /* isAddUser */, false /* isRestricted */,
- switchToEnabled));
}
+ records.add(new UserRecord(info, picture, false /* isGuest */,
+ isCurrent, false /* isAddUser */, false /* isRestricted */,
+ switchToEnabled, false /* isAddSupervisedUser */));
}
}
- if (records.size() > 1 || guestRecord != null) {
- Prefs.putBoolean(mContext, Key.SEEN_MULTI_USER, true);
- }
+ }
+ if (records.size() > 1 || guestRecord != null) {
+ Prefs.putBoolean(mContext, Key.SEEN_MULTI_USER, true);
+ }
- boolean systemCanCreateUsers = !mUserManager.hasBaseUserRestriction(
- UserManager.DISALLOW_ADD_USER, UserHandle.SYSTEM);
- boolean currentUserCanCreateUsers = currentUserInfo != null
- && (currentUserInfo.isAdmin()
- || currentUserInfo.id == UserHandle.USER_SYSTEM)
- && systemCanCreateUsers;
- boolean anyoneCanCreateUsers = systemCanCreateUsers && addUsersWhenLocked;
- boolean canCreateGuest = (currentUserCanCreateUsers || anyoneCanCreateUsers)
- && guestRecord == null;
- boolean canCreateUser = (currentUserCanCreateUsers || anyoneCanCreateUsers)
- && mUserManager.canAddMoreUsers(UserManager.USER_TYPE_FULL_SECONDARY);
- boolean createIsRestricted = !addUsersWhenLocked;
-
- if (guestRecord == null) {
- if (mGuestUserAutoCreated) {
- // If mGuestIsResetting=true, the switch should be disabled since
- // we will just use it as an indicator for "Resetting guest...".
- // Otherwise, default to canSwitchUsers.
- boolean isSwitchToGuestEnabled =
- !mGuestIsResetting.get() && canSwitchUsers;
- guestRecord = new UserRecord(null /* info */, null /* picture */,
- true /* isGuest */, false /* isCurrent */,
- false /* isAddUser */, false /* isRestricted */,
- isSwitchToGuestEnabled);
- checkIfAddUserDisallowedByAdminOnly(guestRecord);
- records.add(guestRecord);
- } else if (canCreateGuest) {
- guestRecord = new UserRecord(null /* info */, null /* picture */,
- true /* isGuest */, false /* isCurrent */,
- false /* isAddUser */, createIsRestricted, canSwitchUsers);
- checkIfAddUserDisallowedByAdminOnly(guestRecord);
- records.add(guestRecord);
- }
- } else {
+ if (guestRecord == null) {
+ if (mGuestUserAutoCreated) {
+ // If mGuestIsResetting=true, the switch should be disabled since
+ // we will just use it as an indicator for "Resetting guest...".
+ // Otherwise, default to canSwitchUsers.
+ boolean isSwitchToGuestEnabled = !mGuestIsResetting.get() && canSwitchUsers;
+ guestRecord = new UserRecord(null /* info */, null /* picture */,
+ true /* isGuest */, false /* isCurrent */,
+ false /* isAddUser */, false /* isRestricted */,
+ isSwitchToGuestEnabled, false /* isAddSupervisedUser */);
+ checkIfAddUserDisallowedByAdminOnly(guestRecord);
+ records.add(guestRecord);
+ } else if (canCreateGuest(guestRecord != null)) {
+ guestRecord = new UserRecord(null /* info */, null /* picture */,
+ true /* isGuest */, false /* isCurrent */,
+ false /* isAddUser */, createIsRestricted(), canSwitchUsers,
+ false /* isAddSupervisedUser */);
+ checkIfAddUserDisallowedByAdminOnly(guestRecord);
records.add(guestRecord);
}
-
- if (canCreateUser) {
- UserRecord addUserRecord = new UserRecord(null /* info */, null /* picture */,
- false /* isGuest */, false /* isCurrent */, true /* isAddUser */,
- createIsRestricted, canSwitchUsers);
- checkIfAddUserDisallowedByAdminOnly(addUserRecord);
- records.add(addUserRecord);
- }
-
- return records;
+ } else {
+ records.add(guestRecord);
}
- @Override
- protected void onPostExecute(ArrayList<UserRecord> userRecords) {
- if (userRecords != null) {
- mUsers = userRecords;
+ if (canCreateUser()) {
+ UserRecord addUserRecord = new UserRecord(null /* info */, null /* picture */,
+ false /* isGuest */, false /* isCurrent */, true /* isAddUser */,
+ createIsRestricted(), canSwitchUsers,
+ false /* isAddSupervisedUser */);
+ checkIfAddUserDisallowedByAdminOnly(addUserRecord);
+ records.add(addUserRecord);
+ }
+
+ if (canCreateSupervisedUser()) {
+ UserRecord addUserRecord = new UserRecord(null /* info */, null /* picture */,
+ false /* isGuest */, false /* isCurrent */, false /* isAddUser */,
+ createIsRestricted(), canSwitchUsers, true /* isAddSupervisedUser */);
+ checkIfAddUserDisallowedByAdminOnly(addUserRecord);
+ records.add(addUserRecord);
+ }
+
+ mUiExecutor.execute(() -> {
+ if (records != null) {
+ mUsers = records;
notifyAdapters();
}
- }
- }.execute((SparseArray) bitmaps);
+ });
+ });
+ }
+
+ boolean systemCanCreateUsers() {
+ return !mUserManager.hasBaseUserRestriction(
+ UserManager.DISALLOW_ADD_USER, UserHandle.SYSTEM);
+ }
+
+ boolean currentUserCanCreateUsers() {
+ UserInfo currentUser = mUserTracker.getUserInfo();
+ return currentUser != null
+ && (currentUser.isAdmin() || mUserTracker.getUserId() == UserHandle.USER_SYSTEM)
+ && systemCanCreateUsers();
+ }
+
+ boolean anyoneCanCreateUsers() {
+ return systemCanCreateUsers() && mAddUsersFromLockScreen;
+ }
+
+ boolean canCreateGuest(boolean hasExistingGuest) {
+ return (currentUserCanCreateUsers() || anyoneCanCreateUsers())
+ && !hasExistingGuest;
+ }
+
+ boolean canCreateUser() {
+ return (currentUserCanCreateUsers() || anyoneCanCreateUsers())
+ && mUserManager.canAddMoreUsers(UserManager.USER_TYPE_FULL_SECONDARY);
+ }
+
+ boolean createIsRestricted() {
+ return !mAddUsersFromLockScreen;
+ }
+
+ boolean canCreateSupervisedUser() {
+ return !TextUtils.isEmpty(mCreateSupervisedUserPackage) && canCreateUser();
}
private void pauseRefreshUsers() {
@@ -485,6 +505,9 @@
} else if (record.isAddUser) {
showAddUserDialog(dialogShower);
return;
+ } else if (record.isAddSupervisedUser) {
+ startSupervisedUserActivity();
+ return;
} else {
id = record.info.id;
}
@@ -561,6 +584,22 @@
}
}
+ private void startSupervisedUserActivity() {
+ final Intent intent = new Intent()
+ .setAction(UserManager.ACTION_CREATE_SUPERVISED_USER)
+ .setPackage(mCreateSupervisedUserPackage)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ // TODO(b/209659998): [to-be-removed] fallback activity for supervised user creation.
+ if (mContext.getPackageManager().resolveActivity(intent, 0) == null) {
+ intent.setPackage(null)
+ .setClassName("com.android.settings",
+ "com.android.settings.users.AddSupervisedUserActivity");
+ }
+
+ mContext.startActivity(intent);
+ }
+
private void listenForCallState() {
mTelephonyListenerManager.addCallStateListener(mPhoneStateListener);
}
@@ -941,6 +980,8 @@
}
} else if (item.isAddUser) {
return context.getString(R.string.user_add_user);
+ } else if (item.isAddSupervisedUser) {
+ return context.getString(R.string.add_user_supervised);
} else {
return item.info.name;
}
@@ -955,9 +996,11 @@
protected static Drawable getIconDrawable(Context context, UserRecord item) {
int iconRes;
if (item.isAddUser) {
- iconRes = R.drawable.ic_add_circle;
+ iconRes = R.drawable.ic_account_circle;
} else if (item.isGuest) {
- iconRes = R.drawable.ic_avatar_guest_user;
+ iconRes = R.drawable.ic_account_circle_filled;
+ } else if (item.isAddSupervisedUser) {
+ iconRes = R.drawable.ic_add_supervised_user;
} else {
iconRes = R.drawable.ic_avatar_user;
}
@@ -1000,6 +1043,7 @@
public final boolean isGuest;
public final boolean isCurrent;
public final boolean isAddUser;
+ public final boolean isAddSupervisedUser;
/** If true, the record is only visible to the owner and only when unlocked. */
public final boolean isRestricted;
public boolean isDisabledByAdmin;
@@ -1007,7 +1051,8 @@
public boolean isSwitchToEnabled;
public UserRecord(UserInfo info, Bitmap picture, boolean isGuest, boolean isCurrent,
- boolean isAddUser, boolean isRestricted, boolean isSwitchToEnabled) {
+ boolean isAddUser, boolean isRestricted, boolean isSwitchToEnabled,
+ boolean isAddSupervisedUser) {
this.info = info;
this.picture = picture;
this.isGuest = isGuest;
@@ -1015,11 +1060,12 @@
this.isAddUser = isAddUser;
this.isRestricted = isRestricted;
this.isSwitchToEnabled = isSwitchToEnabled;
+ this.isAddSupervisedUser = isAddSupervisedUser;
}
public UserRecord copyWithIsCurrent(boolean _isCurrent) {
return new UserRecord(info, picture, isGuest, _isCurrent, isAddUser, isRestricted,
- isSwitchToEnabled);
+ isSwitchToEnabled, isAddSupervisedUser);
}
public int resolveId() {
@@ -1043,6 +1089,7 @@
}
if (isGuest) sb.append(" <isGuest>");
if (isAddUser) sb.append(" <isAddUser>");
+ if (isAddSupervisedUser) sb.append(" <isAddSupervisedUser>");
if (isCurrent) sb.append(" <isCurrent>");
if (picture != null) sb.append(" <hasPicture>");
if (isRestricted) sb.append(" <isRestricted>");
@@ -1058,77 +1105,6 @@
}
}
- public static class UserDetailAdapter implements DetailAdapter {
- private final Intent USER_SETTINGS_INTENT = new Intent(Settings.ACTION_USER_SETTINGS);
-
- private final Context mContext;
- private final Provider<UserDetailView.Adapter> mUserDetailViewAdapterProvider;
-
- @Inject
- UserDetailAdapter(Context context,
- Provider<UserDetailView.Adapter> userDetailViewAdapterProvider) {
- mContext = context;
- mUserDetailViewAdapterProvider = userDetailViewAdapterProvider;
- }
-
- @Override
- public CharSequence getTitle() {
- return mContext.getString(R.string.quick_settings_user_title);
- }
-
- @Override
- public View createDetailView(Context context, View convertView, ViewGroup parent) {
- UserDetailView v;
- if (!(convertView instanceof UserDetailView)) {
- v = UserDetailView.inflate(context, parent, false);
- v.setAdapter(mUserDetailViewAdapterProvider.get());
- } else {
- v = (UserDetailView) convertView;
- }
- v.refreshAdapter();
- return v;
- }
-
- @Override
- public Intent getSettingsIntent() {
- return USER_SETTINGS_INTENT;
- }
-
- @Override
- public int getSettingsText() {
- return R.string.quick_settings_more_user_settings;
- }
-
- @Override
- public Boolean getToggleState() {
- return null;
- }
-
- @Override
- public void setToggleState(boolean state) {
- }
-
- @Override
- public int getMetricsCategory() {
- return MetricsEvent.QS_USERDETAIL;
- }
-
- @Override
- public UiEventLogger.UiEventEnum openDetailEvent() {
- return QSUserSwitcherEvent.QS_USER_DETAIL_OPEN;
- }
-
- @Override
- public UiEventLogger.UiEventEnum closeDetailEvent() {
- return QSUserSwitcherEvent.QS_USER_DETAIL_CLOSE;
- }
-
- @Override
- public UiEventLogger.UiEventEnum moreSettingsEvent() {
- return QSUserSwitcherEvent.QS_USER_MORE_SETTINGS;
- }
- };
-
private final KeyguardStateController.Callback mCallback =
new KeyguardStateController.Callback() {
@Override
@@ -1178,7 +1154,7 @@
context.getString(mGuestUserAutoCreated
? com.android.settingslib.R.string.guest_reset_guest_confirm_button
: R.string.guest_exit_guest_dialog_remove), this);
- SystemUIDialog.setWindowOnTop(this);
+ SystemUIDialog.setWindowOnTop(this, mKeyguardStateController.isShowing());
setCanceledOnTouchOutside(false);
mGuestId = guestId;
mTargetId = targetId;
@@ -1213,7 +1189,7 @@
context.getString(android.R.string.cancel), this);
setButton(DialogInterface.BUTTON_POSITIVE,
context.getString(android.R.string.ok), this);
- SystemUIDialog.setWindowOnTop(this);
+ SystemUIDialog.setWindowOnTop(this, mKeyguardStateController.isShowing());
}
@Override
@@ -1230,33 +1206,8 @@
if (ActivityManager.isUserAMonkey()) {
return;
}
- Intent intent = CreateUserActivity.createIntentForStart(getContext());
-
- // There are some differences between ActivityStarter and ActivityTaskManager in
- // terms of how they start an activity. ActivityStarter hides the notification bar
- // before starting the activity to make sure nothing is in front of the new
- // activity. ActivityStarter also tries to unlock the device if it's locked.
- // When locked with PIN/pattern/password then it shows the prompt, if there are no
- // security steps then it dismisses the keyguard and then starts the activity.
- // ActivityTaskManager doesn't hide the notification bar or unlocks the device, but
- // it can start an activity on top of the locked screen.
- if (!mKeyguardStateController.isUnlocked()
- && !mKeyguardStateController.canDismissLockScreen()) {
- // Device is locked and can't be unlocked without a PIN/pattern/password so we
- // need to use ActivityTaskManager to start the activity on top of the locked
- // screen.
- try {
- mActivityTaskManager.startActivity(null,
- mContext.getBasePackageName(), mContext.getAttributionTag(), intent,
- intent.resolveTypeIfNeeded(mContext.getContentResolver()), null,
- null, 0, 0, null, null);
- } catch (RemoteException e) {
- e.printStackTrace();
- Log.e(TAG, "Couldn't start create user activity", e);
- }
- } else {
- mActivityStarter.startActivity(intent, true);
- }
+ mShadeController.get().collapsePanel();
+ getContext().startActivity(CreateUserActivity.createIntentForStart(getContext()));
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
index 52b58d4..71355bb 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
@@ -23,6 +23,7 @@
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TunerSwitch);
mDefault = a.getBoolean(R.styleable.TunerSwitch_defValue, false);
mAction = a.getInt(R.styleable.TunerSwitch_metricsAction, -1);
+ a.recycle();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerZenModePanel.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerZenModePanel.java
deleted file mode 100644
index 4d95969..0000000
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerZenModePanel.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2016 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.tuner;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.Intent;
-import android.provider.Settings;
-import android.provider.Settings.Global;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.widget.Checkable;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import com.android.systemui.Prefs;
-import com.android.systemui.R;
-import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.systemui.volume.ZenModePanel;
-import com.android.systemui.volume.ZenModePanel.Callback;
-
-public class TunerZenModePanel extends LinearLayout implements OnClickListener {
- private static final String TAG = "TunerZenModePanel";
-
- private Callback mCallback;
- private ZenModePanel mZenModePanel;
- private View mHeaderSwitch;
- private int mZenMode;
- private ZenModeController mController;
- private View mButtons;
- private View mMoreSettings;
- private View mDone;
- private OnClickListener mDoneListener;
- private boolean mEditing;
-
- public TunerZenModePanel(Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- }
-
- public void init(ZenModeController zenModeController) {
- mController = zenModeController;
- mHeaderSwitch = findViewById(R.id.tuner_zen_switch);
- mHeaderSwitch.setVisibility(View.VISIBLE);
- mHeaderSwitch.setOnClickListener(this);
- ((TextView) mHeaderSwitch.findViewById(android.R.id.title)).setText(
- R.string.quick_settings_dnd_label);
- mZenModePanel = (ZenModePanel) findViewById(R.id.zen_mode_panel);
- mZenModePanel.init(zenModeController);
- mButtons = findViewById(R.id.tuner_zen_buttons);
- mMoreSettings = mButtons.findViewById(android.R.id.button2);
- mMoreSettings.setOnClickListener(this);
- ((TextView) mMoreSettings).setText(R.string.quick_settings_more_settings);
- mDone = mButtons.findViewById(android.R.id.button1);
- mDone.setOnClickListener(this);
- ((TextView) mDone).setText(R.string.quick_settings_done);
- // Hide the resizing space because it causes issues in the volume panel.
- ViewGroup detail_header = findViewById(R.id.tuner_zen_switch);
- detail_header.getChildAt(0).setVisibility(View.GONE);
- // No background so it can blend with volume panel.
- findViewById(R.id.edit_container).setBackground(null);
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- mEditing = false;
- }
-
- public void setCallback(Callback zenPanelCallback) {
- mCallback = zenPanelCallback;
- mZenModePanel.setCallback(zenPanelCallback);
- }
-
- @Override
- public void onClick(View v) {
- if (v == mHeaderSwitch) {
- mEditing = true;
- if (mZenMode == Global.ZEN_MODE_OFF) {
- mZenMode = Prefs.getInt(mContext, Prefs.Key.DND_FAVORITE_ZEN,
- Global.ZEN_MODE_ALARMS);
- mController.setZen(mZenMode, null, TAG);
- postUpdatePanel();
- } else {
- mZenMode = Global.ZEN_MODE_OFF;
- mController.setZen(Global.ZEN_MODE_OFF, null, TAG);
- postUpdatePanel();
- }
- } else if (v == mMoreSettings) {
- Intent intent = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- getContext().startActivity(intent);
- } else if (v == mDone) {
- mEditing = false;
- setVisibility(View.GONE);
- mDoneListener.onClick(v);
- }
- }
-
- public boolean isEditing() {
- return mEditing;
- }
-
- public void setZenState(int zenMode) {
- mZenMode = zenMode;
- postUpdatePanel();
- }
-
- private void postUpdatePanel() {
- // The complicated structure from reusing the same ZenPanel has resulted in some
- // unstableness/flickering from callbacks coming in quickly. To solve this just
- // post the UI updates a little bit.
- removeCallbacks(mUpdate);
- postDelayed(mUpdate, 40);
- }
-
- public void setDoneListener(OnClickListener onClickListener) {
- mDoneListener = onClickListener;
- }
-
- private void updatePanel() {
- boolean zenOn = mZenMode != Global.ZEN_MODE_OFF;
- ((Checkable) mHeaderSwitch.findViewById(android.R.id.toggle)).setChecked(zenOn);
- mZenModePanel.setVisibility(zenOn ? View.VISIBLE : View.GONE);
- mButtons.setVisibility(zenOn ? View.VISIBLE : View.GONE);
- }
-
- private final Runnable mUpdate = new Runnable() {
- @Override
- public void run() {
- updatePanel();
- }
- };
-}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TVSystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/tv/TVSystemUICoreStartableModule.kt
new file mode 100644
index 0000000..ad8dc82
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tv/TVSystemUICoreStartableModule.kt
@@ -0,0 +1,164 @@
+/*
+ * 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.tv
+
+import com.android.systemui.CoreStartable
+import com.android.systemui.SliceBroadcastRelayHandler
+import com.android.systemui.accessibility.WindowMagnification
+import com.android.systemui.dagger.qualifiers.PerUser
+import com.android.systemui.globalactions.GlobalActionsComponent
+import com.android.systemui.keyboard.KeyboardUI
+import com.android.systemui.media.RingtonePlayer
+import com.android.systemui.media.systemsounds.HomeSoundEffectController
+import com.android.systemui.power.PowerUI
+import com.android.systemui.privacy.television.TvOngoingPrivacyChip
+import com.android.systemui.shortcut.ShortcutKeyDispatcher
+import com.android.systemui.statusbar.notification.InstantAppNotifier
+import com.android.systemui.statusbar.tv.TvStatusBar
+import com.android.systemui.statusbar.tv.VpnStatusObserver
+import com.android.systemui.statusbar.tv.notifications.TvNotificationHandler
+import com.android.systemui.statusbar.tv.notifications.TvNotificationPanel
+import com.android.systemui.toast.ToastUI
+import com.android.systemui.usb.StorageNotification
+import com.android.systemui.util.NotificationChannels
+import com.android.systemui.volume.VolumeUI
+import com.android.systemui.wmshell.WMShell
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+
+/**
+ * Collection of {@link CoreStartable}s that should be run on TV.
+ */
+@Module
+abstract class TVSystemUICoreStartableModule {
+ /** Inject into GlobalActionsComponent. */
+ @Binds
+ @IntoMap
+ @ClassKey(GlobalActionsComponent::class)
+ abstract fun bindGlobalActionsComponent(sysui: GlobalActionsComponent): CoreStartable
+
+ /** Inject into HomeSoundEffectController. */
+ @Binds
+ @IntoMap
+ @ClassKey(HomeSoundEffectController::class)
+ abstract fun bindHomeSoundEffectController(sysui: HomeSoundEffectController): CoreStartable
+
+ /** Inject into InstantAppNotifier. */
+ @Binds
+ @IntoMap
+ @ClassKey(InstantAppNotifier::class)
+ abstract fun bindInstantAppNotifier(sysui: InstantAppNotifier): CoreStartable
+
+ /** Inject into KeyboardUI. */
+ @Binds
+ @IntoMap
+ @ClassKey(KeyboardUI::class)
+ abstract fun bindKeyboardUI(sysui: KeyboardUI): CoreStartable
+
+ /** Inject into NotificationChannels. */
+ @Binds
+ @IntoMap
+ @ClassKey(NotificationChannels::class)
+ @PerUser
+ abstract fun bindNotificationChannels(sysui: NotificationChannels): CoreStartable
+
+ /** Inject into PowerUI. */
+ @Binds
+ @IntoMap
+ @ClassKey(PowerUI::class)
+ abstract fun bindPowerUI(sysui: PowerUI): CoreStartable
+
+ /** Inject into RingtonePlayer. */
+ @Binds
+ @IntoMap
+ @ClassKey(RingtonePlayer::class)
+ abstract fun bind(sysui: RingtonePlayer): CoreStartable
+
+ /** Inject into ShortcutKeyDispatcher. */
+ @Binds
+ @IntoMap
+ @ClassKey(ShortcutKeyDispatcher::class)
+ abstract fun bindShortcutKeyDispatcher(sysui: ShortcutKeyDispatcher): CoreStartable
+
+ /** Inject into SliceBroadcastRelayHandler. */
+ @Binds
+ @IntoMap
+ @ClassKey(SliceBroadcastRelayHandler::class)
+ abstract fun bindSliceBroadcastRelayHandler(sysui: SliceBroadcastRelayHandler): CoreStartable
+
+ /** Inject into StorageNotification. */
+ @Binds
+ @IntoMap
+ @ClassKey(StorageNotification::class)
+ abstract fun bindStorageNotification(sysui: StorageNotification): CoreStartable
+
+ /** Inject into ToastUI. */
+ @Binds
+ @IntoMap
+ @ClassKey(ToastUI::class)
+ abstract fun bindToastUI(service: ToastUI): CoreStartable
+
+ /** Inject into TvNotificationHandler. */
+ @Binds
+ @IntoMap
+ @ClassKey(TvNotificationHandler::class)
+ abstract fun bindTvNotificationHandler(sysui: TvNotificationHandler): CoreStartable
+
+ /** Inject into TvNotificationPanel. */
+ @Binds
+ @IntoMap
+ @ClassKey(TvNotificationPanel::class)
+ abstract fun bindTvNotificationPanel(sysui: TvNotificationPanel): CoreStartable
+
+ /** Inject into TvOngoingPrivacyChip. */
+ @Binds
+ @IntoMap
+ @ClassKey(TvOngoingPrivacyChip::class)
+ abstract fun bindTvOngoingPrivacyChip(sysui: TvOngoingPrivacyChip): CoreStartable
+
+ /** Inject into TvStatusBar. */
+ @Binds
+ @IntoMap
+ @ClassKey(TvStatusBar::class)
+ abstract fun bindTvStatusBar(sysui: TvStatusBar): CoreStartable
+
+ /** Inject into VolumeUI. */
+ @Binds
+ @IntoMap
+ @ClassKey(VolumeUI::class)
+ abstract fun bindVolumeUI(sysui: VolumeUI): CoreStartable
+
+ /** Inject into VpnStatusObserver. */
+ @Binds
+ @IntoMap
+ @ClassKey(VpnStatusObserver::class)
+ abstract fun bindVpnStatusObserver(sysui: VpnStatusObserver): CoreStartable
+
+ /** Inject into WindowMagnification. */
+ @Binds
+ @IntoMap
+ @ClassKey(WindowMagnification::class)
+ abstract fun bindWindowMagnification(sysui: WindowMagnification): CoreStartable
+
+ /** Inject into WMShell. */
+ @Binds
+ @IntoMap
+ @ClassKey(WMShell::class)
+ abstract fun bindWMShell(sysui: WMShell): CoreStartable
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java b/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java
index bef05eb..6fdce1a 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java
@@ -34,6 +34,7 @@
DependencyProvider.class,
SystemUIBinder.class,
SystemUIModule.class,
+ TVSystemUICoreStartableModule.class,
TvSystemUIModule.class,
TvSystemUIBinder.class})
public interface TvSysUIComponent extends SysUIComponent {
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java
index d0fb91c..23f37ec 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java
@@ -16,28 +16,13 @@
package com.android.systemui.tv;
-import com.android.systemui.CoreStartable;
import com.android.systemui.dagger.GlobalRootComponent;
-import com.android.systemui.statusbar.tv.VpnStatusObserver;
-import com.android.systemui.statusbar.tv.notifications.TvNotificationHandler;
import dagger.Binds;
import dagger.Module;
-import dagger.multibindings.ClassKey;
-import dagger.multibindings.IntoMap;
@Module
interface TvSystemUIBinder {
@Binds
GlobalRootComponent bindGlobalRootComponent(TvGlobalRootComponent globalRootComponent);
-
- @Binds
- @IntoMap
- @ClassKey(TvNotificationHandler.class)
- CoreStartable bindTvNotificationHandler(TvNotificationHandler systemui);
-
- @Binds
- @IntoMap
- @ClassKey(VpnStatusObserver.class)
- CoreStartable bindVpnStatusObserver(VpnStatusObserver systemui);
}
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index cf361ec..345fc99 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -46,10 +46,15 @@
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.systemui.CoreStartable;
import com.android.systemui.SystemUIApplication;
+import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.util.NotificationChannels;
import java.util.List;
+import javax.inject.Inject;
+
+/** */
+@SysUISingleton
public class StorageNotification extends CoreStartable {
private static final String TAG = "StorageNotification";
@@ -61,6 +66,7 @@
private NotificationManager mNotificationManager;
private StorageManager mStorageManager;
+ @Inject
public StorageNotification(Context context) {
super(context);
}
diff --git a/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java b/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java
index 890ee5f..c9de966 100644
--- a/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java
@@ -44,7 +44,9 @@
* Creates an intent to start this activity.
*/
public static Intent createIntentForStart(Context context) {
- return new Intent(context, CreateUserActivity.class);
+ Intent intent = new Intent(context, CreateUserActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
+ return intent;
}
private static final String TAG = "CreateUserActivity";
diff --git a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
index d6a8ab2..14585fb 100644
--- a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
@@ -27,11 +27,10 @@
import android.graphics.drawable.LayerDrawable
import android.os.Bundle
import android.os.UserManager
+import android.provider.Settings
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import android.view.WindowInsets
-import android.view.WindowInsets.Type
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.ImageView
@@ -45,6 +44,7 @@
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.FalsingManager.LOW_PENALTY
+import com.android.systemui.statusbar.phone.ShadeController
import com.android.systemui.statusbar.policy.UserSwitcherController
import com.android.systemui.statusbar.policy.UserSwitcherController.BaseUserAdapter
import com.android.systemui.statusbar.policy.UserSwitcherController.UserRecord
@@ -64,15 +64,26 @@
private val broadcastDispatcher: BroadcastDispatcher,
private val layoutInflater: LayoutInflater,
private val falsingManager: FalsingManager,
- private val userManager: UserManager
+ private val userManager: UserManager,
+ private val shadeController: ShadeController
) : LifecycleActivity() {
private lateinit var parent: ViewGroup
private lateinit var broadcastReceiver: BroadcastReceiver
private var popupMenu: UserSwitcherPopupMenu? = null
private lateinit var addButton: View
- private var addUserItem: UserRecord? = null
- private var addGuestItem: UserRecord? = null
+ private var addUserRecords = mutableListOf<UserRecord>()
+ // When the add users options become available, insert another option to manage users
+ private val manageUserRecord = UserRecord(
+ null /* info */,
+ null /* picture */,
+ false /* isGuest */,
+ false /* isCurrent */,
+ false /* isAddUser */,
+ false /* isRestricted */,
+ false /* isSwitchToEnabled */,
+ false /* isAddSupervisedUser */
+ )
private val adapter = object : BaseUserAdapter(userSwitcherController) {
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
@@ -104,7 +115,18 @@
return view
}
+ override fun getName(context: Context, item: UserRecord): String {
+ return if (item == manageUserRecord) {
+ getString(R.string.manage_users)
+ } else {
+ super.getName(context, item)
+ }
+ }
+
fun findUserIcon(item: UserRecord): Drawable {
+ if (item == manageUserRecord) {
+ return getDrawable(R.drawable.ic_manage_users)
+ }
if (item.info == null) {
return getIconDrawable(this@UserSwitcherActivity, item)
}
@@ -169,20 +191,11 @@
super.onCreate(savedInstanceState)
setContentView(R.layout.user_switcher_fullscreen)
+ window.decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)
- parent = requireViewById<ViewGroup>(R.id.user_switcher_root).apply {
- setOnApplyWindowInsetsListener {
- v: View, insets: WindowInsets ->
- v.apply {
- val l = getPaddingLeft()
- val t = getPaddingTop()
- val r = getPaddingRight()
- setPadding(l, t, r, insets.getInsets(Type.systemBars()).bottom)
- }
-
- WindowInsets.CONSUMED
- }
- }
+ parent = requireViewById<ViewGroup>(R.id.user_switcher_root)
requireViewById<View>(R.id.cancel).apply {
setOnClickListener {
@@ -203,15 +216,19 @@
private fun showPopupMenu() {
val items = mutableListOf<UserRecord>()
- addUserItem?.let { items.add(it) }
- addGuestItem?.let { items.add(it) }
+ addUserRecords.forEach { items.add(it) }
var popupMenuAdapter = ItemAdapter(
this,
R.layout.user_switcher_fullscreen_popup_item,
layoutInflater,
{ item: UserRecord -> adapter.getName(this@UserSwitcherActivity, item) },
- { item: UserRecord -> adapter.findUserIcon(item) }
+ { item: UserRecord -> adapter.findUserIcon(item).mutate().apply {
+ setTint(resources.getColor(
+ R.color.user_switcher_fullscreen_popup_item_tint,
+ getTheme()
+ ))
+ } }
)
popupMenuAdapter.addAll(items)
@@ -225,10 +242,19 @@
}
// -1 for the header
val item = popupMenuAdapter.getItem(pos - 1)
- adapter.onUserListItemClicked(item)
+ if (item == manageUserRecord) {
+ val i = Intent().setAction(Settings.ACTION_USER_SETTINGS)
+ this@UserSwitcherActivity.startActivity(i)
+ } else {
+ adapter.onUserListItemClicked(item)
+ }
dismiss()
popupMenu = null
+
+ if (!item.isAddUser) {
+ this@UserSwitcherActivity.finish()
+ }
}
show()
@@ -245,14 +271,15 @@
}
}
parent.removeViews(start, count)
+ addUserRecords.clear()
val flow = requireViewById<Flow>(R.id.flow)
for (i in 0 until adapter.getCount()) {
val item = adapter.getItem(i)
- if (item.isAddUser) {
- addUserItem = item
- } else if (item.isGuest && item.info == null) {
- addGuestItem = item
+ if (item.isAddUser ||
+ item.isAddSupervisedUser ||
+ item.isGuest && item.info == null) {
+ addUserRecords.add(item)
} else {
val userView = adapter.getView(i, null, parent)
userView.setId(View.generateViewId())
@@ -273,7 +300,8 @@
}
}
- if (addUserItem != null || addGuestItem != null) {
+ if (!addUserRecords.isEmpty()) {
+ addUserRecords.add(manageUserRecord)
addButton.visibility = View.VISIBLE
} else {
addButton.visibility = View.GONE
diff --git a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherPopupMenu.kt b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherPopupMenu.kt
index 8963547..754a934 100644
--- a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherPopupMenu.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherPopupMenu.kt
@@ -42,7 +42,7 @@
setBackgroundDrawable(
res.getDrawable(R.drawable.bouncer_user_switcher_popup_bg, context.getTheme())
)
- setModal(true)
+ setModal(false)
setOverlapAnchor(true)
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
index ce7e4cf..76dfcb1 100644
--- a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
+++ b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
@@ -29,6 +29,9 @@
import java.util.Arrays;
+import javax.inject.Inject;
+
+// NOT Singleton. Started per-user.
public class NotificationChannels extends CoreStartable {
public static String ALERTS = "ALR";
public static String SCREENSHOTS_HEADSUP = "SCN_HEADSUP";
@@ -38,6 +41,7 @@
public static String TVPIP = TvPipNotificationController.NOTIFICATION_CHANNEL; // "TVPIP"
public static String HINTS = "HNT";
+ @Inject
public NotificationChannels(Context context) {
super(context);
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/condition/Condition.java b/packages/SystemUI/src/com/android/systemui/util/condition/Condition.java
index 0bbf56c..db35437e 100644
--- a/packages/SystemUI/src/com/android/systemui/util/condition/Condition.java
+++ b/packages/SystemUI/src/com/android/systemui/util/condition/Condition.java
@@ -36,6 +36,7 @@
private final ArrayList<WeakReference<Callback>> mCallbacks = new ArrayList<>();
private boolean mIsConditionMet = false;
private boolean mStarted = false;
+ private boolean mOverriding = false;
/**
* Starts monitoring the condition.
@@ -48,6 +49,21 @@
protected abstract void stop();
/**
+ * Sets whether this condition's value overrides others in determining the overall state.
+ */
+ public void setOverriding(boolean overriding) {
+ mOverriding = overriding;
+ updateCondition(mIsConditionMet);
+ }
+
+ /**
+ * Returns whether the current condition overrides
+ */
+ public boolean isOverridingCondition() {
+ return mOverriding;
+ }
+
+ /**
* Registers a callback to receive updates once started. This should be called before
* {@link #start()}. Also triggers the callback immediately if already started.
*/
@@ -57,7 +73,7 @@
mCallbacks.add(new WeakReference<>(callback));
if (mStarted) {
- callback.onConditionChanged(this, mIsConditionMet);
+ callback.onConditionChanged(this);
return;
}
@@ -107,11 +123,15 @@
if (cb == null) {
iterator.remove();
} else {
- cb.onConditionChanged(this, mIsConditionMet);
+ cb.onConditionChanged(this);
}
}
}
+ public boolean isConditionMet() {
+ return mIsConditionMet;
+ }
+
private boolean shouldLog() {
return Log.isLoggable(mTag, Log.DEBUG);
}
@@ -124,8 +144,7 @@
* Called when the fulfillment of the condition changes.
*
* @param condition The condition in question.
- * @param isConditionMet True if the condition has been fulfilled. False otherwise.
*/
- void onConditionChanged(Condition condition, boolean isConditionMet);
+ void onConditionChanged(Condition condition);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/condition/Monitor.java b/packages/SystemUI/src/com/android/systemui/util/condition/Monitor.java
index 8b6e982..d3c6e9a 100644
--- a/packages/SystemUI/src/com/android/systemui/util/condition/Monitor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/condition/Monitor.java
@@ -18,15 +18,17 @@
import android.util.Log;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.statusbar.policy.CallbackController;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Collection;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.stream.Collectors;
import javax.inject.Inject;
@@ -41,9 +43,7 @@
// Set of all conditions that need to be monitored.
private final Set<Condition> mConditions;
-
- // Map of values of each condition.
- private final HashMap<Condition, Boolean> mConditionsMap = new HashMap<>();
+ private final Executor mExecutor;
// Whether all conditions have been met.
private boolean mAllConditionsMet = false;
@@ -52,10 +52,43 @@
private boolean mHaveConditionsStarted = false;
// Callback for when each condition has been updated.
- private final Condition.Callback mConditionCallback = (condition, isConditionMet) -> {
- mConditionsMap.put(condition, isConditionMet);
+ private final Condition.Callback mConditionCallback = new Condition.Callback() {
+ @Override
+ public void onConditionChanged(Condition condition) {
+ mExecutor.execute(() -> updateConditionMetState());
+ }
+ };
- final boolean newAllConditionsMet = !mConditionsMap.containsValue(false);
+ @Inject
+ public Monitor(Executor executor, Set<Condition> conditions, Set<Callback> callbacks) {
+ mConditions = new HashSet<>();
+ mExecutor = executor;
+
+ if (conditions != null) {
+ mConditions.addAll(conditions);
+ }
+
+ if (callbacks == null) {
+ return;
+ }
+
+ for (Callback callback : callbacks) {
+ addCallbackLocked(callback);
+ }
+ }
+
+ private void updateConditionMetState() {
+ // Overriding conditions do not override each other
+ final Collection<Condition> overridingConditions = mConditions.stream()
+ .filter(Condition::isOverridingCondition).collect(Collectors.toSet());
+
+ final Collection<Condition> targetCollection = overridingConditions.isEmpty()
+ ? mConditions : overridingConditions;
+
+ final boolean newAllConditionsMet = targetCollection.isEmpty() ? true : targetCollection
+ .stream()
+ .map(Condition::isConditionMet)
+ .allMatch(conditionMet -> conditionMet);
if (newAllConditionsMet == mAllConditionsMet) {
return;
@@ -74,32 +107,48 @@
callback.onConditionsChanged(mAllConditionsMet);
}
}
- };
-
- @Inject
- public Monitor(Set<Condition> conditions, Set<Callback> callbacks) {
- mConditions = conditions;
-
- // If there is no condition, give green pass.
- if (mConditions.isEmpty()) {
- mAllConditionsMet = true;
- return;
- }
-
- // Initializes the conditions map and registers a callback for each condition.
- mConditions.forEach((condition -> mConditionsMap.put(condition, false)));
-
- if (callbacks == null) {
- return;
- }
-
- for (Callback callback : callbacks) {
- addCallback(callback);
- }
}
- @Override
- public void addCallback(@NotNull Callback callback) {
+ private void addConditionLocked(@NotNull Condition condition) {
+ mConditions.add(condition);
+
+ if (!mHaveConditionsStarted) {
+ return;
+ }
+
+ condition.addCallback(mConditionCallback);
+ updateConditionMetState();
+ }
+
+ /**
+ * Adds a condition for the monitor to listen to and consider when determining whether the
+ * overall condition state is met.
+ */
+ public void addCondition(@NotNull Condition condition) {
+ mExecutor.execute(() -> addConditionLocked(condition));
+ }
+
+ /**
+ * Removes a condition from further consideration.
+ */
+ public void removeCondition(@NotNull Condition condition) {
+ mExecutor.execute(() -> {
+ mConditions.remove(condition);
+
+ if (!mHaveConditionsStarted) {
+ return;
+ }
+
+ condition.removeCallback(mConditionCallback);
+ updateConditionMetState();
+ });
+ }
+
+ private void addCallbackLocked(@NotNull Callback callback) {
+ if (mCallbacks.contains(callback)) {
+ return;
+ }
+
if (shouldLog()) Log.d(mTag, "adding callback");
mCallbacks.add(callback);
@@ -109,36 +158,36 @@
if (!mHaveConditionsStarted) {
if (shouldLog()) Log.d(mTag, "starting all conditions");
mConditions.forEach(condition -> condition.addCallback(mConditionCallback));
+ updateConditionMetState();
mHaveConditionsStarted = true;
}
}
@Override
- public void removeCallback(@NotNull Callback callback) {
- if (shouldLog()) Log.d(mTag, "removing callback");
- final Iterator<Callback> iterator = mCallbacks.iterator();
- while (iterator.hasNext()) {
- final Callback cb = iterator.next();
- if (cb == null || cb == callback) {
- iterator.remove();
- }
- }
-
- if (mCallbacks.isEmpty() && mHaveConditionsStarted) {
- if (shouldLog()) Log.d(mTag, "stopping all conditions");
- mConditions.forEach(condition -> condition.removeCallback(mConditionCallback));
-
- mAllConditionsMet = false;
- mHaveConditionsStarted = false;
- }
+ public void addCallback(@NotNull Callback callback) {
+ mExecutor.execute(() -> addCallbackLocked(callback));
}
- /**
- * Force updates each condition to the value provided.
- */
- @VisibleForTesting
- public void overrideAllConditionsMet(boolean value) {
- mConditions.forEach(condition -> condition.updateCondition(value));
+ @Override
+ public void removeCallback(@NotNull Callback callback) {
+ mExecutor.execute(() -> {
+ if (shouldLog()) Log.d(mTag, "removing callback");
+ final Iterator<Callback> iterator = mCallbacks.iterator();
+ while (iterator.hasNext()) {
+ final Callback cb = iterator.next();
+ if (cb == null || cb == callback) {
+ iterator.remove();
+ }
+ }
+
+ if (mCallbacks.isEmpty() && mHaveConditionsStarted) {
+ if (shouldLog()) Log.d(mTag, "stopping all conditions");
+ mConditions.forEach(condition -> condition.removeCallback(mConditionCallback));
+
+ mAllConditionsMet = false;
+ mHaveConditionsStarted = false;
+ }
+ });
}
private boolean shouldLog() {
diff --git a/packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt b/packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt
index b64d7be..d8de07d 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt
@@ -21,6 +21,7 @@
import com.android.internal.view.RotationPolicy
import com.android.internal.view.RotationPolicy.RotationPolicyListener
import com.android.systemui.util.settings.SecureSettings
+import com.android.systemui.util.traceSection
import javax.inject.Inject
/**
@@ -44,7 +45,9 @@
RotationPolicyWrapper {
override fun setRotationLock(enabled: Boolean) {
- RotationPolicy.setRotationLock(context, enabled)
+ traceSection("RotationPolicyWrapperImpl#setRotationLock") {
+ RotationPolicy.setRotationLock(context, enabled)
+ }
}
override fun setRotationLockAtAngle(enabled: Boolean, rotation: Int) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
index c083c14..955d616 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@@ -22,6 +22,7 @@
import android.content.res.Configuration;
import android.media.VolumePolicy;
import android.os.Bundle;
+import android.provider.Settings;
import android.view.WindowManager.LayoutParams;
import com.android.settingslib.applications.InterestingConfigChanges;
@@ -59,6 +60,11 @@
public static final boolean DEFAULT_VOLUME_UP_TO_EXIT_SILENT = false;
public static final boolean DEFAULT_DO_NOT_DISTURB_WHEN_SILENT = false;
+ private static final Intent ZEN_SETTINGS =
+ new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
+ private static final Intent ZEN_PRIORITY_SETTINGS =
+ new Intent(Settings.ACTION_ZEN_MODE_PRIORITY_SETTINGS);
+
protected final Context mContext;
private final VolumeDialogControllerImpl mController;
private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges(
@@ -191,12 +197,12 @@
private final VolumeDialogImpl.Callback mVolumeDialogCallback = new VolumeDialogImpl.Callback() {
@Override
public void onZenSettingsClicked() {
- startSettings(ZenModePanel.ZEN_SETTINGS);
+ startSettings(ZEN_SETTINGS);
}
@Override
public void onZenPrioritySettingsClicked() {
- startSettings(ZenModePanel.ZEN_PRIORITY_SETTINGS);
+ startSettings(ZEN_PRIORITY_SETTINGS);
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index 0cd4fb9..e69de29 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -1,1083 +0,0 @@
-/**
- * Copyright (C) 2014 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.volume;
-
-import android.animation.LayoutTransition;
-import android.animation.LayoutTransition.TransitionListener;
-import android.app.ActivityManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
-import android.content.res.Configuration;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.provider.Settings;
-import android.provider.Settings.Global;
-import android.service.notification.Condition;
-import android.service.notification.ZenModeConfig;
-import android.service.notification.ZenModeConfig.ZenRule;
-import android.text.TextUtils;
-import android.text.format.DateFormat;
-import android.text.format.DateUtils;
-import android.util.ArraySet;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.MathUtils;
-import android.util.Slog;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.CompoundButton;
-import android.widget.CompoundButton.OnCheckedChangeListener;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.RadioButton;
-import android.widget.RadioGroup;
-import android.widget.TextView;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.UiEventLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.Prefs;
-import com.android.systemui.R;
-import com.android.systemui.qs.QSDndEvent;
-import com.android.systemui.qs.QSEvents;
-import com.android.systemui.statusbar.policy.ZenModeController;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.GregorianCalendar;
-import java.util.Locale;
-import java.util.Objects;
-
-public class ZenModePanel extends FrameLayout {
- private static final String TAG = "ZenModePanel";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
- public static final int STATE_MODIFY = 0;
- public static final int STATE_AUTO_RULE = 1;
- public static final int STATE_OFF = 2;
-
- private static final int SECONDS_MS = 1000;
- private static final int MINUTES_MS = 60 * SECONDS_MS;
-
- private static final int[] MINUTE_BUCKETS = ZenModeConfig.MINUTE_BUCKETS;
- private static final int MIN_BUCKET_MINUTES = MINUTE_BUCKETS[0];
- private static final int MAX_BUCKET_MINUTES = MINUTE_BUCKETS[MINUTE_BUCKETS.length - 1];
- private static final int DEFAULT_BUCKET_INDEX = Arrays.binarySearch(MINUTE_BUCKETS, 60);
- private static final int FOREVER_CONDITION_INDEX = 0;
- private static final int COUNTDOWN_CONDITION_INDEX = 1;
- private static final int COUNTDOWN_ALARM_CONDITION_INDEX = 2;
- private static final int COUNTDOWN_CONDITION_COUNT = 2;
-
- public static final Intent ZEN_SETTINGS
- = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
- public static final Intent ZEN_PRIORITY_SETTINGS
- = new Intent(Settings.ACTION_ZEN_MODE_PRIORITY_SETTINGS);
-
- private static final long TRANSITION_DURATION = 300;
-
- private final Context mContext;
- protected final LayoutInflater mInflater;
- private final H mHandler = new H();
- private final ZenPrefs mPrefs;
- private final TransitionHelper mTransitionHelper = new TransitionHelper();
- private final Uri mForeverId;
- private final ConfigurableTexts mConfigurableTexts;
- private final UiEventLogger mUiEventLogger = QSEvents.INSTANCE.getQsUiEventsLogger();
-
- private String mTag = TAG + "/" + Integer.toHexString(System.identityHashCode(this));
-
- protected SegmentedButtons mZenButtons;
- private View mZenIntroduction;
- private TextView mZenIntroductionMessage;
- private View mZenIntroductionConfirm;
- private TextView mZenIntroductionCustomize;
- protected LinearLayout mZenConditions;
- private TextView mZenAlarmWarning;
- private RadioGroup mZenRadioGroup;
- private LinearLayout mZenRadioGroupContent;
-
- private Callback mCallback;
- private ZenModeController mController;
- private Condition mExitCondition;
- private int mBucketIndex = -1;
- private boolean mExpanded;
- private boolean mHidden;
- private int mSessionZen;
- private int mAttachedZen;
- private boolean mAttached;
- private Condition mSessionExitCondition;
- private boolean mVoiceCapable;
-
- protected int mZenModeConditionLayoutId;
- protected int mZenModeButtonLayoutId;
- private View mEmpty;
- private TextView mEmptyText;
- private ImageView mEmptyIcon;
- private View mAutoRule;
- private TextView mAutoTitle;
- private int mState = STATE_MODIFY;
- private ViewGroup mEdit;
-
- public ZenModePanel(Context context, AttributeSet attrs) {
- super(context, attrs);
- mContext = context;
- mPrefs = new ZenPrefs();
- mInflater = LayoutInflater.from(mContext);
- mForeverId = Condition.newId(mContext).appendPath("forever").build();
- mConfigurableTexts = new ConfigurableTexts(mContext);
- mVoiceCapable = Util.isVoiceCapable(mContext);
- mZenModeConditionLayoutId = R.layout.zen_mode_condition;
- mZenModeButtonLayoutId = R.layout.zen_mode_button;
- if (DEBUG) Log.d(mTag, "new ZenModePanel");
- }
-
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("ZenModePanel state:");
- pw.print(" mAttached="); pw.println(mAttached);
- pw.print(" mHidden="); pw.println(mHidden);
- pw.print(" mExpanded="); pw.println(mExpanded);
- pw.print(" mSessionZen="); pw.println(mSessionZen);
- pw.print(" mAttachedZen="); pw.println(mAttachedZen);
- pw.print(" mConfirmedPriorityIntroduction=");
- pw.println(mPrefs.mConfirmedPriorityIntroduction);
- pw.print(" mConfirmedSilenceIntroduction=");
- pw.println(mPrefs.mConfirmedSilenceIntroduction);
- pw.print(" mVoiceCapable="); pw.println(mVoiceCapable);
- mTransitionHelper.dump(fd, pw, args);
- }
-
- protected void createZenButtons() {
- mZenButtons = findViewById(R.id.zen_buttons);
- mZenButtons.addButton(R.string.interruption_level_none_twoline,
- R.string.interruption_level_none_with_warning,
- Global.ZEN_MODE_NO_INTERRUPTIONS);
- mZenButtons.addButton(R.string.interruption_level_alarms_twoline,
- R.string.interruption_level_alarms,
- Global.ZEN_MODE_ALARMS);
- mZenButtons.addButton(R.string.interruption_level_priority_twoline,
- R.string.interruption_level_priority,
- Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
- mZenButtons.setCallback(mZenButtonsCallback);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- createZenButtons();
- mZenIntroduction = findViewById(R.id.zen_introduction);
- mZenIntroductionMessage = findViewById(R.id.zen_introduction_message);
- mZenIntroductionConfirm = findViewById(R.id.zen_introduction_confirm);
- mZenIntroductionConfirm.setOnClickListener(v -> confirmZenIntroduction());
- mZenIntroductionCustomize = findViewById(R.id.zen_introduction_customize);
- mZenIntroductionCustomize.setOnClickListener(v -> {
- confirmZenIntroduction();
- if (mCallback != null) {
- mCallback.onPrioritySettings();
- }
- });
- mConfigurableTexts.add(mZenIntroductionCustomize, R.string.zen_priority_customize_button);
-
- mZenConditions = findViewById(R.id.zen_conditions);
- mZenAlarmWarning = findViewById(R.id.zen_alarm_warning);
- mZenRadioGroup = findViewById(R.id.zen_radio_buttons);
- mZenRadioGroupContent = findViewById(R.id.zen_radio_buttons_content);
-
- mEdit = findViewById(R.id.edit_container);
-
- mEmpty = findViewById(android.R.id.empty);
- mEmpty.setVisibility(INVISIBLE);
- mEmptyText = mEmpty.findViewById(android.R.id.title);
- mEmptyIcon = mEmpty.findViewById(android.R.id.icon);
-
- mAutoRule = findViewById(R.id.auto_rule);
- mAutoTitle = mAutoRule.findViewById(android.R.id.title);
- mAutoRule.setVisibility(INVISIBLE);
- }
-
- public void setEmptyState(int icon, int text) {
- mEmptyIcon.post(() -> {
- mEmptyIcon.setImageResource(icon);
- mEmptyText.setText(text);
- });
- }
-
- public void setAutoText(CharSequence text) {
- mAutoTitle.post(() -> mAutoTitle.setText(text));
- }
-
- public void setState(int state) {
- if (mState == state) return;
- transitionFrom(getView(mState), getView(state));
- mState = state;
- }
-
- private void transitionFrom(View from, View to) {
- from.post(() -> {
- // TODO: Better transitions
- to.setAlpha(0);
- to.setVisibility(VISIBLE);
- to.bringToFront();
- to.animate().cancel();
- to.animate().alpha(1)
- .setDuration(TRANSITION_DURATION)
- .withEndAction(() -> from.setVisibility(INVISIBLE))
- .start();
- });
- }
-
- private View getView(int state) {
- switch (state) {
- case STATE_AUTO_RULE:
- return mAutoRule;
- case STATE_OFF:
- return mEmpty;
- default:
- return mEdit;
- }
- }
-
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- mConfigurableTexts.update();
- if (mZenButtons != null) {
- mZenButtons.update();
- }
- }
-
- private void confirmZenIntroduction() {
- final String prefKey = prefKeyForConfirmation(getSelectedZen(Global.ZEN_MODE_OFF));
- if (prefKey == null) return;
- if (DEBUG) Log.d(TAG, "confirmZenIntroduction " + prefKey);
- Prefs.putBoolean(mContext, prefKey, true);
- mHandler.sendEmptyMessage(H.UPDATE_WIDGETS);
- }
-
- private static String prefKeyForConfirmation(int zen) {
- switch (zen) {
- case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
- return Prefs.Key.DND_CONFIRMED_PRIORITY_INTRODUCTION;
- case Global.ZEN_MODE_NO_INTERRUPTIONS:
- return Prefs.Key.DND_CONFIRMED_SILENCE_INTRODUCTION;
- case Global.ZEN_MODE_ALARMS:
- return Prefs.Key.DND_CONFIRMED_ALARM_INTRODUCTION;
- default:
- return null;
- }
- }
-
- private void onAttach() {
- setExpanded(true);
- mAttachedZen = mController.getZen();
- ZenRule manualRule = mController.getManualRule();
- mExitCondition = manualRule != null ? manualRule.condition : null;
- if (DEBUG) Log.d(mTag, "onAttach " + mAttachedZen + " " + manualRule);
- handleUpdateManualRule(manualRule);
- mZenButtons.setSelectedValue(mAttachedZen, false);
- mSessionZen = mAttachedZen;
- mTransitionHelper.clear();
- mController.addCallback(mZenCallback);
- setSessionExitCondition(copy(mExitCondition));
- updateWidgets();
- setAttached(true);
- }
-
- private void onDetach() {
- if (DEBUG) Log.d(mTag, "onDetach");
- setExpanded(false);
- checkForAttachedZenChange();
- setAttached(false);
- mAttachedZen = -1;
- mSessionZen = -1;
- mController.removeCallback(mZenCallback);
- setSessionExitCondition(null);
- mTransitionHelper.clear();
- }
-
- @VisibleForTesting
- void setAttached(boolean attached) {
- mAttached = attached;
- }
-
- @Override
- public void onVisibilityAggregated(boolean isVisible) {
- super.onVisibilityAggregated(isVisible);
- if (isVisible == mAttached) return;
- if (isVisible) {
- onAttach();
- } else {
- onDetach();
- }
- }
-
- private void setSessionExitCondition(Condition condition) {
- if (Objects.equals(condition, mSessionExitCondition)) return;
- if (DEBUG) Log.d(mTag, "mSessionExitCondition=" + getConditionId(condition));
- mSessionExitCondition = condition;
- }
-
- public void setHidden(boolean hidden) {
- if (mHidden == hidden) return;
- if (DEBUG) Log.d(mTag, "hidden=" + hidden);
- mHidden = hidden;
- updateWidgets();
- }
-
- private void checkForAttachedZenChange() {
- final int selectedZen = getSelectedZen(-1);
- if (DEBUG) Log.d(mTag, "selectedZen=" + selectedZen);
- if (selectedZen != mAttachedZen) {
- if (DEBUG) Log.d(mTag, "attachedZen: " + mAttachedZen + " -> " + selectedZen);
- if (selectedZen == Global.ZEN_MODE_NO_INTERRUPTIONS) {
- mPrefs.trackNoneSelected();
- }
- }
- }
-
- private void setExpanded(boolean expanded) {
- if (expanded == mExpanded) return;
- if (DEBUG) Log.d(mTag, "setExpanded " + expanded);
- mExpanded = expanded;
- updateWidgets();
- fireExpanded();
- }
-
- protected void addZenConditions(int count) {
- for (int i = 0; i < count; i++) {
- final View rb = mInflater.inflate(mZenModeButtonLayoutId, mEdit, false);
- rb.setId(i);
- mZenRadioGroup.addView(rb);
- final View rbc = mInflater.inflate(mZenModeConditionLayoutId, mEdit, false);
- rbc.setId(i + count);
- mZenRadioGroupContent.addView(rbc);
- }
- }
-
- public void init(ZenModeController controller) {
- mController = controller;
- final int minConditions = 1 /*forever*/ + COUNTDOWN_CONDITION_COUNT;
- addZenConditions(minConditions);
- mSessionZen = getSelectedZen(-1);
- handleUpdateManualRule(mController.getManualRule());
- if (DEBUG) Log.d(mTag, "init mExitCondition=" + mExitCondition);
- hideAllConditions();
- }
-
- private void setExitCondition(Condition exitCondition) {
- if (Objects.equals(mExitCondition, exitCondition)) return;
- mExitCondition = exitCondition;
- if (DEBUG) Log.d(mTag, "mExitCondition=" + getConditionId(mExitCondition));
- updateWidgets();
- }
-
- private static Uri getConditionId(Condition condition) {
- return condition != null ? condition.id : null;
- }
-
- private Uri getRealConditionId(Condition condition) {
- return isForever(condition) ? null : getConditionId(condition);
- }
-
- private static Condition copy(Condition condition) {
- return condition == null ? null : condition.copy();
- }
-
- public void setCallback(Callback callback) {
- mCallback = callback;
- }
-
- @VisibleForTesting
- void handleUpdateManualRule(ZenRule rule) {
- final int zen = rule != null ? rule.zenMode : Global.ZEN_MODE_OFF;
- handleUpdateZen(zen);
- final Condition c = rule == null ? null
- : rule.condition != null ? rule.condition
- : createCondition(rule.conditionId);
- handleUpdateConditions(c);
- setExitCondition(c);
- }
-
- private Condition createCondition(Uri conditionId) {
- if (ZenModeConfig.isValidCountdownToAlarmConditionId(conditionId)) {
- long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
- Condition c = ZenModeConfig.toNextAlarmCondition(
- mContext, time, ActivityManager.getCurrentUser());
- return c;
- } else if (ZenModeConfig.isValidCountdownConditionId(conditionId)) {
- long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
- int mins = (int) ((time - System.currentTimeMillis() + DateUtils.MINUTE_IN_MILLIS / 2)
- / DateUtils.MINUTE_IN_MILLIS);
- Condition c = ZenModeConfig.toTimeCondition(mContext, time, mins,
- ActivityManager.getCurrentUser(), false);
- return c;
- }
- // If there is a manual rule, but it has no condition listed then it is forever.
- return forever();
- }
-
- private void handleUpdateZen(int zen) {
- if (mSessionZen != -1 && mSessionZen != zen) {
- mSessionZen = zen;
- }
- mZenButtons.setSelectedValue(zen, false /* fromClick */);
- updateWidgets();
- }
-
- @VisibleForTesting
- int getSelectedZen(int defValue) {
- final Object zen = mZenButtons.getSelectedValue();
- return zen != null ? (Integer) zen : defValue;
- }
-
- private void updateWidgets() {
- if (mTransitionHelper.isTransitioning()) {
- mTransitionHelper.pendingUpdateWidgets();
- return;
- }
- final int zen = getSelectedZen(Global.ZEN_MODE_OFF);
- final boolean zenImportant = zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
- final boolean zenNone = zen == Global.ZEN_MODE_NO_INTERRUPTIONS;
- final boolean zenAlarm = zen == Global.ZEN_MODE_ALARMS;
- final boolean introduction = (zenImportant && !mPrefs.mConfirmedPriorityIntroduction
- || zenNone && !mPrefs.mConfirmedSilenceIntroduction
- || zenAlarm && !mPrefs.mConfirmedAlarmIntroduction);
-
- mZenButtons.setVisibility(mHidden ? GONE : VISIBLE);
- mZenIntroduction.setVisibility(introduction ? VISIBLE : GONE);
- if (introduction) {
- int message = zenImportant
- ? R.string.zen_priority_introduction
- : zenAlarm
- ? R.string.zen_alarms_introduction
- : mVoiceCapable
- ? R.string.zen_silence_introduction_voice
- : R.string.zen_silence_introduction;
- mConfigurableTexts.add(mZenIntroductionMessage, message);
- mConfigurableTexts.update();
- mZenIntroductionCustomize.setVisibility(zenImportant ? VISIBLE : GONE);
- }
- final String warning = computeAlarmWarningText(zenNone);
- mZenAlarmWarning.setVisibility(warning != null ? VISIBLE : GONE);
- mZenAlarmWarning.setText(warning);
- }
-
- private String computeAlarmWarningText(boolean zenNone) {
- if (!zenNone) {
- return null;
- }
- final long now = System.currentTimeMillis();
- final long nextAlarm = mController.getNextAlarm();
- if (nextAlarm < now) {
- return null;
- }
- int warningRes = 0;
- if (mSessionExitCondition == null || isForever(mSessionExitCondition)) {
- warningRes = R.string.zen_alarm_warning_indef;
- } else {
- final long time = ZenModeConfig.tryParseCountdownConditionId(mSessionExitCondition.id);
- if (time > now && nextAlarm < time) {
- warningRes = R.string.zen_alarm_warning;
- }
- }
- if (warningRes == 0) {
- return null;
- }
- final boolean soon = (nextAlarm - now) < 24 * 60 * 60 * 1000;
- final boolean is24 = DateFormat.is24HourFormat(mContext, ActivityManager.getCurrentUser());
- final String skeleton = soon ? (is24 ? "Hm" : "hma") : (is24 ? "EEEHm" : "EEEhma");
- final String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton);
- final CharSequence formattedTime = DateFormat.format(pattern, nextAlarm);
- final int templateRes = soon ? R.string.alarm_template : R.string.alarm_template_far;
- final String template = getResources().getString(templateRes, formattedTime);
- return getResources().getString(warningRes, template);
- }
-
- @VisibleForTesting
- void handleUpdateConditions(Condition c) {
- if (mTransitionHelper.isTransitioning()) {
- return;
- }
- // forever
- bind(forever(), mZenRadioGroupContent.getChildAt(FOREVER_CONDITION_INDEX),
- FOREVER_CONDITION_INDEX);
- if (c == null) {
- bindGenericCountdown();
- bindNextAlarm(getTimeUntilNextAlarmCondition());
- } else if (isForever(c)) {
-
- getConditionTagAt(FOREVER_CONDITION_INDEX).rb.setChecked(true);
- bindGenericCountdown();
- bindNextAlarm(getTimeUntilNextAlarmCondition());
- } else {
- if (isAlarm(c)) {
- bindGenericCountdown();
- bindNextAlarm(c);
- getConditionTagAt(COUNTDOWN_ALARM_CONDITION_INDEX).rb.setChecked(true);
- } else if (isCountdown(c)) {
- bindNextAlarm(getTimeUntilNextAlarmCondition());
- bind(c, mZenRadioGroupContent.getChildAt(COUNTDOWN_CONDITION_INDEX),
- COUNTDOWN_CONDITION_INDEX);
- getConditionTagAt(COUNTDOWN_CONDITION_INDEX).rb.setChecked(true);
- } else {
- Slog.wtf(TAG, "Invalid manual condition: " + c);
- }
- }
- mZenConditions.setVisibility(mSessionZen != Global.ZEN_MODE_OFF ? View.VISIBLE : View.GONE);
- }
-
- private void bindGenericCountdown() {
- mBucketIndex = DEFAULT_BUCKET_INDEX;
- Condition countdown = ZenModeConfig.toTimeCondition(mContext,
- MINUTE_BUCKETS[mBucketIndex], ActivityManager.getCurrentUser());
- // don't change the hour condition while the user is viewing the panel
- if (!mAttached || getConditionTagAt(COUNTDOWN_CONDITION_INDEX).condition == null) {
- bind(countdown, mZenRadioGroupContent.getChildAt(COUNTDOWN_CONDITION_INDEX),
- COUNTDOWN_CONDITION_INDEX);
- }
- }
-
- private void bindNextAlarm(Condition c) {
- View alarmContent = mZenRadioGroupContent.getChildAt(COUNTDOWN_ALARM_CONDITION_INDEX);
- ConditionTag tag = (ConditionTag) alarmContent.getTag();
- // Don't change the alarm condition while the user is viewing the panel
- if (c != null && (!mAttached || tag == null || tag.condition == null)) {
- bind(c, alarmContent, COUNTDOWN_ALARM_CONDITION_INDEX);
- }
-
- tag = (ConditionTag) alarmContent.getTag();
- boolean showAlarm = tag != null && tag.condition != null;
- mZenRadioGroup.getChildAt(COUNTDOWN_ALARM_CONDITION_INDEX).setVisibility(
- showAlarm ? View.VISIBLE : View.INVISIBLE);
- alarmContent.setVisibility(showAlarm ? View.VISIBLE : View.INVISIBLE);
- }
-
- private Condition forever() {
- return new Condition(mForeverId, foreverSummary(mContext), "", "", 0 /*icon*/,
- Condition.STATE_TRUE, 0 /*flags*/);
- }
-
- private static String foreverSummary(Context context) {
- return context.getString(com.android.internal.R.string.zen_mode_forever);
- }
-
- // Returns a time condition if the next alarm is within the next week.
- private Condition getTimeUntilNextAlarmCondition() {
- GregorianCalendar weekRange = new GregorianCalendar();
- setToMidnight(weekRange);
- weekRange.add(Calendar.DATE, 6);
- final long nextAlarmMs = mController.getNextAlarm();
- if (nextAlarmMs > 0) {
- GregorianCalendar nextAlarm = new GregorianCalendar();
- nextAlarm.setTimeInMillis(nextAlarmMs);
- setToMidnight(nextAlarm);
-
- if (weekRange.compareTo(nextAlarm) >= 0) {
- return ZenModeConfig.toNextAlarmCondition(mContext, nextAlarmMs,
- ActivityManager.getCurrentUser());
- }
- }
- return null;
- }
-
- private void setToMidnight(Calendar calendar) {
- calendar.set(Calendar.HOUR_OF_DAY, 0);
- calendar.set(Calendar.MINUTE, 0);
- calendar.set(Calendar.SECOND, 0);
- calendar.set(Calendar.MILLISECOND, 0);
- }
-
- @VisibleForTesting
- ConditionTag getConditionTagAt(int index) {
- return (ConditionTag) mZenRadioGroupContent.getChildAt(index).getTag();
- }
-
- @VisibleForTesting
- int getVisibleConditions() {
- int rt = 0;
- final int N = mZenRadioGroupContent.getChildCount();
- for (int i = 0; i < N; i++) {
- rt += mZenRadioGroupContent.getChildAt(i).getVisibility() == VISIBLE ? 1 : 0;
- }
- return rt;
- }
-
- private void hideAllConditions() {
- final int N = mZenRadioGroupContent.getChildCount();
- for (int i = 0; i < N; i++) {
- mZenRadioGroupContent.getChildAt(i).setVisibility(GONE);
- }
- }
-
- private static boolean isAlarm(Condition c) {
- return c != null && ZenModeConfig.isValidCountdownToAlarmConditionId(c.id);
- }
-
- private static boolean isCountdown(Condition c) {
- return c != null && ZenModeConfig.isValidCountdownConditionId(c.id);
- }
-
- private boolean isForever(Condition c) {
- return c != null && mForeverId.equals(c.id);
- }
-
- private void bind(final Condition condition, final View row, final int rowId) {
- if (condition == null) throw new IllegalArgumentException("condition must not be null");
- final boolean enabled = condition.state == Condition.STATE_TRUE;
- final ConditionTag tag =
- row.getTag() != null ? (ConditionTag) row.getTag() : new ConditionTag();
- row.setTag(tag);
- final boolean first = tag.rb == null;
- if (tag.rb == null) {
- tag.rb = (RadioButton) mZenRadioGroup.getChildAt(rowId);
- }
- tag.condition = condition;
- final Uri conditionId = getConditionId(tag.condition);
- if (DEBUG) Log.d(mTag, "bind i=" + mZenRadioGroupContent.indexOfChild(row) + " first="
- + first + " condition=" + conditionId);
- tag.rb.setEnabled(enabled);
- tag.rb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- if (mExpanded && isChecked) {
- tag.rb.setChecked(true);
- if (DEBUG) Log.d(mTag, "onCheckedChanged " + conditionId);
- MetricsLogger.action(mContext, MetricsEvent.QS_DND_CONDITION_SELECT);
- mUiEventLogger.log(QSDndEvent.QS_DND_CONDITION_SELECT);
- select(tag.condition);
- announceConditionSelection(tag);
- }
- }
- });
-
- if (tag.lines == null) {
- tag.lines = row.findViewById(android.R.id.content);
- }
- if (tag.line1 == null) {
- tag.line1 = (TextView) row.findViewById(android.R.id.text1);
- mConfigurableTexts.add(tag.line1);
- }
- if (tag.line2 == null) {
- tag.line2 = (TextView) row.findViewById(android.R.id.text2);
- mConfigurableTexts.add(tag.line2);
- }
- final String line1 = !TextUtils.isEmpty(condition.line1) ? condition.line1
- : condition.summary;
- final String line2 = condition.line2;
- tag.line1.setText(line1);
- if (TextUtils.isEmpty(line2)) {
- tag.line2.setVisibility(GONE);
- } else {
- tag.line2.setVisibility(VISIBLE);
- tag.line2.setText(line2);
- }
- tag.lines.setEnabled(enabled);
- tag.lines.setAlpha(enabled ? 1 : .4f);
-
- final ImageView button1 = (ImageView) row.findViewById(android.R.id.button1);
- button1.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- onClickTimeButton(row, tag, false /*down*/, rowId);
- }
- });
-
- final ImageView button2 = (ImageView) row.findViewById(android.R.id.button2);
- button2.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- onClickTimeButton(row, tag, true /*up*/, rowId);
- }
- });
- tag.lines.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- tag.rb.setChecked(true);
- }
- });
-
- final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
- if (rowId != COUNTDOWN_ALARM_CONDITION_INDEX && time > 0) {
- button1.setVisibility(VISIBLE);
- button2.setVisibility(VISIBLE);
- if (mBucketIndex > -1) {
- button1.setEnabled(mBucketIndex > 0);
- button2.setEnabled(mBucketIndex < MINUTE_BUCKETS.length - 1);
- } else {
- final long span = time - System.currentTimeMillis();
- button1.setEnabled(span > MIN_BUCKET_MINUTES * MINUTES_MS);
- final Condition maxCondition = ZenModeConfig.toTimeCondition(mContext,
- MAX_BUCKET_MINUTES, ActivityManager.getCurrentUser());
- button2.setEnabled(!Objects.equals(condition.summary, maxCondition.summary));
- }
-
- button1.setAlpha(button1.isEnabled() ? 1f : .5f);
- button2.setAlpha(button2.isEnabled() ? 1f : .5f);
- } else {
- button1.setVisibility(GONE);
- button2.setVisibility(GONE);
- }
- // wire up interaction callbacks for newly-added condition rows
- if (first) {
- Interaction.register(tag.rb, mInteractionCallback);
- Interaction.register(tag.lines, mInteractionCallback);
- Interaction.register(button1, mInteractionCallback);
- Interaction.register(button2, mInteractionCallback);
- }
- row.setVisibility(VISIBLE);
- }
-
- private void announceConditionSelection(ConditionTag tag) {
- final int zen = getSelectedZen(Global.ZEN_MODE_OFF);
- String modeText;
- switch(zen) {
- case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
- modeText = mContext.getString(R.string.interruption_level_priority);
- break;
- case Global.ZEN_MODE_NO_INTERRUPTIONS:
- modeText = mContext.getString(R.string.interruption_level_none);
- break;
- case Global.ZEN_MODE_ALARMS:
- modeText = mContext.getString(R.string.interruption_level_alarms);
- break;
- default:
- return;
- }
- announceForAccessibility(mContext.getString(R.string.zen_mode_and_condition, modeText,
- tag.line1.getText()));
- }
-
- private void onClickTimeButton(View row, ConditionTag tag, boolean up, int rowId) {
- MetricsLogger.action(mContext, MetricsEvent.QS_DND_TIME, up);
- mUiEventLogger.log(up ? QSDndEvent.QS_DND_TIME_UP : QSDndEvent.QS_DND_TIME_DOWN);
- Condition newCondition = null;
- final int N = MINUTE_BUCKETS.length;
- if (mBucketIndex == -1) {
- // not on a known index, search for the next or prev bucket by time
- final Uri conditionId = getConditionId(tag.condition);
- final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
- final long now = System.currentTimeMillis();
- for (int i = 0; i < N; i++) {
- int j = up ? i : N - 1 - i;
- final int bucketMinutes = MINUTE_BUCKETS[j];
- final long bucketTime = now + bucketMinutes * MINUTES_MS;
- if (up && bucketTime > time || !up && bucketTime < time) {
- mBucketIndex = j;
- newCondition = ZenModeConfig.toTimeCondition(mContext,
- bucketTime, bucketMinutes, ActivityManager.getCurrentUser(),
- false /*shortVersion*/);
- break;
- }
- }
- if (newCondition == null) {
- mBucketIndex = DEFAULT_BUCKET_INDEX;
- newCondition = ZenModeConfig.toTimeCondition(mContext,
- MINUTE_BUCKETS[mBucketIndex], ActivityManager.getCurrentUser());
- }
- } else {
- // on a known index, simply increment or decrement
- mBucketIndex = Math.max(0, Math.min(N - 1, mBucketIndex + (up ? 1 : -1)));
- newCondition = ZenModeConfig.toTimeCondition(mContext,
- MINUTE_BUCKETS[mBucketIndex], ActivityManager.getCurrentUser());
- }
- bind(newCondition, row, rowId);
- tag.rb.setChecked(true);
- select(newCondition);
- announceConditionSelection(tag);
- }
-
- private void select(final Condition condition) {
- if (DEBUG) Log.d(mTag, "select " + condition);
- if (mSessionZen == -1 || mSessionZen == Global.ZEN_MODE_OFF) {
- if (DEBUG) Log.d(mTag, "Ignoring condition selection outside of manual zen");
- return;
- }
- final Uri realConditionId = getRealConditionId(condition);
- if (mController != null) {
- AsyncTask.execute(new Runnable() {
- @Override
- public void run() {
- mController.setZen(mSessionZen, realConditionId, TAG + ".selectCondition");
- }
- });
- }
- setExitCondition(condition);
- if (realConditionId == null) {
- mPrefs.setMinuteIndex(-1);
- } else if ((isAlarm(condition) || isCountdown(condition)) && mBucketIndex != -1) {
- mPrefs.setMinuteIndex(mBucketIndex);
- }
- setSessionExitCondition(copy(condition));
- }
-
- private void fireInteraction() {
- if (mCallback != null) {
- mCallback.onInteraction();
- }
- }
-
- private void fireExpanded() {
- if (mCallback != null) {
- mCallback.onExpanded(mExpanded);
- }
- }
-
- private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
- @Override
- public void onManualRuleChanged(ZenRule rule) {
- mHandler.obtainMessage(H.MANUAL_RULE_CHANGED, rule).sendToTarget();
- }
- };
-
- private final class H extends Handler {
- private static final int MANUAL_RULE_CHANGED = 2;
- private static final int UPDATE_WIDGETS = 3;
-
- private H() {
- super(Looper.getMainLooper());
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MANUAL_RULE_CHANGED: handleUpdateManualRule((ZenRule) msg.obj); break;
- case UPDATE_WIDGETS: updateWidgets(); break;
- }
- }
- }
-
- public interface Callback {
- void onPrioritySettings();
- void onInteraction();
- void onExpanded(boolean expanded);
- }
-
- // used as the view tag on condition rows
- @VisibleForTesting
- static class ConditionTag {
- RadioButton rb;
- View lines;
- TextView line1;
- TextView line2;
- Condition condition;
- }
-
- private final class ZenPrefs implements OnSharedPreferenceChangeListener {
- private final int mNoneDangerousThreshold;
-
- private int mMinuteIndex;
- private int mNoneSelected;
- private boolean mConfirmedPriorityIntroduction;
- private boolean mConfirmedSilenceIntroduction;
- private boolean mConfirmedAlarmIntroduction;
-
- private ZenPrefs() {
- mNoneDangerousThreshold = mContext.getResources()
- .getInteger(R.integer.zen_mode_alarm_warning_threshold);
- Prefs.registerListener(mContext, this);
- updateMinuteIndex();
- updateNoneSelected();
- updateConfirmedPriorityIntroduction();
- updateConfirmedSilenceIntroduction();
- updateConfirmedAlarmIntroduction();
- }
-
- public void trackNoneSelected() {
- mNoneSelected = clampNoneSelected(mNoneSelected + 1);
- if (DEBUG) Log.d(mTag, "Setting none selected: " + mNoneSelected + " threshold="
- + mNoneDangerousThreshold);
- Prefs.putInt(mContext, Prefs.Key.DND_NONE_SELECTED, mNoneSelected);
- }
-
- public int getMinuteIndex() {
- return mMinuteIndex;
- }
-
- public void setMinuteIndex(int minuteIndex) {
- minuteIndex = clampIndex(minuteIndex);
- if (minuteIndex == mMinuteIndex) return;
- mMinuteIndex = clampIndex(minuteIndex);
- if (DEBUG) Log.d(mTag, "Setting favorite minute index: " + mMinuteIndex);
- Prefs.putInt(mContext, Prefs.Key.DND_FAVORITE_BUCKET_INDEX, mMinuteIndex);
- }
-
- @Override
- public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
- updateMinuteIndex();
- updateNoneSelected();
- updateConfirmedPriorityIntroduction();
- updateConfirmedSilenceIntroduction();
- updateConfirmedAlarmIntroduction();
- }
-
- private void updateMinuteIndex() {
- mMinuteIndex = clampIndex(Prefs.getInt(mContext,
- Prefs.Key.DND_FAVORITE_BUCKET_INDEX, DEFAULT_BUCKET_INDEX));
- if (DEBUG) Log.d(mTag, "Favorite minute index: " + mMinuteIndex);
- }
-
- private int clampIndex(int index) {
- return MathUtils.constrain(index, -1, MINUTE_BUCKETS.length - 1);
- }
-
- private void updateNoneSelected() {
- mNoneSelected = clampNoneSelected(Prefs.getInt(mContext,
- Prefs.Key.DND_NONE_SELECTED, 0));
- if (DEBUG) Log.d(mTag, "None selected: " + mNoneSelected);
- }
-
- private int clampNoneSelected(int noneSelected) {
- return MathUtils.constrain(noneSelected, 0, Integer.MAX_VALUE);
- }
-
- private void updateConfirmedPriorityIntroduction() {
- final boolean confirmed = Prefs.getBoolean(mContext,
- Prefs.Key.DND_CONFIRMED_PRIORITY_INTRODUCTION, false);
- if (confirmed == mConfirmedPriorityIntroduction) return;
- mConfirmedPriorityIntroduction = confirmed;
- if (DEBUG) Log.d(mTag, "Confirmed priority introduction: "
- + mConfirmedPriorityIntroduction);
- }
-
- private void updateConfirmedSilenceIntroduction() {
- final boolean confirmed = Prefs.getBoolean(mContext,
- Prefs.Key.DND_CONFIRMED_SILENCE_INTRODUCTION, false);
- if (confirmed == mConfirmedSilenceIntroduction) return;
- mConfirmedSilenceIntroduction = confirmed;
- if (DEBUG) Log.d(mTag, "Confirmed silence introduction: "
- + mConfirmedSilenceIntroduction);
- }
-
- private void updateConfirmedAlarmIntroduction() {
- final boolean confirmed = Prefs.getBoolean(mContext,
- Prefs.Key.DND_CONFIRMED_ALARM_INTRODUCTION, false);
- if (confirmed == mConfirmedAlarmIntroduction) return;
- mConfirmedAlarmIntroduction = confirmed;
- if (DEBUG) Log.d(mTag, "Confirmed alarm introduction: "
- + mConfirmedAlarmIntroduction);
- }
- }
-
- protected final SegmentedButtons.Callback mZenButtonsCallback = new SegmentedButtons.Callback() {
- @Override
- public void onSelected(final Object value, boolean fromClick) {
- if (value != null && mZenButtons.isShown() && isAttachedToWindow()) {
- final int zen = (Integer) value;
- if (fromClick) {
- MetricsLogger.action(mContext, MetricsEvent.QS_DND_ZEN_SELECT, zen);
- }
- if (DEBUG) Log.d(mTag, "mZenButtonsCallback selected=" + zen);
- final Uri realConditionId = getRealConditionId(mSessionExitCondition);
- AsyncTask.execute(new Runnable() {
- @Override
- public void run() {
- mController.setZen(zen, realConditionId, TAG + ".selectZen");
- if (zen != Global.ZEN_MODE_OFF) {
- Prefs.putInt(mContext, Prefs.Key.DND_FAVORITE_ZEN, zen);
- }
- }
- });
- }
- }
-
- @Override
- public void onInteraction() {
- fireInteraction();
- }
- };
-
- private final Interaction.Callback mInteractionCallback = new Interaction.Callback() {
- @Override
- public void onInteraction() {
- fireInteraction();
- }
- };
-
- private final class TransitionHelper implements TransitionListener, Runnable {
- private final ArraySet<View> mTransitioningViews = new ArraySet<View>();
-
- private boolean mTransitioning;
- private boolean mPendingUpdateWidgets;
-
- public void clear() {
- mTransitioningViews.clear();
- mPendingUpdateWidgets = false;
- }
-
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println(" TransitionHelper state:");
- pw.print(" mPendingUpdateWidgets="); pw.println(mPendingUpdateWidgets);
- pw.print(" mTransitioning="); pw.println(mTransitioning);
- pw.print(" mTransitioningViews="); pw.println(mTransitioningViews);
- }
-
- public void pendingUpdateWidgets() {
- mPendingUpdateWidgets = true;
- }
-
- public boolean isTransitioning() {
- return !mTransitioningViews.isEmpty();
- }
-
- @Override
- public void startTransition(LayoutTransition transition,
- ViewGroup container, View view, int transitionType) {
- mTransitioningViews.add(view);
- updateTransitioning();
- }
-
- @Override
- public void endTransition(LayoutTransition transition,
- ViewGroup container, View view, int transitionType) {
- mTransitioningViews.remove(view);
- updateTransitioning();
- }
-
- @Override
- public void run() {
- if (DEBUG) Log.d(mTag, "TransitionHelper run"
- + " mPendingUpdateWidgets=" + mPendingUpdateWidgets);
- if (mPendingUpdateWidgets) {
- updateWidgets();
- }
- mPendingUpdateWidgets = false;
- }
-
- private void updateTransitioning() {
- final boolean transitioning = isTransitioning();
- if (mTransitioning == transitioning) return;
- mTransitioning = transitioning;
- if (DEBUG) Log.d(mTag, "TransitionHelper mTransitioning=" + mTransitioning);
- if (!mTransitioning) {
- if (mPendingUpdateWidgets) {
- mHandler.post(this);
- } else {
- mPendingUpdateWidgets = false;
- }
- }
- }
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index 24b01e0..6736bfd 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -307,7 +307,8 @@
UserInfo info = new UserInfo(i /* id */, "Name: " + i, null /* iconPath */,
0 /* flags */);
users.add(new UserRecord(info, null, false /* isGuest */, false /* isCurrent */,
- false /* isAddUser */, false /* isRestricted */, true /* isSwitchToEnabled */));
+ false /* isAddUser */, false /* isRestricted */, true /* isSwitchToEnabled */,
+ false /* isAddSupervisedUser */));
}
return users;
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java
index 9f8f6c1..06082b6 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java
@@ -32,6 +32,7 @@
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.tuner.TunerService;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -66,6 +67,11 @@
mController.setupUri(KeyguardSliceProvider.KEYGUARD_SLICE_URI);
}
+ @After
+ public void tearDown() {
+ mController.onViewDetached();
+ }
+
@Test
public void refresh_replacesSliceContentAndNotifiesListener() {
mController.refresh();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 08d881f..f71dd24 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -32,7 +32,6 @@
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -58,7 +57,6 @@
import android.hardware.face.FaceSensorProperties;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.fingerprint.FingerprintManager;
-import android.media.AudioManager;
import android.nfc.NfcAdapter;
import android.os.Bundle;
import android.os.Handler;
@@ -74,9 +72,6 @@
import android.testing.TestableContext;
import android.testing.TestableLooper;
-import androidx.lifecycle.LiveData;
-import androidx.lifecycle.Observer;
-
import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.telephony.TelephonyIntents;
@@ -92,7 +87,6 @@
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.telephony.TelephonyListenerManager;
-import com.android.systemui.util.RingerModeTracker;
import org.junit.After;
import org.junit.Assert;
@@ -101,7 +95,6 @@
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
-import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.MockitoSession;
@@ -161,10 +154,6 @@
@Mock
private TelephonyManager mTelephonyManager;
@Mock
- private RingerModeTracker mRingerModeTracker;
- @Mock
- private LiveData<Integer> mRingerModeLiveData;
- @Mock
private StatusBarStateController mStatusBarStateController;
@Mock
private AuthController mAuthController;
@@ -242,8 +231,6 @@
mSpiedContext.addMockSystemService(SubscriptionManager.class, mSubscriptionManager);
mSpiedContext.addMockSystemService(TelephonyManager.class, mTelephonyManager);
- when(mRingerModeTracker.getRingerMode()).thenReturn(mRingerModeLiveData);
-
mMockitoSession = ExtendedMockito.mockitoSession()
.spyStatic(SubscriptionManager.class).startMocking();
ExtendedMockito.doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
@@ -866,29 +853,6 @@
}
@Test
- public void testRingerModeChange() {
- ArgumentCaptor<Observer<Integer>> captor = ArgumentCaptor.forClass(Observer.class);
- verify(mRingerModeLiveData).observeForever(captor.capture());
- Observer<Integer> observer = captor.getValue();
-
- KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class);
-
- mKeyguardUpdateMonitor.registerCallback(callback);
-
- observer.onChanged(AudioManager.RINGER_MODE_NORMAL);
- observer.onChanged(AudioManager.RINGER_MODE_SILENT);
- observer.onChanged(AudioManager.RINGER_MODE_VIBRATE);
-
- mTestableLooper.processAllMessages();
-
- InOrder orderVerify = inOrder(callback);
- orderVerify.verify(callback).onRingerModeChanged(anyInt()); // Initial update on register
- orderVerify.verify(callback).onRingerModeChanged(AudioManager.RINGER_MODE_NORMAL);
- orderVerify.verify(callback).onRingerModeChanged(AudioManager.RINGER_MODE_SILENT);
- orderVerify.verify(callback).onRingerModeChanged(AudioManager.RINGER_MODE_VIBRATE);
- }
-
- @Test
public void testRegisterAuthControllerCallback() {
assertThat(mKeyguardUpdateMonitor.isUdfpsEnrolled()).isFalse();
@@ -1120,7 +1084,7 @@
super(context,
TestableLooper.get(KeyguardUpdateMonitorTest.this).getLooper(),
mBroadcastDispatcher, mDumpManager,
- mRingerModeTracker, mBackgroundExecutor, mMainExecutor,
+ mBackgroundExecutor, mMainExecutor,
mStatusBarStateController, mLockPatternUtils,
mAuthController, mTelephonyListenerManager,
mInteractionJankMonitor, mLatencyTracker);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/DisplayCutoutBaseViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/DisplayCutoutBaseViewTest.kt
new file mode 100644
index 0000000..e62b4e6
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/DisplayCutoutBaseViewTest.kt
@@ -0,0 +1,161 @@
+/*
+ * 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.systemui
+
+import android.graphics.Canvas
+import android.graphics.Insets
+import android.graphics.Path
+import android.graphics.Rect
+import android.graphics.RectF
+import android.graphics.Region
+import android.testing.AndroidTestingRunner
+import android.view.Display
+import android.view.DisplayCutout
+import android.view.DisplayInfo
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito.never
+import com.android.internal.R
+import com.android.systemui.util.mockito.eq
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.`when` as whenever
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class DisplayCutoutBaseViewTest : SysuiTestCase() {
+
+ @Mock private lateinit var mockCanvas: Canvas
+ @Mock private lateinit var mockRootView: View
+ @Mock private lateinit var mockDisplay: Display
+
+ private lateinit var cutoutBaseView: DisplayCutoutBaseView
+ private val cutout: DisplayCutout = DisplayCutout.Builder()
+ .setSafeInsets(Insets.of(0, 2, 0, 0))
+ .setBoundingRectTop(Rect(1, 0, 2, 2))
+ .build()
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ }
+
+ @Test
+ fun testBoundingRectsToRegion() {
+ setupDisplayCutoutBaseView(true /* fillCutout */, true /* hasCutout */)
+ val rect = Rect(1, 2, 3, 4)
+ assertThat(cutoutBaseView.rectsToRegion(listOf(rect)).bounds).isEqualTo(rect)
+ }
+
+ @Test
+ fun testDrawCutout_fillCutout() {
+ setupDisplayCutoutBaseView(true /* fillCutout */, true /* hasCutout */)
+ cutoutBaseView.onDraw(mockCanvas)
+
+ verify(cutoutBaseView).drawCutouts(mockCanvas)
+ }
+
+ @Test
+ fun testDrawCutout_notFillCutout() {
+ setupDisplayCutoutBaseView(false /* fillCutout */, true /* hasCutout */)
+ cutoutBaseView.onDraw(mockCanvas)
+
+ verify(cutoutBaseView, never()).drawCutouts(mockCanvas)
+ }
+
+ @Test
+ fun testShouldInterceptTouch_hasCutout() {
+ setupDisplayCutoutBaseView(true /* fillCutout */, true /* hasCutout */)
+ cutoutBaseView.updateCutout()
+
+ assertThat(cutoutBaseView.shouldInterceptTouch()).isTrue()
+ }
+
+ @Test
+ fun testShouldInterceptTouch_noCutout() {
+ setupDisplayCutoutBaseView(true /* fillCutout */, false /* hasCutout */)
+ cutoutBaseView.updateCutout()
+
+ assertThat(cutoutBaseView.shouldInterceptTouch()).isFalse()
+ }
+
+ @Test
+ fun testGetInterceptRegion_hasCutout() {
+ setupDisplayCutoutBaseView(true /* fillCutout */, true /* hasCutout */)
+ whenever(mockRootView.left).thenReturn(0)
+ whenever(mockRootView.top).thenReturn(0)
+ whenever(mockRootView.right).thenReturn(100)
+ whenever(mockRootView.bottom).thenReturn(200)
+
+ val expect = Region()
+ expect.op(cutout.boundingRectTop, Region.Op.UNION)
+ expect.op(0, 0, 100, 200, Region.Op.INTERSECT)
+
+ cutoutBaseView.updateCutout()
+
+ assertThat(cutoutBaseView.interceptRegion).isEqualTo(expect)
+ }
+
+ @Test
+ fun testGetInterceptRegion_noCutout() {
+ setupDisplayCutoutBaseView(true /* fillCutout */, false /* hasCutout */)
+ cutoutBaseView.updateCutout()
+
+ assertThat(cutoutBaseView.interceptRegion).isNull()
+ }
+
+ @Test
+ fun testCutoutProtection() {
+ setupDisplayCutoutBaseView(true /* fillCutout */, false /* hasCutout */)
+ val bounds = Rect(0, 0, 10, 10)
+ val path = Path()
+ val pathBounds = RectF(bounds)
+ path.addRect(pathBounds, Path.Direction.CCW)
+
+ context.mainExecutor.execute {
+ cutoutBaseView.setProtection(path, bounds)
+ cutoutBaseView.enableShowProtection(true)
+ }
+ waitForIdleSync()
+
+ assertThat(cutoutBaseView.protectionPath.isRect(pathBounds)).isTrue()
+ assertThat(cutoutBaseView.protectionRect).isEqualTo(pathBounds)
+ }
+
+ private fun setupDisplayCutoutBaseView(fillCutout: Boolean, hasCutout: Boolean) {
+ mContext.orCreateTestableResources.addOverride(
+ R.array.config_displayUniqueIdArray, arrayOf<String>())
+ mContext.orCreateTestableResources.addOverride(
+ R.bool.config_fillMainBuiltInDisplayCutout, fillCutout)
+
+ cutoutBaseView = spy(DisplayCutoutBaseView(mContext))
+ whenever(cutoutBaseView.display).thenReturn(mockDisplay)
+ whenever(cutoutBaseView.rootView).thenReturn(mockRootView)
+ whenever(mockDisplay.getDisplayInfo(eq(cutoutBaseView.displayInfo))
+ ).then {
+ val info = it.getArgument<DisplayInfo>(0)
+ info.displayCutout = if (hasCutout) cutout else null
+ return@then true
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index 72d72c8..70f3251 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -14,7 +14,6 @@
package com.android.systemui;
-import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.DisplayCutout.BOUNDS_POSITION_BOTTOM;
import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT;
import static android.view.DisplayCutout.BOUNDS_POSITION_LENGTH;
@@ -22,7 +21,7 @@
import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
-import static com.android.systemui.ScreenDecorations.rectsToRegion;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.google.common.truth.Truth.assertThat;
@@ -32,7 +31,6 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.Mockito.atLeastOnce;
@@ -49,10 +47,12 @@
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Insets;
+import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.VectorDrawable;
import android.hardware.display.DisplayManager;
+import android.hardware.graphics.common.DisplayDecorationSupport;
import android.os.Handler;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -89,7 +89,6 @@
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
-import java.util.Collections;
@RunWithLooper
@RunWith(AndroidTestingRunner.class)
@@ -106,6 +105,8 @@
private FakeThreadFactory mThreadFactory;
private ArrayList<DecorProvider> mDecorProviders;
@Mock
+ private Display mDisplay;
+ @Mock
private TunerService mTunerService;
@Mock
private BroadcastDispatcher mBroadcastDispatcher;
@@ -140,14 +141,15 @@
.getMaximumWindowMetrics();
when(mWindowManager.getMaximumWindowMetrics()).thenReturn(metrics);
mContext.addMockSystemService(WindowManager.class, mWindowManager);
-
mDisplayManager = mock(DisplayManager.class);
- Display display = mContext.getSystemService(DisplayManager.class)
- .getDisplay(DEFAULT_DISPLAY);
- when(mDisplayManager.getDisplay(anyInt())).thenReturn(display);
mContext.addMockSystemService(DisplayManager.class, mDisplayManager);
- when(mMockTypedArray.length()).thenReturn(0);
+ spyOn(mContext);
+ when(mContext.getDisplay()).thenReturn(mDisplay);
+ // Not support hwc layer by default
+ doReturn(null).when(mDisplay).getDisplayDecorationSupport();
+
+ when(mMockTypedArray.length()).thenReturn(0);
mPrivacyDotTopLeftDecorProvider = spy(new PrivacyDotCornerDecorProviderImpl(
R.id.privacy_dot_top_left_container,
DisplayCutout.BOUNDS_POSITION_TOP,
@@ -975,12 +977,6 @@
}
@Test
- public void testBoundingRectsToRegion() throws Exception {
- Rect rect = new Rect(1, 2, 3, 4);
- assertThat(rectsToRegion(Collections.singletonList(rect)).getBounds(), is(rect));
- }
-
- @Test
public void testRegistration_From_NoOverlay_To_HasOverlays() {
doReturn(false).when(mScreenDecorations).hasOverlays();
mScreenDecorations.start();
@@ -1029,6 +1025,114 @@
assertThat(mScreenDecorations.mIsRegistered, is(false));
}
+ @Test
+ public void testSupportHwcLayer_SwitchFrom_NotSupport() {
+ setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */,
+ 0 /* roundedPadding */, false /* multipleRadius */,
+ true /* fillCutout */, false /* privacyDot */);
+
+ // top cutout
+ final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
+
+ mScreenDecorations.start();
+ // should only inflate mOverlays when the hwc doesn't support screen decoration
+ assertNull(mScreenDecorations.mScreenDecorHwcWindow);
+ assertNotNull(mScreenDecorations.mOverlays);
+ assertNotNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]);
+ assertNotNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]);
+
+ final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport();
+ decorationSupport.format = PixelFormat.R_8;
+ doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport();
+ // Trigger the support hwc screen decoration change by changing the display unique id
+ mScreenDecorations.mDisplayUniqueId = "test";
+ mScreenDecorations.mDisplayListener.onDisplayChanged(1);
+
+ // should only inflate hwc layer when the hwc supports screen decoration
+ assertNotNull(mScreenDecorations.mScreenDecorHwcWindow);
+ assertNull(mScreenDecorations.mOverlays);
+ }
+
+ @Test
+ public void testNotSupportHwcLayer_SwitchFrom_Support() {
+ setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */,
+ 0 /* roundedPadding */, false /* multipleRadius */,
+ true /* fillCutout */, false /* privacyDot */);
+ final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport();
+ decorationSupport.format = PixelFormat.R_8;
+ doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport();
+
+ // top cutout
+ final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
+
+ mScreenDecorations.start();
+ // should only inflate hwc layer when the hwc supports screen decoration
+ assertNotNull(mScreenDecorations.mScreenDecorHwcWindow);
+ assertNull(mScreenDecorations.mOverlays);
+
+ doReturn(null).when(mDisplay).getDisplayDecorationSupport();
+ // Trigger the support hwc screen decoration change by changing the display unique id
+ mScreenDecorations.mDisplayUniqueId = "test";
+ mScreenDecorations.mDisplayListener.onDisplayChanged(1);
+
+ // should only inflate mOverlays when the hwc doesn't support screen decoration
+ assertNull(mScreenDecorations.mScreenDecorHwcWindow);
+ assertNotNull(mScreenDecorations.mOverlays);
+ assertNotNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]);
+ assertNotNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]);
+ }
+
+ @Test
+ public void testHwcLayer_noPrivacyDot() {
+ setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */,
+ 0 /* roundedPadding */, false /* multipleRadius */,
+ true /* fillCutout */, false /* privacyDot */);
+ final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport();
+ decorationSupport.format = PixelFormat.R_8;
+ doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport();
+
+ // top cutout
+ final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
+
+ mScreenDecorations.start();
+
+ // Should only inflate hwc layer.
+ assertNotNull(mScreenDecorations.mScreenDecorHwcWindow);
+ assertNull(mScreenDecorations.mOverlays);
+ }
+
+ @Test
+ public void testHwcLayer_PrivacyDot() {
+ setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */,
+ 0 /* roundedPadding */, false /* multipleRadius */,
+ true /* fillCutout */, true /* privacyDot */);
+ final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport();
+ decorationSupport.format = PixelFormat.R_8;
+ doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport();
+
+ // top cutout
+ final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
+
+ mScreenDecorations.start();
+
+ assertNotNull(mScreenDecorations.mScreenDecorHwcWindow);
+ // mOverlays are inflated but the visibility should be GONE.
+ assertNotNull(mScreenDecorations.mOverlays);
+ final View topOverlay = mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP].getRootView();
+ final View botOverlay = mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].getRootView();
+ assertEquals(topOverlay.getVisibility(), View.INVISIBLE);
+ assertEquals(botOverlay.getVisibility(), View.INVISIBLE);
+
+ }
+
private void setupResources(int radius, int radiusTop, int radiusBottom, int roundedPadding,
boolean multipleRadius, boolean fillCutout, boolean privacyDot) {
mContext.getOrCreateTestableResources().addOverride(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalSettingConditionTest.java b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalSettingConditionTest.java
index 2d52c42..c5b1a1d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalSettingConditionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalSettingConditionTest.java
@@ -16,7 +16,8 @@
package com.android.systemui.communal;
-import static org.mockito.ArgumentMatchers.anyBoolean;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
@@ -59,7 +60,8 @@
final Condition.Callback callback = mock(Condition.Callback.class);
mCondition.addCallback(callback);
- verify(callback).onConditionChanged(mCondition, true);
+ verify(callback).onConditionChanged(mCondition);
+ assertThat(mCondition.isConditionMet()).isTrue();
}
@Test
@@ -68,7 +70,7 @@
final Condition.Callback callback = mock(Condition.Callback.class);
mCondition.addCallback(callback);
- verify(callback, never()).onConditionChanged(eq(mCondition), anyBoolean());
+ verify(callback, never()).onConditionChanged(eq(mCondition));
}
@Test
@@ -80,7 +82,8 @@
clearInvocations(callback);
updateCommunalSetting(true);
- verify(callback).onConditionChanged(mCondition, true);
+ verify(callback).onConditionChanged(mCondition);
+ assertThat(mCondition.isConditionMet()).isTrue();
}
@Test
@@ -92,7 +95,8 @@
clearInvocations(callback);
updateCommunalSetting(false);
- verify(callback).onConditionChanged(mCondition, false);
+ verify(callback).onConditionChanged(mCondition);
+ assertThat(mCondition.isConditionMet()).isFalse();
}
@Test
@@ -104,7 +108,8 @@
clearInvocations(callback);
updateCommunalSetting(true);
- verify(callback, never()).onConditionChanged(mCondition, true);
+ verify(callback, never()).onConditionChanged(mCondition);
+ assertThat(mCondition.isConditionMet()).isTrue();
}
private void updateCommunalSetting(boolean value) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalTrustedNetworkConditionTest.java b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalTrustedNetworkConditionTest.java
index 61a5126..500205c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalTrustedNetworkConditionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalTrustedNetworkConditionTest.java
@@ -16,7 +16,8 @@
package com.android.systemui.communal;
-import static org.mockito.ArgumentMatchers.anyBoolean;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.clearInvocations;
@@ -49,6 +50,7 @@
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
@SmallTest
@@ -89,7 +91,8 @@
networkCallback.onCapabilitiesChanged(network, fakeNetworkCapabilities(mTrustedWifi1));
// Verifies that the callback is triggered.
- verify(callback).onConditionChanged(mCondition, true);
+ verify(callback).onConditionChanged(mCondition);
+ assertThat(mCondition.isConditionMet()).isTrue();
}
@Test
@@ -110,7 +113,7 @@
networkCallback.onCapabilitiesChanged(network, fakeNetworkCapabilities(mTrustedWifi2));
// Verifies that the callback is not triggered.
- verify(callback, never()).onConditionChanged(eq(mCondition), anyBoolean());
+ verify(callback, never()).onConditionChanged(eq(mCondition));
}
@Test
@@ -126,11 +129,13 @@
networkCallback.onAvailable(network);
networkCallback.onCapabilitiesChanged(network, fakeNetworkCapabilities(mTrustedWifi1));
+ Mockito.clearInvocations(callback);
// Connected to non-trusted Wi-Fi network.
networkCallback.onCapabilitiesChanged(network, fakeNetworkCapabilities("random-wifi"));
// Verifies that the callback is triggered.
- verify(callback).onConditionChanged(mCondition, false);
+ verify(callback).onConditionChanged(mCondition);
+ assertThat(mCondition.isConditionMet()).isFalse();
}
@Test
@@ -151,7 +156,8 @@
networkCallback.onLost(network);
// Verifies that the callback is triggered.
- verify(callback).onConditionChanged(mCondition, false);
+ verify(callback).onConditionChanged(mCondition);
+ assertThat(mCondition.isConditionMet()).isFalse();
}
// Captures and returns the network callback, assuming it is registered with the connectivity
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
index cdffaec..7e1edd2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
@@ -35,6 +35,7 @@
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
@@ -306,4 +307,11 @@
// THEN the display screen state will change
assertEquals(Display.STATE_DOZE_SUSPEND, mServiceFake.screenState);
}
+
+ @Test
+ public void authCallbackRemovedOnDestroy() {
+ mScreen.destroy();
+
+ verify(mAuthController).removeCallback(anyObject());
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
index 8adb55b..58ffbfa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
@@ -31,14 +31,13 @@
import android.view.WindowManager;
import android.view.WindowManagerImpl;
+import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.settingslib.dream.DreamBackend;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.dreams.complication.Complication;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
import com.android.systemui.dreams.touch.DreamOverlayTouchMonitor;
import com.android.systemui.util.concurrency.FakeExecutor;
@@ -52,10 +51,6 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class DreamOverlayServiceTest extends SysuiTestCase {
@@ -100,9 +95,6 @@
@Mock
DreamOverlayStateController mStateController;
- @Mock
- DreamBackend mDreamBackend;
-
DreamOverlayService mService;
@Before
@@ -118,8 +110,6 @@
.thenReturn(mLifecycleRegistry);
when(mDreamOverlayComponent.getDreamOverlayTouchMonitor())
.thenReturn(mDreamOverlayTouchMonitor);
- when(mDreamOverlayComponent.getDreamBackend())
- .thenReturn(mDreamBackend);
when(mDreamOverlayComponentFactory
.create(any(), any()))
.thenReturn(mDreamOverlayComponent);
@@ -173,22 +163,12 @@
}
@Test
- public void testSetAvailableComplicationTypes() throws Exception {
- final Set<Integer> enabledComplications = new HashSet<>(
- Arrays.asList(DreamBackend.COMPLICATION_TYPE_TIME,
- DreamBackend.COMPLICATION_TYPE_DATE,
- DreamBackend.COMPLICATION_TYPE_WEATHER));
- when(mDreamBackend.getEnabledComplications()).thenReturn(enabledComplications);
-
- final IBinder proxy = mService.onBind(new Intent());
- final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
-
- overlay.startDream(mWindowParams, mDreamOverlayCallback);
+ public void testDestroy() {
+ mService.onDestroy();
mMainExecutor.runAllReady();
- final int expectedTypes =
- Complication.COMPLICATION_TYPE_TIME | Complication.COMPLICATION_TYPE_DATE
- | Complication.COMPLICATION_TYPE_WEATHER;
- verify(mStateController).setAvailableComplicationTypes(expectedTypes);
+ verify(mKeyguardUpdateMonitor).removeCallback(any());
+ verify(mLifecycleRegistry).setCurrentState(Lifecycle.State.DESTROYED);
+ verify(mStateController).setOverlayActive(false);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java
new file mode 100644
index 0000000..09976e0
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.systemui.dreams.complication;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.settingslib.dream.DreamBackend;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dreams.DreamOverlayStateController;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Arrays;
+import java.util.HashSet;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class ComplicationTypesUpdaterTest extends SysuiTestCase {
+ @Mock
+ private Context mContext;
+ @Mock
+ private DreamBackend mDreamBackend;
+ @Mock
+ private SecureSettings mSecureSettings;
+ @Mock
+ private DreamOverlayStateController mDreamOverlayStateController;
+ @Captor
+ private ArgumentCaptor<ContentObserver> mSettingsObserverCaptor;
+
+ private final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
+
+ private ComplicationTypesUpdater mController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mDreamBackend.getEnabledComplications()).thenReturn(new HashSet<>());
+
+ mController = new ComplicationTypesUpdater(mContext, mDreamBackend, mExecutor,
+ mSecureSettings, mDreamOverlayStateController);
+ }
+
+ @Test
+ public void testPushUpdateToDreamOverlayStateControllerImmediatelyOnStart() {
+ // DreamOverlayStateController shouldn't be updated before start().
+ verify(mDreamOverlayStateController, never()).setAvailableComplicationTypes(anyInt());
+
+ mController.start();
+ mExecutor.runAllReady();
+
+ // DreamOverlayStateController updated immediately on start().
+ verify(mDreamOverlayStateController).setAvailableComplicationTypes(anyInt());
+ }
+
+ @Test
+ public void testPushUpdateToDreamOverlayStateControllerOnChange() {
+ mController.start();
+ mExecutor.runAllReady();
+
+ when(mDreamBackend.getEnabledComplications()).thenReturn(new HashSet<>(Arrays.asList(
+ DreamBackend.COMPLICATION_TYPE_TIME, DreamBackend.COMPLICATION_TYPE_WEATHER,
+ DreamBackend.COMPLICATION_TYPE_AIR_QUALITY)));
+ final ContentObserver settingsObserver = captureSettingsObserver();
+ settingsObserver.onChange(false);
+ mExecutor.runAllReady();
+
+ verify(mDreamOverlayStateController).setAvailableComplicationTypes(
+ Complication.COMPLICATION_TYPE_TIME | Complication.COMPLICATION_TYPE_WEATHER
+ | Complication.COMPLICATION_TYPE_AIR_QUALITY);
+ }
+
+ private ContentObserver captureSettingsObserver() {
+ verify(mSecureSettings).registerContentObserverForUser(
+ eq(Settings.Secure.SCREENSAVER_ENABLED_COMPLICATIONS),
+ mSettingsObserverCaptor.capture(), eq(UserHandle.myUserId()));
+ return mSettingsObserverCaptor.getValue();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dump/DumpHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dump/DumpHandlerTest.kt
index 9e67eda..57fbbc9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dump/DumpHandlerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/dump/DumpHandlerTest.kt
@@ -62,7 +62,7 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
- dumpHandler = DumpHandler(mContext, dumpManager, logBufferEulogizer)
+ dumpHandler = DumpHandler(mContext, dumpManager, logBufferEulogizer, mutableMapOf())
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 210cb82..a80aed7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -18,6 +18,9 @@
import static android.view.WindowManagerPolicyConstants.OFF_BECAUSE_OF_USER;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
+
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
@@ -43,6 +46,7 @@
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardDisplayManager;
+import com.android.keyguard.KeyguardSecurityView;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.mediator.ScreenOnCoordinator;
import com.android.systemui.SysuiTestCase;
@@ -181,6 +185,24 @@
verify(mStatusBarKeyguardViewManager, atLeast(1)).show(null);
}
+ @Test
+ public void testBouncerPrompt_deviceLockedByAdmin() {
+ // GIVEN no trust agents enabled and biometrics aren't enrolled
+ when(mUpdateMonitor.isTrustUsuallyManaged(anyInt())).thenReturn(false);
+ when(mUpdateMonitor.isUnlockingWithBiometricsPossible(anyInt())).thenReturn(false);
+
+ // WHEN the strong auth reason is AFTER_DPM_LOCK_NOW
+ KeyguardUpdateMonitor.StrongAuthTracker strongAuthTracker =
+ mock(KeyguardUpdateMonitor.StrongAuthTracker.class);
+ when(mUpdateMonitor.getStrongAuthTracker()).thenReturn(strongAuthTracker);
+ when(strongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn(
+ STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW);
+
+ // THEN the bouncer prompt reason should return PROMPT_REASON_DEVICE_ADMIN
+ assertEquals(KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN,
+ mViewMediator.mViewMediatorCallback.getBouncerPromptReason());
+ }
+
private void createAndStartViewMediator() {
mViewMediator = new KeyguardViewMediator(
mContext,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index 609291a..708fc91 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -74,6 +74,7 @@
private const val SESSION_ARTIST = "SESSION_ARTIST"
private const val SESSION_TITLE = "SESSION_TITLE"
private const val USER_ID = 0
+private const val DISABLED_DEVICE_NAME = "DISABLED_DEVICE_NAME"
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -131,7 +132,7 @@
private lateinit var session: MediaSession
private val device = MediaDeviceData(true, null, DEVICE_NAME)
- private val disabledDevice = MediaDeviceData(false, null, "Disabled Device")
+ private val disabledDevice = MediaDeviceData(false, null, DISABLED_DEVICE_NAME)
private lateinit var mediaData: MediaData
private val clock = FakeSystemClock()
@@ -396,13 +397,12 @@
@Test
fun bindDisabledDevice() {
seamless.id = 1
- val fallbackString = context.getString(R.string.media_seamless_other_device)
player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
val state = mediaData.copy(device = disabledDevice)
player.bindPlayer(state, PACKAGE)
assertThat(seamless.isEnabled()).isFalse()
- assertThat(seamlessText.getText()).isEqualTo(fallbackString)
- assertThat(seamless.contentDescription).isEqualTo(fallbackString)
+ assertThat(seamlessText.getText()).isEqualTo(DISABLED_DEVICE_NAME)
+ assertThat(seamless.contentDescription).isEqualTo(DISABLED_DEVICE_NAME)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
index 649ee87..f4fa921 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -1,6 +1,5 @@
package com.android.systemui.media
-import android.app.Notification
import android.app.Notification.MediaStyle
import android.app.PendingIntent
import android.app.smartspace.SmartspaceAction
@@ -240,15 +239,14 @@
@Test
fun testOnNotificationAdded_isRcn_markedRemote() {
- val bundle = Bundle().apply {
- putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, "Remote Cast Notification")
- }
val rcn = SbnBuilder().run {
setPkg("com.android.systemui") // System package
modifyNotification(context).also {
it.setSmallIcon(android.R.drawable.ic_media_pause)
- it.setStyle(MediaStyle().apply { setMediaSession(session.sessionToken) })
- it.addExtras(bundle)
+ it.setStyle(MediaStyle().apply {
+ setMediaSession(session.sessionToken)
+ setRemotePlaybackInfo("Remote device", 0, null)
+ })
}
build()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
index 3d59497..d912a89 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
@@ -30,6 +30,8 @@
import com.android.settingslib.media.MediaDevice
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
+import com.android.systemui.media.muteawait.MediaMuteAwaitConnectionManager
+import com.android.systemui.media.muteawait.MediaMuteAwaitConnectionManagerFactory
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
@@ -44,6 +46,7 @@
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.any
+import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
@@ -71,6 +74,8 @@
@Mock private lateinit var lmmFactory: LocalMediaManagerFactory
@Mock private lateinit var lmm: LocalMediaManager
@Mock private lateinit var mr2: MediaRouter2Manager
+ @Mock private lateinit var muteAwaitFactory: MediaMuteAwaitConnectionManagerFactory
+ @Mock private lateinit var muteAwaitManager: MediaMuteAwaitConnectionManager
private lateinit var fakeFgExecutor: FakeExecutor
private lateinit var fakeBgExecutor: FakeExecutor
@Mock private lateinit var dumpster: DumpManager
@@ -88,14 +93,22 @@
fun setUp() {
fakeFgExecutor = FakeExecutor(FakeSystemClock())
fakeBgExecutor = FakeExecutor(FakeSystemClock())
- manager = MediaDeviceManager(controllerFactory, lmmFactory, mr2, fakeFgExecutor,
- fakeBgExecutor, dumpster)
+ manager = MediaDeviceManager(
+ controllerFactory,
+ lmmFactory,
+ mr2,
+ muteAwaitFactory,
+ fakeFgExecutor,
+ fakeBgExecutor,
+ dumpster
+ )
manager.addListener(listener)
// Configure mocks.
whenever(device.name).thenReturn(DEVICE_NAME)
whenever(device.iconWithoutBackground).thenReturn(icon)
whenever(lmmFactory.create(PACKAGE)).thenReturn(lmm)
+ whenever(muteAwaitFactory.create(lmm)).thenReturn(muteAwaitManager)
whenever(lmm.getCurrentConnectedDevice()).thenReturn(device)
whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(route)
@@ -146,6 +159,7 @@
manager.onMediaDataRemoved(KEY)
fakeBgExecutor.runAllReady()
verify(lmm).unregisterCallback(any())
+ verify(muteAwaitManager).stopListening()
}
@Test
@@ -169,6 +183,7 @@
fakeFgExecutor.runAllReady()
// THEN the listener for the old key should removed.
verify(lmm).unregisterCallback(any())
+ verify(muteAwaitManager).stopListening()
// AND a new device event emitted
val data = captureDeviceData(KEY, KEY_OLD)
assertThat(data.enabled).isTrue()
@@ -240,6 +255,7 @@
manager.onMediaDataLoaded(KEY, null, mediaData)
fakeBgExecutor.runAllReady()
val deviceCallback = captureCallback()
+ verify(muteAwaitManager).startListening()
// WHEN the device list changes
deviceCallback.onDeviceListUpdate(mutableListOf(device))
assertThat(fakeBgExecutor.runAllReady()).isEqualTo(1)
@@ -268,6 +284,51 @@
}
@Test
+ fun onAboutToConnectDeviceChangedWithNonNullParams() {
+ manager.onMediaDataLoaded(KEY, null, mediaData)
+ // Run and reset the executors and listeners so we only focus on new events.
+ fakeBgExecutor.runAllReady()
+ fakeFgExecutor.runAllReady()
+ reset(listener)
+
+ val deviceCallback = captureCallback()
+ // WHEN the about-to-connect device changes to non-null
+ val name = "AboutToConnectDeviceName"
+ val mockIcon = mock(Drawable::class.java)
+ deviceCallback.onAboutToConnectDeviceChanged(name, mockIcon)
+ assertThat(fakeFgExecutor.runAllReady()).isEqualTo(1)
+ // THEN the about-to-connect device is returned
+ val data = captureDeviceData(KEY)
+ assertThat(data.enabled).isTrue()
+ assertThat(data.name).isEqualTo(name)
+ assertThat(data.icon).isEqualTo(mockIcon)
+ }
+
+ @Test
+ fun onAboutToConnectDeviceChangedWithNullParams() {
+ manager.onMediaDataLoaded(KEY, null, mediaData)
+ fakeBgExecutor.runAllReady()
+ val deviceCallback = captureCallback()
+ // First set a non-null about-to-connect device
+ deviceCallback.onAboutToConnectDeviceChanged(
+ "AboutToConnectDeviceName", mock(Drawable::class.java)
+ )
+ // Run and reset the executors and listeners so we only focus on new events.
+ fakeBgExecutor.runAllReady()
+ fakeFgExecutor.runAllReady()
+ reset(listener)
+
+ // WHEN the about-to-connect device changes to null
+ deviceCallback.onAboutToConnectDeviceChanged(null, null)
+ assertThat(fakeFgExecutor.runAllReady()).isEqualTo(1)
+ // THEN the normal device is returned
+ val data = captureDeviceData(KEY)
+ assertThat(data.enabled).isTrue()
+ assertThat(data.name).isEqualTo(DEVICE_NAME)
+ assertThat(data.icon).isEqualTo(icon)
+ }
+
+ @Test
fun listenerReceivesKeyRemoved() {
manager.onMediaDataLoaded(KEY, null, mediaData)
// WHEN the notification is removed
@@ -376,6 +437,24 @@
verify(mr2, never()).getRoutingSessionForMediaController(eq(controller))
}
+ @Test
+ fun testRemotePlaybackDeviceOverride() {
+ whenever(route.name).thenReturn(DEVICE_NAME)
+ val deviceData = MediaDeviceData(false, null, REMOTE_DEVICE_NAME, null)
+ val mediaDataWithDevice = mediaData.copy(device = deviceData)
+
+ // GIVEN media data that already has a device set
+ manager.onMediaDataLoaded(KEY, null, mediaDataWithDevice)
+ fakeBgExecutor.runAllReady()
+ fakeFgExecutor.runAllReady()
+
+ // THEN we keep the device info, and don't register a listener
+ val data = captureDeviceData(KEY)
+ assertThat(data.enabled).isFalse()
+ assertThat(data.name).isEqualTo(REMOTE_DEVICE_NAME)
+ verify(lmm, never()).registerCallback(any())
+ }
+
fun captureCallback(): LocalMediaManager.DeviceCallback {
val captor = ArgumentCaptor.forClass(LocalMediaManager.DeviceCallback::class.java)
verify(lmm).registerCallback(captor.capture())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
index 9f542f0..c5c4d79 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
@@ -24,6 +24,7 @@
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.media.session.MediaSessionManager;
import android.os.Bundle;
@@ -99,7 +100,10 @@
@Test
public void refresh_withIconCompat_iconIsVisible() {
- mIconCompat = mock(IconCompat.class);
+ mIconCompat = IconCompat.createWithBitmap(
+ Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888));
+ when(mMediaOutputBaseAdapter.getController()).thenReturn(mMediaOutputController);
+
mMediaOutputBaseDialogImpl.refresh();
final ImageView view = mMediaOutputBaseDialogImpl.mDialogView.requireViewById(
R.id.header_icon);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
index 0576987..bdc3117 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
@@ -201,7 +201,7 @@
assertThat(devices.containsAll(mMediaDevices)).isTrue();
assertThat(devices.size()).isEqualTo(mMediaDevices.size());
- verify(mCb).onRouteChanged();
+ verify(mCb).onDeviceListChanged();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt
new file mode 100644
index 0000000..88c4514
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt
@@ -0,0 +1,202 @@
+/*
+ * 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.systemui.media.muteawait
+
+import android.content.Context
+import android.graphics.drawable.Drawable
+import android.media.AudioAttributes.USAGE_MEDIA
+import android.media.AudioAttributes.USAGE_UNKNOWN
+import android.media.AudioDeviceAttributes
+import android.media.AudioDeviceInfo
+import android.media.AudioManager
+import android.media.AudioManager.MuteAwaitConnectionCallback.EVENT_CONNECTION
+import android.test.suitebuilder.annotation.SmallTest
+import com.android.settingslib.media.DeviceIconUtil
+import com.android.settingslib.media.LocalMediaManager
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.time.FakeSystemClock
+import org.junit.Before
+import org.junit.Test
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.reset
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+
+@SmallTest
+class MediaMuteAwaitConnectionManagerTest : SysuiTestCase() {
+ private lateinit var muteAwaitConnectionManager: MediaMuteAwaitConnectionManager
+ @Mock
+ private lateinit var audioManager: AudioManager
+ @Mock
+ private lateinit var deviceIconUtil: DeviceIconUtil
+ @Mock
+ private lateinit var localMediaManager: LocalMediaManager
+ private lateinit var icon: Drawable
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ context.addMockSystemService(Context.AUDIO_SERVICE, audioManager)
+ icon = context.getDrawable(R.drawable.ic_cake)!!
+ whenever(deviceIconUtil.getIconFromAudioDeviceType(any(), any())).thenReturn(icon)
+
+ muteAwaitConnectionManager = MediaMuteAwaitConnectionManager(
+ FakeExecutor(FakeSystemClock()),
+ localMediaManager,
+ context,
+ deviceIconUtil
+ )
+ }
+
+ @Test
+ fun constructor_audioManagerCallbackNotRegistered() {
+ verify(audioManager, never()).registerMuteAwaitConnectionCallback(any(), any())
+ }
+
+ @Test
+ fun startListening_audioManagerCallbackRegistered() {
+ muteAwaitConnectionManager.startListening()
+
+ verify(audioManager).registerMuteAwaitConnectionCallback(any(), any())
+ }
+
+ @Test
+ fun stopListening_audioManagerCallbackUnregistered() {
+ muteAwaitConnectionManager.stopListening()
+
+ verify(audioManager).unregisterMuteAwaitConnectionCallback(any())
+ }
+
+ @Test
+ fun startListening_audioManagerHasNoMuteAwaitDevice_localMediaMangerNotNotified() {
+ whenever(audioManager.mutingExpectedDevice).thenReturn(null)
+
+ muteAwaitConnectionManager.startListening()
+
+ verify(localMediaManager, never()).dispatchAboutToConnectDeviceChanged(any(), any())
+ }
+
+ @Test
+ fun startListening_audioManagerHasMuteAwaitDevice_localMediaMangerNotified() {
+ whenever(audioManager.mutingExpectedDevice).thenReturn(DEVICE)
+
+ muteAwaitConnectionManager.startListening()
+
+ verify(localMediaManager).dispatchAboutToConnectDeviceChanged(eq(DEVICE_NAME), eq(icon))
+ }
+
+ @Test
+ fun onMutedUntilConnection_notUsageMedia_localMediaManagerNotNotified() {
+ muteAwaitConnectionManager.startListening()
+ val muteAwaitListener = getMuteAwaitListener()
+
+ muteAwaitListener.onMutedUntilConnection(DEVICE, intArrayOf(USAGE_UNKNOWN))
+
+ verify(localMediaManager, never()).dispatchAboutToConnectDeviceChanged(any(), any())
+ }
+
+ @Test
+ fun onMutedUntilConnection_isUsageMedia_localMediaManagerNotified() {
+ muteAwaitConnectionManager.startListening()
+ val muteAwaitListener = getMuteAwaitListener()
+
+
+ muteAwaitListener.onMutedUntilConnection(DEVICE, intArrayOf(USAGE_MEDIA))
+
+ verify(localMediaManager).dispatchAboutToConnectDeviceChanged(eq(DEVICE_NAME), eq(icon))
+ }
+
+ @Test
+ fun onUnmutedEvent_noDeviceMutedBefore_localMediaManagerNotNotified() {
+ muteAwaitConnectionManager.startListening()
+ val muteAwaitListener = getMuteAwaitListener()
+
+ muteAwaitListener.onUnmutedEvent(EVENT_CONNECTION, DEVICE, intArrayOf(USAGE_MEDIA))
+
+ verify(localMediaManager, never()).dispatchAboutToConnectDeviceChanged(any(), any())
+ }
+
+ @Test
+ fun onUnmutedEvent_notSameDevice_localMediaManagerNotNotified() {
+ muteAwaitConnectionManager.startListening()
+ val muteAwaitListener = getMuteAwaitListener()
+ muteAwaitListener.onMutedUntilConnection(DEVICE, intArrayOf(USAGE_MEDIA))
+ reset(localMediaManager)
+
+ val otherDevice = AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_OUTPUT,
+ AudioDeviceInfo.TYPE_USB_HEADSET,
+ "address",
+ "DifferentName",
+ listOf(),
+ listOf(),
+ )
+ muteAwaitListener.onUnmutedEvent(EVENT_CONNECTION, otherDevice, intArrayOf(USAGE_MEDIA))
+
+ verify(localMediaManager, never()).dispatchAboutToConnectDeviceChanged(any(), any())
+ }
+
+ @Test
+ fun onUnmutedEvent_notUsageMedia_localMediaManagerNotNotified() {
+ muteAwaitConnectionManager.startListening()
+ val muteAwaitListener = getMuteAwaitListener()
+ muteAwaitListener.onMutedUntilConnection(DEVICE, intArrayOf(USAGE_MEDIA))
+ reset(localMediaManager)
+
+ muteAwaitListener.onUnmutedEvent(EVENT_CONNECTION, DEVICE, intArrayOf(USAGE_UNKNOWN))
+
+ verify(localMediaManager, never()).dispatchAboutToConnectDeviceChanged(any(), any())
+ }
+
+ @Test
+ fun onUnmutedEvent_sameDeviceAndUsageMedia_localMediaManagerNotified() {
+ muteAwaitConnectionManager.startListening()
+ val muteAwaitListener = getMuteAwaitListener()
+ muteAwaitListener.onMutedUntilConnection(DEVICE, intArrayOf(USAGE_MEDIA))
+ reset(localMediaManager)
+
+ muteAwaitListener.onUnmutedEvent(EVENT_CONNECTION, DEVICE, intArrayOf(USAGE_MEDIA))
+
+ verify(localMediaManager).dispatchAboutToConnectDeviceChanged(eq(null), eq(null))
+ }
+
+ private fun getMuteAwaitListener(): AudioManager.MuteAwaitConnectionCallback {
+ val listenerCaptor = ArgumentCaptor.forClass(
+ AudioManager.MuteAwaitConnectionCallback::class.java
+ )
+ verify(audioManager).registerMuteAwaitConnectionCallback(any(), listenerCaptor.capture())
+ return listenerCaptor.value!!
+ }
+}
+
+private const val DEVICE_NAME = "DeviceName"
+private val DEVICE = AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_OUTPUT,
+ AudioDeviceInfo.TYPE_USB_HEADSET,
+ "address",
+ DEVICE_NAME,
+ listOf(),
+ listOf(),
+)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
index cb05d03..14afece 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
@@ -203,7 +203,9 @@
verify(statusBarManager).updateMediaTapToTransferReceiverDisplay(
eq(StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER),
- any()
+ any(),
+ nullable(),
+ nullable()
)
}
@@ -213,7 +215,9 @@
verify(statusBarManager).updateMediaTapToTransferReceiverDisplay(
eq(StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER),
- any()
+ any(),
+ nullable(),
+ nullable()
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
index 242fd19..f05d621 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
@@ -92,16 +92,16 @@
fun setIcon_viewHasIconAndContentDescription() {
controllerCommon.displayChip(getState())
val chipView = getChipView()
- val drawable = Icon.createWithResource(context, R.drawable.ic_cake).loadDrawable(context)
- val contentDescription = "test description"
- controllerCommon.setIcon(MediaTttChipState(drawable, contentDescription), chipView)
+ val state = MediaTttChipState(PACKAGE_NAME)
+ controllerCommon.setIcon(state, chipView)
- assertThat(chipView.getAppIconView().drawable).isEqualTo(drawable)
- assertThat(chipView.getAppIconView().contentDescription).isEqualTo(contentDescription)
+ assertThat(chipView.getAppIconView().drawable).isEqualTo(state.getAppIcon(context))
+ assertThat(chipView.getAppIconView().contentDescription)
+ .isEqualTo(state.getAppName(context))
}
- private fun getState() = MediaTttChipState(appIconDrawable, APP_ICON_CONTENT_DESCRIPTION)
+ private fun getState() = MediaTttChipState(PACKAGE_NAME)
private fun getChipView(): ViewGroup {
val viewCaptor = ArgumentCaptor.forClass(View::class.java)
@@ -122,4 +122,4 @@
}
}
-private const val APP_ICON_CONTENT_DESCRIPTION = "Content description"
+private const val PACKAGE_NAME = "com.android.systemui"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
index fce4954..44f691c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
@@ -19,6 +19,7 @@
import android.app.StatusBarManager
import android.graphics.drawable.Icon
import android.media.MediaRoute2Info
+import android.os.Handler
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
@@ -52,7 +53,8 @@
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- controllerReceiver = MediaTttChipControllerReceiver(commandQueue, context, windowManager)
+ controllerReceiver = MediaTttChipControllerReceiver(
+ commandQueue, context, windowManager, Handler.getMain())
val callbackCaptor = ArgumentCaptor.forClass(CommandQueue.Callbacks::class.java)
verify(commandQueue).addCallback(callbackCaptor.capture())
@@ -61,19 +63,24 @@
@Test
fun commandQueueCallback_closeToSender_triggersChip() {
+ val appName = "FakeAppName"
commandQueueCallback.updateMediaTapToTransferReceiverDisplay(
StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER,
- routeInfo
+ routeInfo,
+ /* appIcon= */ null,
+ appName
)
- assertThat(getChipView().getAppIconView().contentDescription).isEqualTo(ROUTE_NAME)
+ assertThat(getChipView().getAppIconView().contentDescription).isEqualTo(appName)
}
@Test
fun commandQueueCallback_farFromSender_noChipShown() {
commandQueueCallback.updateMediaTapToTransferReceiverDisplay(
StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER,
- routeInfo
+ routeInfo,
+ null,
+ null
)
verify(windowManager, never()).addView(any(), any())
@@ -83,12 +90,16 @@
fun commandQueueCallback_closeThenFar_chipShownThenHidden() {
commandQueueCallback.updateMediaTapToTransferReceiverDisplay(
StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER,
- routeInfo
+ routeInfo,
+ null,
+ null
)
commandQueueCallback.updateMediaTapToTransferReceiverDisplay(
StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER,
- routeInfo
+ routeInfo,
+ null,
+ null
)
val viewCaptor = ArgumentCaptor.forClass(View::class.java)
@@ -97,14 +108,43 @@
}
@Test
- fun displayChip_chipContainsIcon() {
- val drawable = Icon.createWithResource(context, R.drawable.ic_cake).loadDrawable(context)
- val contentDescription = "Test description"
+ fun displayChip_nullAppIconDrawable_iconIsFromPackageName() {
+ val state = ChipStateReceiver(PACKAGE_NAME, appIconDrawable = null, "appName")
- controllerReceiver.displayChip(ChipStateReceiver(drawable, contentDescription))
+ controllerReceiver.displayChip(state)
+
+ assertThat(getChipView().getAppIconView().drawable).isEqualTo(state.getAppIcon(context))
+
+ }
+
+ @Test
+ fun displayChip_hasAppIconDrawable_iconIsDrawable() {
+ val drawable = Icon.createWithResource(context, R.drawable.ic_cake).loadDrawable(context)
+ val state = ChipStateReceiver(PACKAGE_NAME, drawable, "appName")
+
+ controllerReceiver.displayChip(state)
assertThat(getChipView().getAppIconView().drawable).isEqualTo(drawable)
- assertThat(getChipView().getAppIconView().contentDescription).isEqualTo(contentDescription)
+ }
+
+ @Test
+ fun displayChip_nullAppName_iconContentDescriptionIsFromPackageName() {
+ val state = ChipStateReceiver(PACKAGE_NAME, appIconDrawable = null, appName = null)
+
+ controllerReceiver.displayChip(state)
+
+ assertThat(getChipView().getAppIconView().contentDescription)
+ .isEqualTo(state.getAppName(context))
+ }
+
+ @Test
+ fun displayChip_hasAppName_iconContentDescriptionIsAppNameOverride() {
+ val appName = "FakeAppName"
+ val state = ChipStateReceiver(PACKAGE_NAME, appIconDrawable = null, appName)
+
+ controllerReceiver.displayChip(state)
+
+ assertThat(getChipView().getAppIconView().contentDescription).isEqualTo(appName)
}
private fun getChipView(): ViewGroup {
@@ -116,7 +156,9 @@
private fun ViewGroup.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon)
}
-private const val ROUTE_NAME = "Test name"
-private val routeInfo = MediaRoute2Info.Builder("id", ROUTE_NAME)
+private const val PACKAGE_NAME = "com.android.systemui"
+
+private val routeInfo = MediaRoute2Info.Builder("id", "Test route name")
.addFeature("feature")
+ .setPackageName(PACKAGE_NAME)
.build()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
index c74ac64..dc39893 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
@@ -17,8 +17,6 @@
package com.android.systemui.media.taptotransfer.sender
import android.app.StatusBarManager
-import android.graphics.drawable.Drawable
-import android.graphics.drawable.Icon
import android.media.MediaRoute2Info
import android.view.View
import android.view.WindowManager
@@ -44,8 +42,6 @@
@SmallTest
@Ignore("b/216286227")
class MediaTttChipControllerSenderTest : SysuiTestCase() {
- private lateinit var appIconDrawable: Drawable
-
private lateinit var controllerSender: MediaTttChipControllerSender
@Mock
@@ -57,7 +53,6 @@
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- appIconDrawable = Icon.createWithResource(context, R.drawable.ic_cake).loadDrawable(context)
controllerSender = MediaTttChipControllerSender(commandQueue, context, windowManager)
val callbackCaptor = ArgumentCaptor.forClass(CommandQueue.Callbacks::class.java)
@@ -197,8 +192,9 @@
controllerSender.displayChip(state)
val chipView = getChipView()
- assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconDrawable)
- assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_ICON_CONTENT_DESC)
+ assertThat(chipView.getAppIconView().drawable).isEqualTo(state.getAppIcon(context))
+ assertThat(chipView.getAppIconView().contentDescription)
+ .isEqualTo(state.getAppName(context))
assertThat(chipView.getChipText()).isEqualTo(state.getChipTextString(context))
assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE)
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
@@ -211,8 +207,9 @@
controllerSender.displayChip(state)
val chipView = getChipView()
- assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconDrawable)
- assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_ICON_CONTENT_DESC)
+ assertThat(chipView.getAppIconView().drawable).isEqualTo(state.getAppIcon(context))
+ assertThat(chipView.getAppIconView().contentDescription)
+ .isEqualTo(state.getAppName(context))
assertThat(chipView.getChipText()).isEqualTo(state.getChipTextString(context))
assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE)
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
@@ -225,8 +222,9 @@
controllerSender.displayChip(state)
val chipView = getChipView()
- assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconDrawable)
- assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_ICON_CONTENT_DESC)
+ assertThat(chipView.getAppIconView().drawable).isEqualTo(state.getAppIcon(context))
+ assertThat(chipView.getAppIconView().contentDescription)
+ .isEqualTo(state.getAppName(context))
assertThat(chipView.getChipText()).isEqualTo(state.getChipTextString(context))
assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.VISIBLE)
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
@@ -239,8 +237,9 @@
controllerSender.displayChip(state)
val chipView = getChipView()
- assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconDrawable)
- assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_ICON_CONTENT_DESC)
+ assertThat(chipView.getAppIconView().drawable).isEqualTo(state.getAppIcon(context))
+ assertThat(chipView.getAppIconView().contentDescription)
+ .isEqualTo(state.getAppName(context))
assertThat(chipView.getChipText()).isEqualTo(state.getChipTextString(context))
assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.VISIBLE)
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
@@ -253,8 +252,9 @@
controllerSender.displayChip(state)
val chipView = getChipView()
- assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconDrawable)
- assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_ICON_CONTENT_DESC)
+ assertThat(chipView.getAppIconView().drawable).isEqualTo(state.getAppIcon(context))
+ assertThat(chipView.getAppIconView().contentDescription)
+ .isEqualTo(state.getAppName(context))
assertThat(chipView.getChipText()).isEqualTo(state.getChipTextString(context))
assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE)
assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE)
@@ -314,8 +314,9 @@
controllerSender.displayChip(state)
val chipView = getChipView()
- assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconDrawable)
- assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_ICON_CONTENT_DESC)
+ assertThat(chipView.getAppIconView().drawable).isEqualTo(state.getAppIcon(context))
+ assertThat(chipView.getAppIconView().contentDescription)
+ .isEqualTo(state.getAppName(context))
assertThat(chipView.getChipText()).isEqualTo(state.getChipTextString(context))
assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE)
assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE)
@@ -375,8 +376,9 @@
controllerSender.displayChip(state)
val chipView = getChipView()
- assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconDrawable)
- assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_ICON_CONTENT_DESC)
+ assertThat(chipView.getAppIconView().drawable).isEqualTo(state.getAppIcon(context))
+ assertThat(chipView.getAppIconView().contentDescription)
+ .isEqualTo(state.getAppName(context))
assertThat(chipView.getChipText()).isEqualTo(state.getChipTextString(context))
assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE)
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
@@ -449,39 +451,40 @@
/** Helper method providing default parameters to not clutter up the tests. */
private fun almostCloseToStartCast() =
- AlmostCloseToStartCast(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME)
+ AlmostCloseToStartCast(PACKAGE_NAME, DEVICE_NAME)
/** Helper method providing default parameters to not clutter up the tests. */
private fun almostCloseToEndCast() =
- AlmostCloseToEndCast(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME)
+ AlmostCloseToEndCast(PACKAGE_NAME, DEVICE_NAME)
/** Helper method providing default parameters to not clutter up the tests. */
private fun transferToReceiverTriggered() =
- TransferToReceiverTriggered(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME)
+ TransferToReceiverTriggered(PACKAGE_NAME, DEVICE_NAME)
/** Helper method providing default parameters to not clutter up the tests. */
private fun transferToThisDeviceTriggered() =
- TransferToThisDeviceTriggered(appIconDrawable, APP_ICON_CONTENT_DESC)
+ TransferToThisDeviceTriggered(PACKAGE_NAME)
/** Helper method providing default parameters to not clutter up the tests. */
private fun transferToReceiverSucceeded(undoCallback: IUndoMediaTransferCallback? = null) =
TransferToReceiverSucceeded(
- appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME, undoCallback
+ PACKAGE_NAME, DEVICE_NAME, undoCallback
)
/** Helper method providing default parameters to not clutter up the tests. */
private fun transferToThisDeviceSucceeded(undoCallback: IUndoMediaTransferCallback? = null) =
TransferToThisDeviceSucceeded(
- appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME, undoCallback
+ PACKAGE_NAME, DEVICE_NAME, undoCallback
)
/** Helper method providing default parameters to not clutter up the tests. */
- private fun transferFailed() = TransferFailed(appIconDrawable, APP_ICON_CONTENT_DESC)
+ private fun transferFailed() = TransferFailed(PACKAGE_NAME)
}
private const val DEVICE_NAME = "My Tablet"
-private const val APP_ICON_CONTENT_DESC = "Content description"
+private const val PACKAGE_NAME = "com.android.systemui"
private val routeInfo = MediaRoute2Info.Builder("id", "Test Name")
.addFeature("feature")
+ .setPackageName(PACKAGE_NAME)
.build()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java
deleted file mode 100644
index 84776c7..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright (C) 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 com.android.systemui.qs;
-
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_MORE_SETTINGS;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.RunWithLooper;
-import android.testing.ViewUtils;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.testing.UiEventLoggerFake;
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.plugins.qs.DetailAdapter;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
-@SmallTest
-public class QSDetailTest extends SysuiTestCase {
-
- private MetricsLogger mMetricsLogger;
- private QSDetail mQsDetail;
- private QSPanelController mQsPanelController;
- private QuickStatusBarHeader mQuickHeader;
- private ActivityStarter mActivityStarter;
- private DetailAdapter mMockDetailAdapter;
- private TestableLooper mTestableLooper;
- private UiEventLoggerFake mUiEventLogger;
- private FrameLayout mParent;
-
- @Before
- public void setup() throws Exception {
- mTestableLooper = TestableLooper.get(this);
- mUiEventLogger = QSEvents.INSTANCE.setLoggerForTesting();
-
- mParent = new FrameLayout(mContext);
- mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
- mActivityStarter = mDependency.injectMockDependency(ActivityStarter.class);
- LayoutInflater.from(mContext).inflate(R.layout.qs_detail, mParent);
- mQsDetail = (QSDetail) mParent.getChildAt(0);
-
- mQsPanelController = mock(QSPanelController.class);
- mQuickHeader = mock(QuickStatusBarHeader.class);
- mQsDetail.setQsPanel(mQsPanelController, mQuickHeader, mock(QSFooter.class),
- mock(FalsingManager.class));
- mQsDetail.mClipper = mock(QSDetailClipper.class);
-
- mMockDetailAdapter = mock(DetailAdapter.class);
- when(mMockDetailAdapter.createDetailView(any(), any(), any()))
- .thenReturn(new View(mContext));
-
- // Only detail in use is the user detail
- when(mMockDetailAdapter.openDetailEvent())
- .thenReturn(QSUserSwitcherEvent.QS_USER_DETAIL_OPEN);
- when(mMockDetailAdapter.closeDetailEvent())
- .thenReturn(QSUserSwitcherEvent.QS_USER_DETAIL_CLOSE);
- when(mMockDetailAdapter.moreSettingsEvent())
- .thenReturn(QSUserSwitcherEvent.QS_USER_MORE_SETTINGS);
- ViewUtils.attachView(mParent);
- }
-
- @After
- public void tearDown() {
- QSEvents.INSTANCE.resetLogger();
- mTestableLooper.processAllMessages();
- ViewUtils.detachView(mParent);
- }
-
- @Test
- public void testShowDetail_Metrics() {
- mTestableLooper.processAllMessages();
-
- mQsDetail.handleShowingDetail(mMockDetailAdapter, 0, 0, false);
- verify(mMetricsLogger).visible(eq(mMockDetailAdapter.getMetricsCategory()));
- assertEquals(1, mUiEventLogger.numLogs());
- assertEquals(QSUserSwitcherEvent.QS_USER_DETAIL_OPEN.getId(), mUiEventLogger.eventId(0));
- mUiEventLogger.getLogs().clear();
-
- mQsDetail.handleShowingDetail(null, 0, 0, false);
- verify(mMetricsLogger).hidden(eq(mMockDetailAdapter.getMetricsCategory()));
-
- assertEquals(1, mUiEventLogger.numLogs());
- assertEquals(QSUserSwitcherEvent.QS_USER_DETAIL_CLOSE.getId(), mUiEventLogger.eventId(0));
- }
-
- @Test
- public void testShowDetail_ShouldAnimate() {
- mTestableLooper.processAllMessages();
-
- when(mMockDetailAdapter.shouldAnimate()).thenReturn(true);
- mQsDetail.setFullyExpanded(true);
-
- mQsDetail.handleShowingDetail(mMockDetailAdapter, 0, 0, false);
- verify(mQsDetail.mClipper).updateCircularClip(eq(true) /* animate */, anyInt(), anyInt(),
- eq(true) /* in */, any());
- clearInvocations(mQsDetail.mClipper);
-
- mQsDetail.handleShowingDetail(null, 0, 0, false);
- verify(mQsDetail.mClipper).updateCircularClip(eq(true) /* animate */, anyInt(), anyInt(),
- eq(false) /* in */, any());
- }
-
- @Test
- public void testShowDetail_ShouldNotAnimate() {
- mTestableLooper.processAllMessages();
-
- when(mMockDetailAdapter.shouldAnimate()).thenReturn(false);
- mQsDetail.setFullyExpanded(true);
-
- mQsDetail.handleShowingDetail(mMockDetailAdapter, 0, 0, false);
- verify(mQsDetail.mClipper).updateCircularClip(eq(false) /* animate */, anyInt(), anyInt(),
- eq(true) /* in */, any());
- clearInvocations(mQsDetail.mClipper);
-
- // Detail adapters should always animate on close. shouldAnimate() should only affect the
- // open transition
- mQsDetail.handleShowingDetail(null, 0, 0, false);
- verify(mQsDetail.mClipper).updateCircularClip(eq(true) /* animate */, anyInt(), anyInt(),
- eq(false) /* in */, any());
- }
-
- @Test
- public void testDoneButton_CloseDetailPanel() {
- mTestableLooper.processAllMessages();
-
- when(mMockDetailAdapter.onDoneButtonClicked()).thenReturn(false);
-
- mQsDetail.handleShowingDetail(mMockDetailAdapter, 0, 0, false);
- mQsDetail.requireViewById(android.R.id.button1).performClick();
- verify(mQsPanelController).closeDetail();
- }
-
- @Test
- public void testDoneButton_KeepDetailPanelOpen() {
- mTestableLooper.processAllMessages();
-
- when(mMockDetailAdapter.onDoneButtonClicked()).thenReturn(true);
-
- mQsDetail.handleShowingDetail(mMockDetailAdapter, 0, 0, false);
- mQsDetail.requireViewById(android.R.id.button1).performClick();
- verify(mQsPanelController, never()).closeDetail();
- }
-
- @Test
- public void testMoreSettingsButton() {
- mTestableLooper.processAllMessages();
-
- mQsDetail.handleShowingDetail(mMockDetailAdapter, 0, 0, false);
- mUiEventLogger.getLogs().clear();
- mQsDetail.requireViewById(android.R.id.button2).performClick();
-
- int metricsCategory = mMockDetailAdapter.getMetricsCategory();
- verify(mMetricsLogger).action(eq(ACTION_QS_MORE_SETTINGS), eq(metricsCategory));
- assertEquals(1, mUiEventLogger.numLogs());
- assertEquals(QSUserSwitcherEvent.QS_USER_MORE_SETTINGS.getId(), mUiEventLogger.eventId(0));
-
- verify(mActivityStarter).postStartActivityDismissingKeyguard(any(), anyInt());
- }
-
- @Test
- public void testNullAdapterClick() {
- DetailAdapter mock = mock(DetailAdapter.class);
- when(mock.moreSettingsEvent()).thenReturn(DetailAdapter.INVALID);
- mQsDetail.setupDetailFooter(mock);
- mQsDetail.requireViewById(android.R.id.button2).performClick();
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index 3266d6a..4ab3926 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -146,7 +146,6 @@
mock(QSLogger.class), mock(UiEventLogger.class), mock(UserTracker.class),
mock(SecureSettings.class), mock(CustomTileStatePersister.class),
mTileServiceRequestControllerBuilder, mock(TileLifecycleManager.Factory.class));
- qs.setHost(host);
qs.setListening(true);
processAllMessages();
@@ -186,7 +185,6 @@
mock(QSTileHost.class),
mock(StatusBarStateController.class),
commandQueue,
- new QSDetailDisplayer(),
mQSMediaHost,
mQQSMediaHost,
mBypassController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java
deleted file mode 100644
index b2ca62f..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java
+++ /dev/null
@@ -1,151 +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 com.android.systemui.qs;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper.RunWithLooper;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.UiEventLogger;
-import com.android.internal.logging.testing.UiEventLoggerFake;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.classifier.FalsingManagerFake;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.media.MediaHost;
-import com.android.systemui.plugins.qs.QSTileView;
-import com.android.systemui.qs.customize.QSCustomizerController;
-import com.android.systemui.qs.logging.QSLogger;
-import com.android.systemui.qs.tileimpl.QSTileImpl;
-import com.android.systemui.settings.brightness.BrightnessController;
-import com.android.systemui.settings.brightness.BrightnessSliderController;
-import com.android.systemui.settings.brightness.ToggleSlider;
-import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.tuner.TunerService;
-import com.android.systemui.util.animation.DisappearParameters;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.Collections;
-
-@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
-@SmallTest
-public class QSPanelControllerTest extends SysuiTestCase {
-
- @Mock
- private QSPanel mQSPanel;
- @Mock
- private QSTileHost mQSTileHost;
- @Mock
- private QSCustomizerController mQSCustomizerController;
- @Mock
- private QSTileRevealController.Factory mQSTileRevealControllerFactory;
- @Mock
- private QSTileRevealController mQSTileRevealController;
- @Mock
- private MediaHost mMediaHost;
- @Mock
- private MetricsLogger mMetricsLogger;
- private UiEventLogger mUiEventLogger = new UiEventLoggerFake();
- private DumpManager mDumpManager = new DumpManager();
- @Mock
- private TunerService mTunerService;
- @Mock
- private QSFgsManagerFooter mQSFgsManagerFooter;
- @Mock
- private QSSecurityFooter mQSSecurityFooter;
- @Mock
- private QSLogger mQSLogger;
- @Mock
- private BrightnessController.Factory mBrightnessControllerFactory;
- @Mock
- private BrightnessController mBrightnessController;
- @Mock
- private BrightnessSliderController.Factory mToggleSliderViewControllerFactory;
- @Mock
- private BrightnessSliderController mBrightnessSliderController;
- @Mock
- QSTileImpl mQSTile;
- @Mock
- QSTileView mQSTileView;
- @Mock
- PagedTileLayout mPagedTileLayout;
- @Mock
- CommandQueue mCommandQueue;
- FalsingManagerFake mFalsingManager = new FalsingManagerFake();
- @Mock
- Resources mResources;
- @Mock
- Configuration mConfiguration;
- @Mock
- FeatureFlags mFeatureFlags;
-
- private QSPanelController mController;
-
- @Before
- public void setup() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- when(mQSPanel.isAttachedToWindow()).thenReturn(true);
- when(mQSPanel.getDumpableTag()).thenReturn("QSPanel");
- when(mQSPanel.getOrCreateTileLayout()).thenReturn(mPagedTileLayout);
- when(mQSPanel.getTileLayout()).thenReturn(mPagedTileLayout);
- when(mQSPanel.getResources()).thenReturn(mResources);
- when(mResources.getConfiguration()).thenReturn(mConfiguration);
- when(mQSTileHost.getTiles()).thenReturn(Collections.singleton(mQSTile));
- when(mQSTileHost.createTileView(any(), eq(mQSTile), anyBoolean())).thenReturn(mQSTileView);
- when(mToggleSliderViewControllerFactory.create(any(), any()))
- .thenReturn(mBrightnessSliderController);
- when(mBrightnessControllerFactory.create(any(ToggleSlider.class)))
- .thenReturn(mBrightnessController);
- when(mQSTileRevealControllerFactory.create(any(), any()))
- .thenReturn(mQSTileRevealController);
- when(mMediaHost.getDisappearParameters()).thenReturn(new DisappearParameters());
-
- mController = new QSPanelController(mQSPanel, mQSFgsManagerFooter, mQSSecurityFooter,
- mTunerService, mQSTileHost, mQSCustomizerController, true, mMediaHost,
- mQSTileRevealControllerFactory, mDumpManager, mMetricsLogger, mUiEventLogger,
- mQSLogger, mBrightnessControllerFactory, mToggleSliderViewControllerFactory,
- mFalsingManager, mCommandQueue, mFeatureFlags
- );
-
- mController.init();
- }
-
- @Test
- public void testOpenDetailsWithNonExistingTile_NoException() {
- mController.openDetails("none");
-
- verify(mQSPanel, never()).openDetails(any());
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
index 4ae19332..5213a30 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
@@ -36,10 +36,7 @@
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyBoolean
-import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
-import org.mockito.Mockito.never
-import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import org.mockito.Mockito.`when` as whenever
@@ -64,9 +61,6 @@
private lateinit var mParentView: ViewGroup
@Mock
- private lateinit var mCallback: QSDetail.Callback
-
- @Mock
private lateinit var mQSTileView: QSTileView
private lateinit var mFooter: View
@@ -97,29 +91,10 @@
whenever(mHost.tiles).thenReturn(emptyList())
whenever(mHost.createTileView(any(), any(), anyBoolean())).thenReturn(mQSTileView)
mQsPanel.addTile(mDndTileRecord)
- mQsPanel.setCallback(mCallback)
}
}
@Test
- fun testOpenDetailsWithExistingTile_NoException() {
- mTestableLooper.runWithLooper {
- mQsPanel.openDetails(dndTile)
- }
-
- verify(mCallback).onShowingDetail(any(), anyInt(), anyInt())
- }
-
- @Test
- fun testOpenDetailsWithNullParameter_NoException() {
- mTestableLooper.runWithLooper {
- mQsPanel.openDetails(null)
- }
-
- verify(mCallback, never()).onShowingDetail(any(), anyInt(), anyInt())
- }
-
- @Test
fun testSecurityFooter_appearsOnBottomOnSplitShade() {
mQsPanel.onConfigurationChanged(getNewOrientationConfig(ORIENTATION_LANDSCAPE))
mQsPanel.switchSecurityFooter(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSBrightnessControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSBrightnessControllerTest.kt
deleted file mode 100644
index de1d86b..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSBrightnessControllerTest.kt
+++ /dev/null
@@ -1,118 +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.systemui.qs
-
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.settings.brightness.BrightnessController
-import com.android.systemui.statusbar.policy.BrightnessMirrorController
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-import org.mockito.Mock
-import org.mockito.Mockito.times
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.never
-import org.mockito.Mockito.mock
-import org.mockito.junit.MockitoJUnit
-
-@SmallTest
-class QuickQSBrightnessControllerTest : SysuiTestCase() {
-
- @Mock
- lateinit var brightnessController: BrightnessController
- @get:Rule
- val mockito = MockitoJUnit.rule()
-
- lateinit var quickQSBrightnessController: QuickQSBrightnessController
-
- @Before
- fun setUp() {
- quickQSBrightnessController = QuickQSBrightnessController(
- brightnessControllerFactory = { brightnessController })
- }
-
- @Test
- fun testSliderIsShownWhenInitializedInSplitShade() {
- quickQSBrightnessController.init(shouldUseSplitNotificationShade = true)
-
- verify(brightnessController).showSlider()
- }
-
- @Test
- fun testSliderIsShownWhenRefreshedInSplitShade() {
- quickQSBrightnessController.refreshVisibility(shouldUseSplitNotificationShade = true)
-
- verify(brightnessController, times(1)).showSlider()
- }
-
- @Test
- fun testSliderIsHiddenWhenRefreshedInNonSplitShade() {
- // needs to be shown first
- quickQSBrightnessController.refreshVisibility(shouldUseSplitNotificationShade = true)
- quickQSBrightnessController.refreshVisibility(shouldUseSplitNotificationShade = false)
-
- verify(brightnessController).hideSlider()
- }
-
- @Test
- fun testSliderChangesVisibilityWhenRotating() {
- quickQSBrightnessController.refreshVisibility(shouldUseSplitNotificationShade = true)
- verify(brightnessController, times(1)).showSlider()
-
- quickQSBrightnessController.refreshVisibility(shouldUseSplitNotificationShade = false)
- verify(brightnessController, times(1)).hideSlider()
- }
-
- @Test
- fun testCallbacksAreRegisteredOnlyOnce() {
- // this flow simulates expanding shade in portrait...
- quickQSBrightnessController.setListening(true)
- quickQSBrightnessController.refreshVisibility(shouldUseSplitNotificationShade = false)
- // ... and rotating to landscape/split shade where slider is visible
- quickQSBrightnessController.refreshVisibility(shouldUseSplitNotificationShade = true)
-
- verify(brightnessController, times(1)).registerCallbacks()
- }
-
- @Test
- fun testCallbacksAreRegisteredOnlyOnceWhenRotatingPhone() {
- quickQSBrightnessController.setListening(true)
- quickQSBrightnessController.refreshVisibility(shouldUseSplitNotificationShade = true)
- quickQSBrightnessController.refreshVisibility(shouldUseSplitNotificationShade = false)
- quickQSBrightnessController.refreshVisibility(shouldUseSplitNotificationShade = true)
-
- verify(brightnessController, times(1)).registerCallbacks()
- }
-
- @Test
- fun testCallbacksAreNotRegisteredWhenSliderNotVisible() {
- quickQSBrightnessController.setListening(true)
- quickQSBrightnessController.refreshVisibility(shouldUseSplitNotificationShade = false)
-
- verify(brightnessController, never()).registerCallbacks()
- }
-
- @Test
- fun testMirrorIsSetWhenSliderIsShown() {
- val mirrorController = mock(BrightnessMirrorController::class.java)
- quickQSBrightnessController.setMirror(mirrorController)
- quickQSBrightnessController.refreshVisibility(shouldUseSplitNotificationShade = true)
-
- verify(brightnessController).setMirror(mirrorController)
- }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
index 1eb16fd..62915b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
@@ -71,8 +71,6 @@
private lateinit var tileLayout: TileLayout
@Mock
private lateinit var tileView: QSTileView
- @Mock
- private lateinit var quickQsBrightnessController: QuickQSBrightnessController
@Captor
private lateinit var captor: ArgumentCaptor<QSPanel.OnConfigurationChangedListener>
@@ -100,8 +98,7 @@
metricsLogger,
uiEventLogger,
qsLogger,
- dumpManager,
- quickQsBrightnessController
+ dumpManager
)
controller.init()
@@ -133,16 +130,6 @@
}
@Test
- fun testBrightnessRefreshedWhenConfigurationChanged() {
- // times(2) because both controller and base controller are registering their listeners
- verify(quickQSPanel, times(2)).addOnConfigurationChangedListener(captor.capture())
-
- captor.allValues.forEach { it.onConfigurationChange(Configuration.EMPTY) }
-
- verify(quickQsBrightnessController).refreshVisibility(anyBoolean())
- }
-
- @Test
fun testMediaExpansionUpdatedWhenConfigurationChanged() {
`when`(mediaFlags.useMediaSessionLayout()).thenReturn(true)
@@ -171,11 +158,10 @@
metricsLogger: MetricsLogger,
uiEventLogger: UiEventLoggerFake,
qsLogger: QSLogger,
- dumpManager: DumpManager,
- quickQSBrightnessController: QuickQSBrightnessController
+ dumpManager: DumpManager
) : QuickQSPanelController(view, qsTileHost, qsCustomizerController, usingMediaPlayer,
mediaHost, usingCollapsedLandscapeMedia, mediaFlags, metricsLogger, uiEventLogger, qsLogger,
- dumpManager, quickQSBrightnessController) {
+ dumpManager) {
private var rotation = RotationUtils.ROTATION_NONE
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
index 8b7346d..30b464b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
@@ -53,7 +53,6 @@
import com.android.internal.logging.InstanceId;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSIconView;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.QSTileHost;
@@ -420,11 +419,5 @@
@Override
public void destroy() {}
-
-
- @Override
- public DetailAdapter getDetailAdapter() {
- return null;
- }
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceRequestControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceRequestControllerTest.kt
index a1c60a6..bdfbca4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceRequestControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceRequestControllerTest.kt
@@ -20,6 +20,7 @@
import android.content.ComponentName
import android.content.DialogInterface
import android.graphics.drawable.Icon
+import android.os.RemoteException
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
@@ -275,11 +276,89 @@
assertThat(c.lastAccepted).isEqualTo(TileServiceRequestController.TILE_ALREADY_ADDED)
}
+ @Test
+ fun interfaceThrowsRemoteException_doesntCrash() {
+ val cancelListenerCaptor =
+ ArgumentCaptor.forClass(DialogInterface.OnCancelListener::class.java)
+ val captor = ArgumentCaptor.forClass(CommandQueue.Callbacks::class.java)
+ verify(commandQueue, atLeastOnce()).addCallback(capture(captor))
+
+ val callback = object : IAddTileResultCallback.Stub() {
+ override fun onTileRequest(p0: Int) {
+ throw RemoteException()
+ }
+ }
+ captor.value.requestAddTile(TEST_COMPONENT, TEST_APP_NAME, TEST_LABEL, icon, callback)
+ verify(tileRequestDialog).setOnCancelListener(capture(cancelListenerCaptor))
+
+ cancelListenerCaptor.value.onCancel(tileRequestDialog)
+ }
+
+ @Test
+ fun testDismissDialogResponse() {
+ val dismissListenerCaptor =
+ ArgumentCaptor.forClass(DialogInterface.OnDismissListener::class.java)
+
+ val callback = Callback()
+ controller.requestTileAdd(TEST_COMPONENT, TEST_APP_NAME, TEST_LABEL, icon, callback)
+ verify(tileRequestDialog).setOnDismissListener(capture(dismissListenerCaptor))
+
+ dismissListenerCaptor.value.onDismiss(tileRequestDialog)
+ assertThat(callback.lastAccepted).isEqualTo(TileServiceRequestController.DISMISSED)
+ }
+
+ @Test
+ fun addTileAndThenDismissSendsOnlyAddTile() {
+ // After clicking, the dialog is dismissed. This tests that only one response
+ // is sent (the first one)
+ val dismissListenerCaptor =
+ ArgumentCaptor.forClass(DialogInterface.OnDismissListener::class.java)
+ val clickListenerCaptor =
+ ArgumentCaptor.forClass(DialogInterface.OnClickListener::class.java)
+
+ val callback = Callback()
+ controller.requestTileAdd(TEST_COMPONENT, TEST_APP_NAME, TEST_LABEL, icon, callback)
+ verify(tileRequestDialog).setPositiveButton(anyInt(), capture(clickListenerCaptor))
+ verify(tileRequestDialog).setOnDismissListener(capture(dismissListenerCaptor))
+
+ clickListenerCaptor.value.onClick(tileRequestDialog, DialogInterface.BUTTON_POSITIVE)
+ dismissListenerCaptor.value.onDismiss(tileRequestDialog)
+
+ assertThat(callback.lastAccepted).isEqualTo(TileServiceRequestController.ADD_TILE)
+ assertThat(callback.timesCalled).isEqualTo(1)
+ }
+
+ @Test
+ fun cancelAndThenDismissSendsOnlyOnce() {
+ // After cancelling, the dialog is dismissed. This tests that only one response
+ // is sent.
+ val dismissListenerCaptor =
+ ArgumentCaptor.forClass(DialogInterface.OnDismissListener::class.java)
+ val cancelListenerCaptor =
+ ArgumentCaptor.forClass(DialogInterface.OnCancelListener::class.java)
+
+ val callback = Callback()
+ controller.requestTileAdd(TEST_COMPONENT, TEST_APP_NAME, TEST_LABEL, icon, callback)
+ verify(tileRequestDialog).setOnCancelListener(capture(cancelListenerCaptor))
+ verify(tileRequestDialog).setOnDismissListener(capture(dismissListenerCaptor))
+
+ cancelListenerCaptor.value.onCancel(tileRequestDialog)
+ dismissListenerCaptor.value.onDismiss(tileRequestDialog)
+
+ assertThat(callback.lastAccepted).isEqualTo(TileServiceRequestController.DISMISSED)
+ assertThat(callback.timesCalled).isEqualTo(1)
+ }
+
private class Callback : IAddTileResultCallback.Stub(), Consumer<Int> {
var lastAccepted: Int? = null
private set
+
+ var timesCalled = 0
+ private set
+
override fun accept(t: Int) {
lastAccepted = t
+ timesCalled++
}
override fun onTileRequest(r: Int) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt
index 88b133e..0f2c264 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt
@@ -48,7 +48,6 @@
import com.android.systemui.qs.tiles.RotationLockTile
import com.android.systemui.qs.tiles.ScreenRecordTile
import com.android.systemui.qs.tiles.UiModeNightTile
-import com.android.systemui.qs.tiles.UserTile
import com.android.systemui.qs.tiles.WifiTile
import com.android.systemui.qs.tiles.WorkModeTile
import com.android.systemui.util.leak.GarbageMonitor
@@ -76,7 +75,6 @@
"location" to LocationTile::class.java,
"cast" to CastTile::class.java,
"hotspot" to HotspotTile::class.java,
- "user" to UserTile::class.java,
"battery" to BatterySaverTile::class.java,
"saver" to DataSaverTile::class.java,
"night" to NightDisplayTile::class.java,
@@ -115,7 +113,6 @@
@Mock private lateinit var locationTile: LocationTile
@Mock private lateinit var castTile: CastTile
@Mock private lateinit var hotspotTile: HotspotTile
- @Mock private lateinit var userTile: UserTile
@Mock private lateinit var batterySaverTile: BatterySaverTile
@Mock private lateinit var dataSaverTile: DataSaverTile
@Mock private lateinit var nightDisplayTile: NightDisplayTile
@@ -159,7 +156,6 @@
{ locationTile },
{ castTile },
{ hotspotTile },
- { userTile },
{ batterySaverTile },
{ dataSaverTile },
{ nightDisplayTile },
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
index 3a3d154..9b0142d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
@@ -147,5 +147,6 @@
current,
false /* isAddUser */,
false /* isRestricted */,
- true /* isSwitchToEnabled */)
+ true /* isSwitchToEnabled */,
+ false /* isAddSupervisedUser */)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
index c20e887..ed35dcb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
@@ -29,6 +29,7 @@
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
import com.android.wifitrackerlib.WifiEntry;
@@ -68,6 +69,8 @@
private InternetAdapter mInternetAdapter;
@Mock
private InternetDialogController mInternetDialogController;
+ @Mock
+ private KeyguardStateController mKeyguard;
private FakeExecutor mBgExecutor = new FakeExecutor(new FakeSystemClock());
private InternetDialog mInternetDialog;
@@ -100,7 +103,7 @@
mInternetDialog = new InternetDialog(mContext, mock(InternetDialogFactory.class),
mInternetDialogController, true, true, true, mock(UiEventLogger.class), mHandler,
- mBgExecutor);
+ mBgExecutor, mKeyguard);
mInternetDialog.mAdapter = mInternetAdapter;
mInternetDialog.mConnectedWifiEntry = mInternetWifiEntry;
mInternetDialog.mWifiEntriesCount = mWifiEntries.size();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt
index b7fdc1a..8695b29 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt
@@ -22,11 +22,13 @@
import android.testing.AndroidTestingRunner
import android.view.View
import androidx.test.filters.SmallTest
+import com.android.internal.logging.UiEventLogger
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.qs.PseudoGridView
+import com.android.systemui.qs.QSUserSwitcherEvent
import com.android.systemui.qs.tiles.UserDetailView
import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.util.mockito.any
@@ -62,6 +64,8 @@
private lateinit var launchView: View
@Mock
private lateinit var dialogLaunchAnimator: DialogLaunchAnimator
+ @Mock
+ private lateinit var uiEventLogger: UiEventLogger
@Captor
private lateinit var clickCaptor: ArgumentCaptor<DialogInterface.OnClickListener>
@@ -79,6 +83,7 @@
activityStarter,
falsingManager,
dialogLaunchAnimator,
+ uiEventLogger,
{ dialog }
)
}
@@ -87,6 +92,7 @@
fun showDialog_callsDialogShow() {
controller.showDialog(launchView)
verify(dialogLaunchAnimator).showFromView(dialog, launchView)
+ verify(uiEventLogger).log(QSUserSwitcherEvent.QS_USER_DETAIL_OPEN)
}
@Test
@@ -108,10 +114,14 @@
}
@Test
- fun doneButtonSetWithNullHandler() {
+ fun doneButtonLogsCorrectly() {
controller.showDialog(launchView)
- verify(dialog).setPositiveButton(anyInt(), eq(null))
+ verify(dialog).setPositiveButton(anyInt(), capture(clickCaptor))
+
+ clickCaptor.value.onClick(dialog, DialogInterface.BUTTON_NEUTRAL)
+
+ verify(uiEventLogger).log(QSUserSwitcherEvent.QS_USER_DETAIL_CLOSE)
}
@Test
@@ -129,6 +139,7 @@
argThat(IntentMatcher(Settings.ACTION_USER_SETTINGS)),
eq(0)
)
+ verify(uiEventLogger).log(QSUserSwitcherEvent.QS_USER_MORE_SETTINGS)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/VersionInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/VersionInfoTest.java
index 218e7db..711187b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/VersionInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/VersionInfoTest.java
@@ -22,7 +22,6 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.OverlayPlugin;
import com.android.systemui.plugins.annotations.Requires;
-import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.qs.QS.HeightListener;
import com.android.systemui.shared.plugins.VersionInfo.InvalidVersionException;
@@ -99,7 +98,6 @@
@Requires(target = QS.class, version = QS.VERSION)
@Requires(target = HeightListener.class, version = HeightListener.VERSION)
- @Requires(target = DetailAdapter.class, version = DetailAdapter.VERSION)
public static class QSImpl {
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 98e2857..466d954 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -229,8 +229,8 @@
mController = new KeyguardIndicationController(mContext, mWakeLockBuilder,
mKeyguardStateController, mStatusBarStateController, mKeyguardUpdateMonitor,
mDockManager, mBroadcastDispatcher, mDevicePolicyManager, mIBatteryStats,
- mUserManager, mExecutor, mFalsingManager, mLockPatternUtils, mScreenLifecycle,
- mIActivityManager, mKeyguardBypassController);
+ mUserManager, mExecutor, mExecutor, mFalsingManager, mLockPatternUtils,
+ mScreenLifecycle, mIActivityManager, mKeyguardBypassController);
mController.init();
mController.setIndicationArea(mIndicationArea);
verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
@@ -244,6 +244,9 @@
verify(mKeyguardStateController).addCallback(
mKeyguardStateControllerCallbackCaptor.capture());
mKeyguardStateControllerCallback = mKeyguardStateControllerCallbackCaptor.getValue();
+
+ mExecutor.runAllReady();
+ reset(mRotateTextViewController);
}
@Test
@@ -328,9 +331,11 @@
@Test
public void disclosure_unmanaged() {
createController();
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
when(mDevicePolicyManager.isDeviceManaged()).thenReturn(false);
when(mDevicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile()).thenReturn(false);
sendUpdateDisclosureBroadcast();
+ mExecutor.runAllReady();
verifyHideIndication(INDICATION_TYPE_DISCLOSURE);
}
@@ -338,9 +343,11 @@
@Test
public void disclosure_deviceOwner_noOrganizationName() {
createController();
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(null);
sendUpdateDisclosureBroadcast();
+ mExecutor.runAllReady();
verifyIndicationMessage(INDICATION_TYPE_DISCLOSURE, mDisclosureGeneric);
}
@@ -348,11 +355,13 @@
@Test
public void disclosure_orgOwnedDeviceWithManagedProfile_noOrganizationName() {
createController();
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
when(mDevicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile()).thenReturn(true);
when(mUserManager.getProfiles(anyInt())).thenReturn(Collections.singletonList(
new UserInfo(10, /* name */ null, /* flags */ FLAG_MANAGED_PROFILE)));
when(mDevicePolicyManager.getOrganizationNameForUser(eq(10))).thenReturn(null);
sendUpdateDisclosureBroadcast();
+ mExecutor.runAllReady();
verifyIndicationMessage(INDICATION_TYPE_DISCLOSURE, mDisclosureGeneric);
}
@@ -360,9 +369,11 @@
@Test
public void disclosure_deviceOwner_withOrganizationName() {
createController();
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(ORGANIZATION_NAME);
sendUpdateDisclosureBroadcast();
+ mExecutor.runAllReady();
verifyIndicationMessage(INDICATION_TYPE_DISCLOSURE, mDisclosureWithOrganization);
}
@@ -370,23 +381,27 @@
@Test
public void disclosure_orgOwnedDeviceWithManagedProfile_withOrganizationName() {
createController();
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
when(mDevicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile()).thenReturn(true);
when(mUserManager.getProfiles(anyInt())).thenReturn(Collections.singletonList(
new UserInfo(10, /* name */ null, FLAG_MANAGED_PROFILE)));
when(mDevicePolicyManager.getOrganizationNameForUser(eq(10))).thenReturn(ORGANIZATION_NAME);
sendUpdateDisclosureBroadcast();
+ mExecutor.runAllReady();
verifyIndicationMessage(INDICATION_TYPE_DISCLOSURE, mDisclosureWithOrganization);
}
@Test
public void disclosure_updateOnTheFly() {
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
when(mDevicePolicyManager.isDeviceManaged()).thenReturn(false);
createController();
when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(null);
sendUpdateDisclosureBroadcast();
+ mExecutor.runAllReady();
verifyIndicationMessage(INDICATION_TYPE_DISCLOSURE, mDisclosureGeneric);
reset(mRotateTextViewController);
@@ -394,12 +409,14 @@
when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(ORGANIZATION_NAME);
sendUpdateDisclosureBroadcast();
+ mExecutor.runAllReady();
verifyIndicationMessage(INDICATION_TYPE_DISCLOSURE, mDisclosureWithOrganization);
reset(mRotateTextViewController);
when(mDevicePolicyManager.isDeviceManaged()).thenReturn(false);
sendUpdateDisclosureBroadcast();
+ mExecutor.runAllReady();
verifyHideIndication(INDICATION_TYPE_DISCLOSURE);
}
@@ -408,11 +425,13 @@
public void disclosure_deviceOwner_financedDeviceWithOrganizationName() {
createController();
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(ORGANIZATION_NAME);
when(mDevicePolicyManager.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
.thenReturn(DEVICE_OWNER_TYPE_FINANCED);
sendUpdateDisclosureBroadcast();
+ mExecutor.runAllReady();
verifyIndicationMessage(INDICATION_TYPE_DISCLOSURE, mFinancedDisclosureWithOrganization);
}
@@ -729,11 +748,13 @@
public void testEmptyOwnerInfoHidesIndicationArea() {
createController();
- // GIVEN the owner info is set to an empty string
+ // GIVEN the owner info is set to an empty string & keyguard is showing
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
when(mLockPatternUtils.getDeviceOwnerInfo()).thenReturn("");
// WHEN asked to update the indication area
mController.setVisible(true);
+ mExecutor.runAllReady();
// THEN the owner info should be hidden
verifyHideIndication(INDICATION_TYPE_OWNER_INFO);
@@ -763,6 +784,7 @@
// WHEN keyguard showing changed called
mKeyguardStateControllerCallback.onKeyguardShowingChanged();
+ mExecutor.runAllReady();
// THEN persistent messages are updated (in this case, most messages are hidden since
// no info is provided) - verify that this happens
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
index 8c5f04f..5e11858 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
@@ -37,6 +37,7 @@
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -55,6 +56,7 @@
@Mock private NotificationHandler mNotificationHandler;
@Mock private NotificationManager mNotificationManager;
+ @Mock private PluginManager mPluginManager;
private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
private final FakeExecutor mFakeExecutor = new FakeExecutor(mFakeSystemClock);
@@ -70,7 +72,8 @@
mContext,
mNotificationManager,
mFakeSystemClock,
- mFakeExecutor);
+ mFakeExecutor,
+ mPluginManager);
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
new Notification(), UserHandle.CURRENT, null, 0);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
index a5ea897..6abdea5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
@@ -23,14 +23,18 @@
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.statusbar.StatusBarStateController
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyFloat
import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import org.mockito.Mockito.`when` as whenever
@@ -73,4 +77,14 @@
assertEquals(StatusBarStateEvent.STATUS_BAR_STATE_SHADE.id, ids[1])
assertEquals(StatusBarStateEvent.STATUS_BAR_STATE_SHADE_LOCKED.id, ids[2])
}
+
+ @Test
+ fun testSetDozeAmountInternal_onlySetsOnce() {
+ val listener = mock(StatusBarStateController.StateListener::class.java)
+ controller.addCallback(listener)
+
+ controller.setDozeAmount(0.5f, false /* animated */)
+ controller.setDozeAmount(0.5f, false /* animated */)
+ verify(listener).onDozeAmountChanged(eq(0.5f), anyFloat())
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
index 60c3bc8..2e1297b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
@@ -81,6 +81,8 @@
@Mock
HeadsUpManager mHeadsUpManager;
@Mock
+ NotificationInterruptLogger mLogger;
+ @Mock
BatteryController mBatteryController;
@Mock
Handler mMockHandler;
@@ -101,6 +103,7 @@
mBatteryController,
mStatusBarStateController,
mHeadsUpManager,
+ mLogger,
mMockHandler);
mNotifInterruptionStateProvider.mUseHeadsUp = true;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
index d280f54..5d16036 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
@@ -36,14 +36,14 @@
setFractionToShade(0f)
setOnLockscreen(true)
- shelf.updateStateWidth(shelfState, /* fraction */ 0f, /* shortestWidth */ 10)
- assertTrue(shelfState.actualWidth == 10)
+ shelf.updateActualWidth(/* fractionToShade */ 0f, /* shortestWidth */ 10f);
+ assertTrue(shelf.actualWidth == 10)
- shelf.updateStateWidth(shelfState, /* fraction */ 0.5f, /* shortestWidth */ 10)
- assertTrue(shelfState.actualWidth == 20)
+ shelf.updateActualWidth(/* fractionToShade */ 0.5f, /* shortestWidth */ 10f)
+ assertTrue(shelf.actualWidth == 20)
- shelf.updateStateWidth(shelfState, /* fraction */ 1f, /* shortestWidth */ 10)
- assertTrue(shelfState.actualWidth == 30)
+ shelf.updateActualWidth(/* fractionToShade */ 1f, /* shortestWidth */ 10f)
+ assertTrue(shelf.actualWidth == 30)
}
@Test
@@ -51,8 +51,8 @@
setFractionToShade(0f)
setOnLockscreen(false)
- shelf.updateStateWidth(shelfState, /* fraction */ 0f, /* shortestWidth */ 10)
- assertTrue(shelfState.actualWidth == 30)
+ shelf.updateActualWidth(/* fraction */ 0f, /* shortestWidth */ 10f)
+ assertTrue(shelf.actualWidth == 30)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index fb232ba..ed144fa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -126,10 +126,9 @@
.thenReturn(true);
when(mAuthController.isUdfpsFingerDown()).thenReturn(false);
when(mKeyguardBypassController.canPlaySubtleWindowAnimations()).thenReturn(true);
- mContext.addMockSystemService(PowerManager.class, mPowerManager);
mDependency.injectTestDependency(NotificationMediaManager.class, mMediaManager);
res.addOverride(com.android.internal.R.integer.config_wakeUpDelayDoze, 0);
- mBiometricUnlockController = new BiometricUnlockController(mContext, mDozeScrimController,
+ mBiometricUnlockController = new BiometricUnlockController(mDozeScrimController,
mKeyguardViewMediator, mScrimController, mShadeController,
mNotificationShadeWindowController, mKeyguardStateController, mHandler,
mUpdateMonitor, res.getResources(), mKeyguardBypassController, mDozeParameters,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
index e9590b0..ed22cd3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
@@ -40,6 +40,7 @@
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.policy.Clock;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.Assert;
@@ -47,6 +48,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Optional;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@@ -76,7 +79,6 @@
mDependency,
TestableLooper.get(this));
mFirst = testHelper.createRow();
- mDependency.injectTestDependency(DarkIconDispatcher.class, mDarkIconDispatcher);
mHeadsUpStatusBarView = new HeadsUpStatusBarView(mContext, mock(View.class),
mock(TextView.class));
mHeadsUpManager = mock(HeadsUpManagerPhone.class);
@@ -92,13 +94,14 @@
mStatusbarStateController,
mBypassController,
mWakeUpCoordinator,
+ mDarkIconDispatcher,
mKeyguardStateController,
mCommandQueue,
mStackScrollerController,
mPanelView,
mHeadsUpStatusBarView,
- new View(mContext),
- mOperatorNameView);
+ new Clock(mContext, null),
+ Optional.of(mOperatorNameView));
mHeadsUpAppearanceController.setAppearFraction(0.0f, 0.0f);
}
@@ -173,13 +176,14 @@
mStatusbarStateController,
mBypassController,
mWakeUpCoordinator,
+ mDarkIconDispatcher,
mKeyguardStateController,
mCommandQueue,
mStackScrollerController,
mPanelView,
mHeadsUpStatusBarView,
- new View(mContext),
- new View(mContext));
+ new Clock(mContext, null),
+ Optional.empty());
Assert.assertEquals(expandedHeight, newController.mExpandedHeight, 0.0f);
Assert.assertEquals(appearFraction, newController.mAppearFraction, 0.0f);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
index 7e33c01..cc4abfc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
@@ -20,6 +20,8 @@
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
+import static junit.framework.Assert.assertTrue;
+
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
@@ -41,6 +43,9 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+import java.util.ArrayList;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -91,7 +96,9 @@
mLightBarController.onStatusBarAppearanceChanged(
appearanceRegions, true /* sbModeChanged */, MODE_TRANSPARENT,
false /* navbarColorManagedByIme */);
- verify(mStatusBarIconController).setIconsDarkArea(eq(firstBounds));
+ ArgumentCaptor<ArrayList<Rect>> captor = ArgumentCaptor.forClass(ArrayList.class);
+ verify(mStatusBarIconController).setIconsDarkArea(captor.capture());
+ assertTrue(captor.getValue().contains(firstBounds));
verify(mLightBarTransitionsController).setIconsDark(eq(true), anyBoolean());
}
@@ -106,7 +113,29 @@
mLightBarController.onStatusBarAppearanceChanged(
appearanceRegions, true /* sbModeChanged */, MODE_TRANSPARENT,
false /* navbarColorManagedByIme */);
- verify(mStatusBarIconController).setIconsDarkArea(eq(secondBounds));
+ ArgumentCaptor<ArrayList<Rect>> captor = ArgumentCaptor.forClass(ArrayList.class);
+ verify(mStatusBarIconController).setIconsDarkArea(captor.capture());
+ assertTrue(captor.getValue().contains(secondBounds));
+ verify(mLightBarTransitionsController).setIconsDark(eq(true), anyBoolean());
+ }
+
+ @Test
+ public void testOnStatusBarAppearanceChanged_multipleStacks_oneStackLightMultipleStackDark() {
+ final Rect firstBounds = new Rect(0, 0, 1, 1);
+ final Rect secondBounds = new Rect(1, 0, 2, 1);
+ final Rect thirdBounds = new Rect(2, 0, 3, 1);
+ final AppearanceRegion[] appearanceRegions = new AppearanceRegion[]{
+ new AppearanceRegion(APPEARANCE_LIGHT_STATUS_BARS, firstBounds),
+ new AppearanceRegion(0 /* appearance */, secondBounds),
+ new AppearanceRegion(APPEARANCE_LIGHT_STATUS_BARS, thirdBounds)
+ };
+ mLightBarController.onStatusBarAppearanceChanged(
+ appearanceRegions, true /* sbModeChanged */, MODE_TRANSPARENT,
+ false /* navbarColorManagedByIme */);
+ ArgumentCaptor<ArrayList<Rect>> captor = ArgumentCaptor.forClass(ArrayList.class);
+ verify(mStatusBarIconController).setIconsDarkArea(captor.capture());
+ assertTrue(captor.getValue().contains(firstBounds));
+ assertTrue(captor.getValue().contains(thirdBounds));
verify(mLightBarTransitionsController).setIconsDark(eq(true), anyBoolean());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
index c13b335..7070bc1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
@@ -78,6 +78,7 @@
@Mock private NotificationEntryManager mNotificationEntryManager;
@Mock private RowContentBindStage mBindStage;
@Mock PeopleNotificationIdentifier mPeopleNotificationIdentifier;
+ @Mock StatusBarStateController mStatusBarStateController;
@Captor private ArgumentCaptor<NotificationEntryListener> mListenerCaptor;
private NotificationEntryListener mNotificationEntryListener;
private final HashMap<String, NotificationEntry> mPendingEntries = new HashMap<>();
@@ -94,7 +95,7 @@
.thenReturn(mPendingEntries.values());
mGroupManager = new NotificationGroupManagerLegacy(
- mock(StatusBarStateController.class),
+ mStatusBarStateController,
() -> mPeopleNotificationIdentifier,
Optional.of(mock(Bubbles.class)),
mock(DumpManager.class));
@@ -103,7 +104,8 @@
when(mBindStage.getStageParams(any())).thenReturn(new RowContentBindParams());
- mGroupAlertTransferHelper = new NotificationGroupAlertTransferHelper(mBindStage);
+ mGroupAlertTransferHelper = new NotificationGroupAlertTransferHelper(
+ mBindStage, mStatusBarStateController, mGroupManager);
mGroupAlertTransferHelper.setHeadsUpManager(mHeadsUpManager);
mGroupAlertTransferHelper.bind(mNotificationEntryManager, mGroupManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
index 7347565..f6eff82 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
@@ -106,10 +106,10 @@
import com.android.systemui.media.KeyguardMediaController;
import com.android.systemui.media.MediaDataManager;
import com.android.systemui.media.MediaHierarchyManager;
+import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.qrcodescanner.controller.QRCodeScannerController;
-import com.android.systemui.qs.QSDetailDisplayer;
import com.android.systemui.screenrecord.RecordingController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardAffordanceView;
@@ -272,8 +272,6 @@
@Mock
private IdleHostViewController mIdleHostViewController;
@Mock
- private QSDetailDisplayer mQSDetailDisplayer;
- @Mock
private KeyguardStatusViewComponent mKeyguardStatusViewComponent;
@Mock
private KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory;
@@ -366,6 +364,8 @@
private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
@Mock
private NotificationShadeWindowController mNotificationShadeWindowController;
+ @Mock
+ private SysUiState mSysUiState;
private Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty();
private SysuiStatusBarStateController mStatusBarStateController;
private NotificationPanelViewController mNotificationPanelViewController;
@@ -525,7 +525,6 @@
mCommunalViewComponentFactory,
mIdleViewComponentFactory,
mLockscreenShadeTransitionController,
- mQSDetailDisplayer,
mGroupManager,
mNotificationAreaController,
mAuthController,
@@ -555,6 +554,7 @@
mControlsComponent,
mInteractionJankMonitor,
mQsFrameTranslateController,
+ mSysUiState,
mKeyguardUnlockAnimationController);
mNotificationPanelViewController.initDependencies(
mStatusBar,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 90b93e7..a7809c2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -130,6 +130,7 @@
import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource;
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.init.NotificationsController;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerFake;
@@ -309,6 +310,7 @@
mPowerManager,
mDreamManager, mAmbientDisplayConfiguration, mNotificationFilter,
mStatusBarStateController, mBatteryController, mHeadsUpManager,
+ mock(NotificationInterruptLogger.class),
new Handler(TestableLooper.get(this).getLooper()));
mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class));
@@ -994,9 +996,10 @@
StatusBarStateController controller,
BatteryController batteryController,
HeadsUpManager headsUpManager,
+ NotificationInterruptLogger logger,
Handler mainHandler) {
super(contentResolver, powerManager, dreamManager, ambientDisplayConfiguration, filter,
- batteryController, controller, headsUpManager, mainHandler);
+ batteryController, controller, headsUpManager, logger, mainHandler);
mUseHeadsUp = true;
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt
index a57f6a1..4a579cb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt
@@ -27,26 +27,22 @@
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.CommunalStateController
-import com.android.systemui.flags.FeatureFlags
import com.android.systemui.keyguard.ScreenLifecycle
import com.android.systemui.plugins.FalsingManager
-import com.android.systemui.qs.tiles.UserDetailView
import com.android.systemui.qs.user.UserSwitchDialogController
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.phone.DozeParameters
import com.android.systemui.statusbar.phone.LockscreenGestureLogger
-import com.android.systemui.statusbar.phone.NotificationPanelViewController
import com.android.systemui.statusbar.phone.ScreenOffAnimationController
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
+import org.mockito.Mockito.`when`
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
-import javax.inject.Provider
@SmallTest
@TestableLooper.RunWithLooper
@@ -77,23 +73,14 @@
private lateinit var dozeParameters: DozeParameters
@Mock
- private lateinit var userDetailViewAdapterProvider: Provider<UserDetailView.Adapter>
-
- @Mock
private lateinit var screenOffAnimationController: ScreenOffAnimationController
@Mock
- private lateinit var featureFlags: FeatureFlags
-
- @Mock
private lateinit var userSwitchDialogController: UserSwitchDialogController
@Mock
private lateinit var uiEventLogger: UiEventLogger
- @Mock
- private lateinit var notificationPanelViewController: NotificationPanelViewController
-
private lateinit var view: FrameLayout
private lateinit var testableLooper: TestableLooper
private lateinit var keyguardQsUserSwitchController: KeyguardQsUserSwitchController
@@ -118,16 +105,12 @@
configurationController,
statusBarStateController,
dozeParameters,
- userDetailViewAdapterProvider,
screenOffAnimationController,
- featureFlags,
userSwitchDialogController,
uiEventLogger)
ViewUtils.attachView(view)
testableLooper.processAllMessages()
- keyguardQsUserSwitchController
- .setNotificationPanelViewController(notificationPanelViewController)
`when`(userSwitcherController.keyguardStateController).thenReturn(keyguardStateController)
`when`(userSwitcherController.keyguardStateController.isShowing).thenReturn(true)
keyguardQsUserSwitchController.init()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
index e479882..0dd6cbb7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
@@ -193,5 +193,6 @@
isCurrentUser,
false /* isAddUser */,
false /* isRestricted */,
- true /* isSwitchToEnabled */)
+ true /* isSwitchToEnabled */,
+ false /* isAddSupervisedUser */)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
index 9a7e702..07e0279 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.policy
import android.app.IActivityManager
-import android.app.IActivityTaskManager
import android.app.admin.DevicePolicyManager
import android.content.Context
import android.content.DialogInterface
@@ -49,13 +48,15 @@
import com.android.systemui.qs.user.UserSwitchDialogController
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.phone.NotificationShadeWindowView
+import com.android.systemui.statusbar.phone.ShadeController
import com.android.systemui.telephony.TelephonyListenerManager
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.settings.SecureSettings
import com.android.systemui.util.time.FakeSystemClock
import org.junit.Assert.assertEquals
-import org.junit.Assert.assertNotNull
import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNotNull
+import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -84,8 +85,6 @@
@Mock private lateinit var userManager: UserManager
@Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
- @Mock private lateinit var activityTaskManager: IActivityTaskManager
- @Mock private lateinit var userDetailAdapter: UserSwitcherController.UserDetailAdapter
@Mock private lateinit var telephonyListenerManager: TelephonyListenerManager
@Mock private lateinit var secureSettings: SecureSettings
@Mock private lateinit var falsingManager: FalsingManager
@@ -96,8 +95,10 @@
@Mock private lateinit var notificationShadeWindowView: NotificationShadeWindowView
@Mock private lateinit var threadedRenderer: ThreadedRenderer
@Mock private lateinit var dialogLaunchAnimator: DialogLaunchAnimator
+ @Mock private lateinit var shadeController: ShadeController
private lateinit var testableLooper: TestableLooper
- private lateinit var uiBgExecutor: FakeExecutor
+ private lateinit var bgExecutor: FakeExecutor
+ private lateinit var uiExecutor: FakeExecutor
private lateinit var uiEventLogger: UiEventLoggerFake
private lateinit var userSwitcherController: UserSwitcherController
private lateinit var picture: Bitmap
@@ -116,10 +117,11 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
testableLooper = TestableLooper.get(this)
- uiBgExecutor = FakeExecutor(FakeSystemClock())
+ bgExecutor = FakeExecutor(FakeSystemClock())
+ uiExecutor = FakeExecutor(FakeSystemClock())
uiEventLogger = UiEventLoggerFake()
- context.orCreateTestableResources.addOverride(
+ mContext.orCreateTestableResources.addOverride(
com.android.internal.R.bool.config_guestUserAutoCreated, false)
mContext.addMockSystemService(Context.FACE_SERVICE, mock(FaceManager::class.java))
@@ -130,8 +132,27 @@
.thenReturn(true)
`when`(notificationShadeWindowView.context).thenReturn(context)
+ // Since userSwitcherController involves InteractionJankMonitor.
+ // Let's fulfill the dependencies.
+ val mockedContext = mock(Context::class.java)
+ doReturn(mockedContext).`when`(notificationShadeWindowView).context
+ doReturn(true).`when`(notificationShadeWindowView).isAttachedToWindow
+ doNothing().`when`(threadedRenderer).addObserver(any())
+ doNothing().`when`(threadedRenderer).removeObserver(any())
+ doReturn(threadedRenderer).`when`(notificationShadeWindowView).threadedRenderer
+
+ picture = UserIcons.convertToBitmap(context.getDrawable(R.drawable.ic_avatar_user))
+
+ // Create defaults for the current user
+ `when`(userTracker.userId).thenReturn(ownerId)
+ `when`(userTracker.userInfo).thenReturn(ownerInfo)
+
+ setupController()
+ }
+
+ private fun setupController() {
userSwitcherController = UserSwitcherController(
- context,
+ mContext,
activityManager,
userManager,
userTracker,
@@ -144,27 +165,14 @@
uiEventLogger,
falsingManager,
telephonyListenerManager,
- activityTaskManager,
- userDetailAdapter,
secureSettings,
- uiBgExecutor,
+ bgExecutor,
+ uiExecutor,
interactionJankMonitor,
latencyTracker,
dumpManager,
+ { shadeController },
dialogLaunchAnimator)
- userSwitcherController.mPauseRefreshUsers = true
-
- // Since userSwitcherController involves InteractionJankMonitor.
- // Let's fulfill the dependencies.
- val mockedContext = mock(Context::class.java)
- doReturn(mockedContext).`when`(notificationShadeWindowView).context
- doReturn(true).`when`(notificationShadeWindowView).isAttachedToWindow
- doNothing().`when`(threadedRenderer).addObserver(any())
- doNothing().`when`(threadedRenderer).removeObserver(any())
- doReturn(threadedRenderer).`when`(notificationShadeWindowView).threadedRenderer
- userSwitcherController.init(notificationShadeWindowView)
-
- picture = UserIcons.convertToBitmap(context.getDrawable(R.drawable.ic_avatar_user))
userSwitcherController.init(notificationShadeWindowView)
}
@@ -177,7 +185,8 @@
false /* current */,
false /* isAddUser */,
false /* isRestricted */,
- true /* isSwitchToEnabled */)
+ true /* isSwitchToEnabled */,
+ false /* isAddSupervisedUser */)
`when`(userTracker.userId).thenReturn(ownerId)
`when`(userTracker.userInfo).thenReturn(ownerInfo)
@@ -196,7 +205,8 @@
false /* current */,
false /* isAddUser */,
false /* isRestricted */,
- true /* isSwitchToEnabled */)
+ true /* isSwitchToEnabled */,
+ false /* isAddSupervisedUser */)
`when`(userTracker.userId).thenReturn(ownerId)
`when`(userTracker.userInfo).thenReturn(ownerInfo)
@@ -220,7 +230,8 @@
false /* current */,
false /* isAddUser */,
false /* isRestricted */,
- true /* isSwitchToEnabled */)
+ true /* isSwitchToEnabled */,
+ false /* isAddSupervisedUser */)
`when`(userTracker.userId).thenReturn(ownerId)
`when`(userTracker.userInfo).thenReturn(ownerInfo)
@@ -240,7 +251,8 @@
true /* current */,
false /* isAddUser */,
false /* isRestricted */,
- true /* isSwitchToEnabled */)
+ true /* isSwitchToEnabled */,
+ false /* isAddSupervisedUser */)
`when`(userTracker.userId).thenReturn(guestInfo.id)
`when`(userTracker.userInfo).thenReturn(guestInfo)
@@ -262,7 +274,8 @@
true /* current */,
false /* isAddUser */,
false /* isRestricted */,
- true /* isSwitchToEnabled */)
+ true /* isSwitchToEnabled */,
+ false /* isAddSupervisedUser */)
`when`(userTracker.userId).thenReturn(guestInfo.id)
`when`(userTracker.userInfo).thenReturn(guestInfo)
@@ -283,7 +296,8 @@
true /* current */,
false /* isAddUser */,
false /* isRestricted */,
- true /* isSwitchToEnabled */)
+ true /* isSwitchToEnabled */,
+ false /* isAddSupervisedUser */)
`when`(userTracker.userId).thenReturn(guestInfo.id)
`when`(userTracker.userInfo).thenReturn(guestInfo)
@@ -302,7 +316,8 @@
true /* current */,
false /* isAddUser */,
false /* isRestricted */,
- true /* isSwitchToEnabled */)
+ true /* isSwitchToEnabled */,
+ false /* isAddSupervisedUser */)
`when`(userTracker.userId).thenReturn(guestId)
`when`(userTracker.userInfo).thenReturn(guestInfo)
@@ -323,7 +338,8 @@
false /* current */,
false /* isAddUser */,
false /* isRestricted */,
- true /* isSwitchToEnabled */)
+ true /* isSwitchToEnabled */,
+ false /* isAddSupervisedUser */)
`when`(userTracker.userId).thenReturn(guestId)
`when`(userTracker.userInfo).thenReturn(guestInfo)
@@ -357,7 +373,8 @@
false /* current */,
false /* isAddUser */,
false /* isRestricted */,
- true /* isSwitchToEnabled */)
+ true /* isSwitchToEnabled */,
+ false /* isAddSupervisedUser */)
`when`(userTracker.userId).thenReturn(guestId)
`when`(userTracker.userInfo).thenReturn(guestInfo)
@@ -389,7 +406,7 @@
userSwitcherController.users.add(UserSwitcherController.UserRecord(
UserInfo(id, name, 0),
null, false, isCurrent, false,
- false, false
+ false, false, false
))
}
val bgUserName = "background_user"
@@ -412,4 +429,42 @@
`when`(userTracker.userId).thenReturn(1)
assertEquals(false, userSwitcherController.isSystemUser)
}
+
+ @Test
+ fun testCanCreateSupervisedUserWithConfiguredPackage() {
+ // GIVEN the supervised user creation package is configured
+ `when`(context.getString(
+ com.android.internal.R.string.config_supervisedUserCreationPackage))
+ .thenReturn("some_pkg")
+
+ // AND the current user is allowed to create new users
+ `when`(userTracker.userId).thenReturn(ownerId)
+ `when`(userTracker.userInfo).thenReturn(ownerInfo)
+
+ // WHEN the controller is started with the above config
+ setupController()
+ testableLooper.processAllMessages()
+
+ // THEN a supervised user can be constructed
+ assertTrue(userSwitcherController.canCreateSupervisedUser())
+ }
+
+ @Test
+ fun testCannotCreateSupervisedUserWithConfiguredPackage() {
+ // GIVEN the supervised user creation package is NOT configured
+ `when`(context.getString(
+ com.android.internal.R.string.config_supervisedUserCreationPackage))
+ .thenReturn(null)
+
+ // AND the current user is allowed to create new users
+ `when`(userTracker.userId).thenReturn(ownerId)
+ `when`(userTracker.userInfo).thenReturn(ownerInfo)
+
+ // WHEN the controller is started with the above config
+ setupController()
+ testableLooper.processAllMessages()
+
+ // THEN a supervised user can NOT be constructed
+ assertFalse(userSwitcherController.canCreateSupervisedUser())
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionMonitorTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionMonitorTest.java
index d645449..5118637 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionMonitorTest.java
@@ -17,6 +17,7 @@
package com.android.systemui.util.condition;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
@@ -24,16 +25,21 @@
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.Arrays;
@@ -46,6 +52,7 @@
private FakeCondition mCondition2;
private FakeCondition mCondition3;
private HashSet<Condition> mConditions;
+ private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
private Monitor mConditionMonitor;
@@ -58,7 +65,83 @@
mCondition3 = spy(new FakeCondition());
mConditions = new HashSet<>(Arrays.asList(mCondition1, mCondition2, mCondition3));
- mConditionMonitor = new Monitor(mConditions, null /*callbacks*/);
+ mConditionMonitor = new Monitor(mExecutor, mConditions, null /*callbacks*/);
+ }
+
+ @Test
+ public void testOverridingCondition() {
+ final Condition overridingCondition = Mockito.mock(Condition.class);
+ final Condition regularCondition = Mockito.mock(Condition.class);
+ final Monitor.Callback callback = Mockito.mock(Monitor.Callback.class);
+
+ final Monitor monitor = new Monitor(
+ mExecutor,
+ new HashSet<>(Arrays.asList(overridingCondition, regularCondition)),
+ new HashSet<>(Arrays.asList(callback)));
+
+ when(overridingCondition.isOverridingCondition()).thenReturn(true);
+ when(overridingCondition.isConditionMet()).thenReturn(true);
+ when(regularCondition.isConditionMet()).thenReturn(false);
+
+ final ArgumentCaptor<Condition.Callback> mCallbackCaptor =
+ ArgumentCaptor.forClass(Condition.Callback.class);
+
+ verify(overridingCondition).addCallback(mCallbackCaptor.capture());
+
+ mCallbackCaptor.getValue().onConditionChanged(overridingCondition);
+ mExecutor.runAllReady();
+
+ verify(callback).onConditionsChanged(eq(true));
+ Mockito.clearInvocations(callback);
+
+ when(regularCondition.isConditionMet()).thenReturn(true);
+ when(overridingCondition.isConditionMet()).thenReturn(false);
+
+ mCallbackCaptor.getValue().onConditionChanged(overridingCondition);
+ mExecutor.runAllReady();
+
+ verify(callback).onConditionsChanged(eq(false));
+
+ clearInvocations(callback);
+ monitor.removeCondition(overridingCondition);
+ mExecutor.runAllReady();
+
+ verify(callback).onConditionsChanged(eq(true));
+ }
+
+ /**
+ * Ensures that when multiple overriding conditions are present, it is the aggregate of those
+ * conditions that are considered.
+ */
+ @Test
+ public void testMultipleOverridingConditions() {
+ final Condition overridingCondition = Mockito.mock(Condition.class);
+ final Condition overridingCondition2 = Mockito.mock(Condition.class);
+ final Condition regularCondition = Mockito.mock(Condition.class);
+ final Monitor.Callback callback = Mockito.mock(Monitor.Callback.class);
+
+ final Monitor monitor = new Monitor(
+ mExecutor,
+ new HashSet<>(Arrays.asList(overridingCondition, overridingCondition2,
+ regularCondition)),
+ new HashSet<>(Arrays.asList(callback)));
+
+ when(overridingCondition.isOverridingCondition()).thenReturn(true);
+ when(overridingCondition.isConditionMet()).thenReturn(true);
+ when(overridingCondition2.isOverridingCondition()).thenReturn(true);
+ when(overridingCondition.isConditionMet()).thenReturn(false);
+ when(regularCondition.isConditionMet()).thenReturn(true);
+
+ final ArgumentCaptor<Condition.Callback> mCallbackCaptor =
+ ArgumentCaptor.forClass(Condition.Callback.class);
+
+ verify(overridingCondition).addCallback(mCallbackCaptor.capture());
+
+ mCallbackCaptor.getValue().onConditionChanged(overridingCondition);
+ mExecutor.runAllReady();
+
+ verify(callback).onConditionsChanged(eq(false));
+ Mockito.clearInvocations(callback);
}
@Test
@@ -66,11 +149,13 @@
final Monitor.Callback callback1 =
mock(Monitor.Callback.class);
mConditionMonitor.addCallback(callback1);
+ mExecutor.runAllReady();
mConditions.forEach(condition -> verify(condition).addCallback(any()));
final Monitor.Callback callback2 =
mock(Monitor.Callback.class);
mConditionMonitor.addCallback(callback2);
+ mExecutor.runAllReady();
mConditions.forEach(condition -> verify(condition, times(1)).addCallback(any()));
}
@@ -79,6 +164,7 @@
final Monitor.Callback callback =
mock(Monitor.Callback.class);
mConditionMonitor.addCallback(callback);
+ mExecutor.runAllReady();
verify(callback).onConditionsChanged(false);
}
@@ -86,38 +172,68 @@
public void addCallback_addSecondCallback_reportWithExistingValue() {
final Monitor.Callback callback1 =
mock(Monitor.Callback.class);
- mConditionMonitor.addCallback(callback1);
-
- mConditionMonitor.overrideAllConditionsMet(true);
+ final Condition condition = mock(Condition.class);
+ when(condition.isConditionMet()).thenReturn(true);
+ final Monitor monitor = new Monitor(mExecutor, new HashSet<>(Arrays.asList(condition)),
+ new HashSet<>(Arrays.asList(callback1)));
final Monitor.Callback callback2 =
mock(Monitor.Callback.class);
- mConditionMonitor.addCallback(callback2);
- verify(callback2).onConditionsChanged(true);
+ monitor.addCallback(callback2);
+ mExecutor.runAllReady();
+ verify(callback2).onConditionsChanged(eq(true));
}
@Test
public void addCallback_noConditions_reportAllConditionsMet() {
- final Monitor monitor = new Monitor(new HashSet<>(), null /*callbacks*/);
+ final Monitor monitor = new Monitor(mExecutor, new HashSet<>(), null /*callbacks*/);
final Monitor.Callback callback = mock(Monitor.Callback.class);
monitor.addCallback(callback);
-
+ mExecutor.runAllReady();
verify(callback).onConditionsChanged(true);
}
@Test
+ public void addCallback_withMultipleInstancesOfTheSameCallback_registerOnlyOne() {
+ final Monitor monitor = new Monitor(mExecutor, new HashSet<>(), null /*callbacks*/);
+ final Monitor.Callback callback = mock(Monitor.Callback.class);
+
+ // Adds the same instance multiple times.
+ monitor.addCallback(callback);
+ monitor.addCallback(callback);
+ monitor.addCallback(callback);
+ mExecutor.runAllReady();
+
+ // Callback should only be triggered once.
+ verify(callback, times(1)).onConditionsChanged(true);
+ }
+
+ @Test
public void removeCallback_shouldNoLongerReceiveUpdate() {
+ final Condition condition = mock(Condition.class);
+ final Monitor monitor = new Monitor(mExecutor, new HashSet<>(Arrays.asList(condition)),
+ null);
final Monitor.Callback callback =
mock(Monitor.Callback.class);
- mConditionMonitor.addCallback(callback);
+ monitor.addCallback(callback);
+ monitor.removeCallback(callback);
+ mExecutor.runAllReady();
clearInvocations(callback);
- mConditionMonitor.removeCallback(callback);
- mConditionMonitor.overrideAllConditionsMet(true);
+ final ArgumentCaptor<Condition.Callback> conditionCallbackCaptor =
+ ArgumentCaptor.forClass(Condition.Callback.class);
+ verify(condition).addCallback(conditionCallbackCaptor.capture());
+ final Condition.Callback conditionCallback = conditionCallbackCaptor.getValue();
+
+ when(condition.isConditionMet()).thenReturn(true);
+ conditionCallback.onConditionChanged(condition);
+ mExecutor.runAllReady();
verify(callback, never()).onConditionsChanged(true);
- mConditionMonitor.overrideAllConditionsMet(false);
+ when(condition.isConditionMet()).thenReturn(false);
+ conditionCallback.onConditionChanged(condition);
+ mExecutor.runAllReady();
verify(callback, never()).onConditionsChanged(false);
}
@@ -131,9 +247,11 @@
mConditionMonitor.addCallback(callback2);
mConditionMonitor.removeCallback(callback1);
+ mExecutor.runAllReady();
mConditions.forEach(condition -> verify(condition, never()).removeCallback(any()));
mConditionMonitor.removeCallback(callback2);
+ mExecutor.runAllReady();
mConditions.forEach(condition -> verify(condition).removeCallback(any()));
}
@@ -147,6 +265,7 @@
mCondition1.fakeUpdateCondition(true);
mCondition2.fakeUpdateCondition(true);
mCondition3.fakeUpdateCondition(true);
+ mExecutor.runAllReady();
verify(callback).onConditionsChanged(true);
}
@@ -163,6 +282,7 @@
clearInvocations(callback);
mCondition1.fakeUpdateCondition(false);
+ mExecutor.runAllReady();
verify(callback).onConditionsChanged(false);
}
@@ -171,16 +291,20 @@
final Monitor.Callback callback =
mock(Monitor.Callback.class);
mConditionMonitor.addCallback(callback);
+ mExecutor.runAllReady();
verify(callback).onConditionsChanged(false);
clearInvocations(callback);
mCondition1.fakeUpdateCondition(true);
+ mExecutor.runAllReady();
verify(callback, never()).onConditionsChanged(anyBoolean());
mCondition2.fakeUpdateCondition(true);
+ mExecutor.runAllReady();
verify(callback, never()).onConditionsChanged(anyBoolean());
mCondition3.fakeUpdateCondition(true);
+ mExecutor.runAllReady();
verify(callback).onConditionsChanged(true);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionTest.java
index 7fc6b51..9e0f863 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionTest.java
@@ -16,7 +16,8 @@
package com.android.systemui.util.condition;
-import static org.mockito.ArgumentMatchers.anyBoolean;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -73,7 +74,8 @@
final Condition.Callback callback2 = mock(Condition.Callback.class);
mCondition.addCallback(callback2);
- verify(callback2).onConditionChanged(mCondition, true);
+ verify(callback2).onConditionChanged(mCondition);
+ assertThat(mCondition.isConditionMet()).isTrue();
}
@Test
@@ -94,7 +96,8 @@
mCondition.addCallback(callback);
mCondition.fakeUpdateCondition(true);
- verify(callback).onConditionChanged(eq(mCondition), eq(true));
+ verify(callback).onConditionChanged(eq(mCondition));
+ assertThat(mCondition.isConditionMet()).isTrue();
}
@Test
@@ -105,7 +108,8 @@
mCondition.addCallback(callback);
mCondition.fakeUpdateCondition(false);
- verify(callback).onConditionChanged(eq(mCondition), eq(false));
+ verify(callback).onConditionChanged(eq(mCondition));
+ assertThat(mCondition.isConditionMet()).isFalse();
}
@Test
@@ -116,7 +120,7 @@
mCondition.addCallback(callback);
mCondition.fakeUpdateCondition(true);
- verify(callback, never()).onConditionChanged(eq(mCondition), anyBoolean());
+ verify(callback, never()).onConditionChanged(eq(mCondition));
}
@Test
@@ -127,6 +131,6 @@
mCondition.addCallback(callback);
mCondition.fakeUpdateCondition(false);
- verify(callback, never()).onConditionChanged(eq(mCondition), anyBoolean());
+ verify(callback, never()).onConditionChanged(eq(mCondition));
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index ca37a40..4bc4e6e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -96,6 +96,7 @@
import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
import com.android.systemui.statusbar.phone.DozeParameters;
@@ -334,6 +335,7 @@
mock(StatusBarStateController.class),
mock(BatteryController.class),
mock(HeadsUpManager.class),
+ mock(NotificationInterruptLogger.class),
mock(Handler.class)
);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
index d82671d..75d8453 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
@@ -82,6 +82,7 @@
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
import com.android.systemui.statusbar.phone.DozeParameters;
@@ -300,6 +301,7 @@
mock(StatusBarStateController.class),
mock(BatteryController.class),
mock(HeadsUpManager.class),
+ mock(NotificationInterruptLogger.class),
mock(Handler.class)
);
when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java
index 7847c57..e698f1e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java
@@ -24,6 +24,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationFilter;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -40,6 +41,7 @@
StatusBarStateController statusBarStateController,
BatteryController batteryController,
HeadsUpManager headsUpManager,
+ NotificationInterruptLogger logger,
Handler mainHandler) {
super(contentResolver,
powerManager,
@@ -49,6 +51,7 @@
batteryController,
statusBarStateController,
headsUpManager,
+ logger,
mainHandler);
mUseHeadsUp = true;
}
diff --git a/services/Android.bp b/services/Android.bp
index 0189303..e010469 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -23,6 +23,7 @@
"-Xep:FormatString:ERROR",
"-Xep:ArrayHashCode:ERROR",
"-Xep:SelfAssignment:ERROR",
+ "-Xep:ArrayEquals:ERROR",
// NOTE: only enable to generate local patchfiles
// "-XepPatchChecks:refaster:frameworks/base/errorprone/refaster/EfficientXml.java.refaster",
// "-XepPatchLocation:/tmp/refaster/",
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 8b62a64..7f10314 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -25,6 +25,7 @@
import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_SERVICE_CLIENT;
import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_SERVICE_CONNECTION;
import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAGER_INTERNAL;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
import static android.view.accessibility.AccessibilityInteractionClient.CALL_STACK;
import static android.view.accessibility.AccessibilityInteractionClient.IGNORE_CALL_STACK;
@@ -66,6 +67,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.Trace;
import android.provider.Settings;
import android.util.Slog;
import android.util.SparseArray;
@@ -80,15 +82,21 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityWindowInfo;
import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputBinding;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.compat.IPlatformCompat;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.internal.view.IInputContext;
+import com.android.internal.view.IInputMethodSession;
+import com.android.internal.view.IInputSessionWithIdCallback;
import com.android.server.LocalServices;
import com.android.server.accessibility.AccessibilityWindowManager.RemoteAccessibilityConnection;
import com.android.server.accessibility.magnification.MagnificationProcessor;
+import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
@@ -180,6 +188,8 @@
boolean mLastAccessibilityButtonCallbackState;
+ boolean mRequestImeApis;
+
int mFetchFlags;
long mNotificationTimeout;
@@ -271,6 +281,9 @@
void onDoubleTapAndHold(int displayId);
+ void requestImeLocked(AccessibilityServiceConnection connection);
+
+ void unbindImeLocked(AccessibilityServiceConnection connection);
}
public AbstractAccessibilityServiceConnection(Context context, ComponentName componentName,
@@ -374,6 +387,9 @@
& AccessibilityServiceInfo.FLAG_REQUEST_FINGERPRINT_GESTURES) != 0;
mRequestAccessibilityButton = (info.flags
& AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
+ // TODO(b/218193835): request ime when ime flag is set and clean up when ime flag is unset
+ mRequestImeApis = (info.flags
+ & AccessibilityServiceInfo.FLAG_INPUT_METHOD_EDITOR) != 0;
}
protected boolean supportsFlagForNotImportantViews(AccessibilityServiceInfo info) {
@@ -1610,6 +1626,27 @@
mInvocationHandler.notifyAccessibilityButtonAvailabilityChangedLocked(available);
}
+ public void createImeSessionLocked() {
+ mInvocationHandler.createImeSessionLocked();
+ }
+
+ public void setImeSessionEnabledLocked(IInputMethodSession session, boolean enabled) {
+ mInvocationHandler.setImeSessionEnabledLocked(session, enabled);
+ }
+
+ public void bindInputLocked(InputBinding binding) {
+ mInvocationHandler.bindInputLocked(binding);
+ }
+
+ public void unbindInputLocked() {
+ mInvocationHandler.unbindInputLocked();
+ }
+
+ public void startInputLocked(IBinder startInputToken, IInputContext inputContext,
+ EditorInfo editorInfo, boolean restarting) {
+ mInvocationHandler.startInputLocked(startInputToken, inputContext, editorInfo, restarting);
+ }
+
/**
* Called by the invocation handler to notify the service that the
* state of magnification has changed.
@@ -1732,6 +1769,84 @@
}
}
+ private void createImeSessionInternal() {
+ final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
+ if (listener != null) {
+ try {
+ if (svcClientTracingEnabled()) {
+ logTraceSvcClient("createImeSession", "");
+ }
+ AccessibilityCallback callback = new AccessibilityCallback();
+ listener.createImeSession(callback);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG,
+ "Error requesting IME session from " + mService, re);
+ }
+ }
+ }
+
+ private void setImeSessionEnabledInternal(IInputMethodSession session, boolean enabled) {
+ final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
+ if (listener != null && session != null) {
+ try {
+ if (svcClientTracingEnabled()) {
+ logTraceSvcClient("createImeSession", "");
+ }
+ listener.setImeSessionEnabled(session, enabled);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG,
+ "Error requesting IME session from " + mService, re);
+ }
+ }
+ }
+
+ private void bindInputInternal(InputBinding binding) {
+ final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
+ if (listener != null) {
+ try {
+ if (svcClientTracingEnabled()) {
+ logTraceSvcClient("bindInput", binding.toString());
+ }
+ listener.bindInput(binding);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG,
+ "Error binding input to " + mService, re);
+ }
+ }
+ }
+
+ private void unbindInputInternal() {
+ final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
+ if (listener != null) {
+ try {
+ if (svcClientTracingEnabled()) {
+ logTraceSvcClient("unbindInput", "");
+ }
+ listener.unbindInput();
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG,
+ "Error unbinding input to " + mService, re);
+ }
+ }
+ }
+
+ private void startInputInternal(IBinder startInputToken, IInputContext inputContext,
+ EditorInfo editorInfo, boolean restarting) {
+ final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
+ if (listener != null) {
+ try {
+ if (svcClientTracingEnabled()) {
+ logTraceSvcClient("startInput", startInputToken + " "
+ + inputContext + " " + editorInfo + restarting);
+ }
+ listener.startInput(startInputToken, inputContext, editorInfo, restarting);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG,
+ "Error starting input to " + mService, re);
+ }
+ }
+ }
+
protected IAccessibilityServiceClient getServiceInterfaceSafely() {
synchronized (mLock) {
return mServiceInterface;
@@ -1925,6 +2040,11 @@
private static final int MSG_ON_ACCESSIBILITY_BUTTON_CLICKED = 7;
private static final int MSG_ON_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED = 8;
private static final int MSG_ON_SYSTEM_ACTIONS_CHANGED = 9;
+ private static final int MSG_CREATE_IME_SESSION = 10;
+ private static final int MSG_SET_IME_SESSION_ENABLED = 11;
+ private static final int MSG_BIND_INPUT = 12;
+ private static final int MSG_UNBIND_INPUT = 13;
+ private static final int MSG_START_INPUT = 14;
/** List of magnification callback states, mapping from displayId -> Boolean */
@GuardedBy("mlock")
@@ -1974,6 +2094,29 @@
notifySystemActionsChangedInternal();
break;
}
+ case MSG_CREATE_IME_SESSION:
+ createImeSessionInternal();
+ break;
+ case MSG_SET_IME_SESSION_ENABLED:
+ final boolean enabled = (message.arg1 != 0);
+ final IInputMethodSession session = (IInputMethodSession) message.obj;
+ setImeSessionEnabledInternal(session, enabled);
+ break;
+ case MSG_BIND_INPUT:
+ final InputBinding binding = (InputBinding) message.obj;
+ bindInputInternal(binding);
+ break;
+ case MSG_UNBIND_INPUT:
+ unbindInputInternal();
+ break;
+ case MSG_START_INPUT:
+ final boolean restarting = (message.arg1 != 0);
+ final SomeArgs args = (SomeArgs) message.obj;
+ final IBinder startInputToken = (IBinder) args.arg1;
+ final IInputContext inputContext = (IInputContext) args.arg2;
+ final EditorInfo editorInfo = (EditorInfo) args.arg3;
+ startInputInternal(startInputToken, inputContext, editorInfo, restarting);
+ break;
default: {
throw new IllegalArgumentException("Unknown message: " + type);
}
@@ -2036,6 +2179,37 @@
(available ? 1 : 0), 0);
msg.sendToTarget();
}
+
+ public void createImeSessionLocked() {
+ final Message msg = obtainMessage(MSG_CREATE_IME_SESSION);
+ msg.sendToTarget();
+ }
+
+ public void setImeSessionEnabledLocked(IInputMethodSession session, boolean enabled) {
+ final Message msg = obtainMessage(MSG_SET_IME_SESSION_ENABLED, (enabled ? 1 : 0),
+ 0, session);
+ msg.sendToTarget();
+ }
+
+ public void bindInputLocked(InputBinding binding) {
+ final Message msg = obtainMessage(MSG_BIND_INPUT, binding);
+ msg.sendToTarget();
+ }
+
+ public void unbindInputLocked() {
+ final Message msg = obtainMessage(MSG_UNBIND_INPUT);
+ msg.sendToTarget();
+ }
+
+ public void startInputLocked(IBinder startInputToken, IInputContext inputContext,
+ EditorInfo editorInfo, boolean restarting) {
+ final SomeArgs args = SomeArgs.obtain();
+ args.arg1 = startInputToken;
+ args.arg2 = inputContext;
+ args.arg3 = editorInfo;
+ final Message msg = obtainMessage(MSG_START_INPUT, restarting ? 1 : 0, 0, args);
+ msg.sendToTarget();
+ }
}
public boolean isServiceHandlesDoubleTapEnabled() {
@@ -2185,4 +2359,18 @@
Binder.restoreCallingIdentity(identity);
}
}
+
+ private static final class AccessibilityCallback extends IInputSessionWithIdCallback.Stub {
+ @Override
+ public void sessionCreated(IInputMethodSession session, int id) {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.sessionCreated");
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ InputMethodManagerInternal.get().onSessionForAccessibilityCreated(id, session);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ }
+ }
}
\ No newline at end of file
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 5b580d9..62da981 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -115,6 +115,8 @@
import android.view.accessibility.IAccessibilityManager;
import android.view.accessibility.IAccessibilityManagerClient;
import android.view.accessibility.IWindowMagnificationConnection;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputBinding;
import com.android.internal.R;
import com.android.internal.accessibility.AccessibilityShortcutController;
@@ -128,12 +130,16 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IntPair;
+import com.android.internal.view.IInputContext;
+import com.android.internal.view.IInputMethodSession;
+import com.android.server.AccessibilityManagerInternal;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.accessibility.magnification.MagnificationController;
import com.android.server.accessibility.magnification.MagnificationProcessor;
import com.android.server.accessibility.magnification.MagnificationScaleProvider;
import com.android.server.accessibility.magnification.WindowMagnificationManager;
+import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.pm.UserManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
@@ -231,7 +237,7 @@
private final MainHandler mMainHandler;
- // Lazily initialized - access through getSystemActionPerfomer()
+ // Lazily initialized - access through getSystemActionPerformer()
private SystemActionPerformer mSystemActionPerformer;
private InteractionBridge mInteractionBridge;
@@ -273,6 +279,13 @@
private Point mTempPoint = new Point();
private boolean mIsAccessibilityButtonShown;
+ private InputBinding mInputBinding;
+ IBinder mStartInputToken;
+ IInputContext mInputContext;
+ EditorInfo mEditorInfo;
+ boolean mRestarting;
+ boolean mInputSessionRequested;
+
private AccessibilityUserState getCurrentUserStateLocked() {
return getUserStateLocked(mCurrentUserId);
}
@@ -298,6 +311,42 @@
}
}
+ private static final class LocalServiceImpl extends AccessibilityManagerInternal {
+ @NonNull
+ private final AccessibilityManagerService mService;
+
+ LocalServiceImpl(@NonNull AccessibilityManagerService service) {
+ mService = service;
+ }
+
+ @Override
+ public void setImeSessionEnabled(SparseArray<IInputMethodSession> sessions,
+ boolean enabled) {
+ mService.setImeSessionEnabled(sessions, enabled);
+ }
+
+ @Override
+ public void unbindInput() {
+ mService.unbindInput();
+ }
+
+ @Override
+ public void bindInput(InputBinding binding) {
+ mService.bindInput(binding);
+ }
+
+ @Override
+ public void createImeSession(ArraySet<Integer> ignoreSet) {
+ mService.createImeSession(ignoreSet);
+ }
+
+ @Override
+ public void startInput(IBinder startInputToken, IInputContext inputContext,
+ EditorInfo editorInfo, boolean restarting) {
+ mService.startInput(startInputToken, inputContext, editorInfo, restarting);
+ }
+ }
+
public static final class Lifecycle extends SystemService {
private final AccessibilityManagerService mService;
@@ -308,6 +357,8 @@
@Override
public void onStart() {
+ LocalServices.addService(AccessibilityManagerInternal.class,
+ new LocalServiceImpl(mService));
publishBinderService(Context.ACCESSIBILITY_SERVICE, mService);
}
@@ -3463,27 +3514,27 @@
@Override
@RequiresPermission(Manifest.permission.SET_SYSTEM_AUDIO_CAPTION)
- public void setSystemAudioCaptioningRequested(boolean isEnabled, int userId) {
+ public void setSystemAudioCaptioningEnabled(boolean isEnabled, int userId) {
mContext.enforceCallingOrSelfPermission(
Manifest.permission.SET_SYSTEM_AUDIO_CAPTION,
- "setSystemAudioCaptioningRequested");
+ "setSystemAudioCaptioningEnabled");
- mCaptioningManagerImpl.setSystemAudioCaptioningRequested(isEnabled, userId);
+ mCaptioningManagerImpl.setSystemAudioCaptioningEnabled(isEnabled, userId);
}
@Override
- public boolean isSystemAudioCaptioningUiRequested(int userId) {
- return mCaptioningManagerImpl.isSystemAudioCaptioningUiRequested(userId);
+ public boolean isSystemAudioCaptioningUiEnabled(int userId) {
+ return mCaptioningManagerImpl.isSystemAudioCaptioningUiEnabled(userId);
}
@Override
@RequiresPermission(Manifest.permission.SET_SYSTEM_AUDIO_CAPTION)
- public void setSystemAudioCaptioningUiRequested(boolean isEnabled, int userId) {
+ public void setSystemAudioCaptioningUiEnabled(boolean isEnabled, int userId) {
mContext.enforceCallingOrSelfPermission(
Manifest.permission.SET_SYSTEM_AUDIO_CAPTION,
- "setSystemAudioCaptioningUiRequested");
+ "setSystemAudioCaptioningUiEnabled");
- mCaptioningManagerImpl.setSystemAudioCaptioningUiRequested(isEnabled, userId);
+ mCaptioningManagerImpl.setSystemAudioCaptioningUiEnabled(isEnabled, userId);
}
@Override
@@ -4240,6 +4291,45 @@
this, displayId));
}
+ @Override
+ public void requestImeLocked(AccessibilityServiceConnection connection) {
+ mMainHandler.sendMessage(obtainMessage(
+ AccessibilityManagerService::createSessionForConnection, this, connection));
+ mMainHandler.sendMessage(obtainMessage(
+ AccessibilityManagerService::bindAndStartInputForConnection, this, connection));
+ }
+
+ @Override
+ public void unbindImeLocked(AccessibilityServiceConnection connection) {
+ mMainHandler.sendMessage(obtainMessage(
+ AccessibilityManagerService::unbindInputForConnection, this, connection));
+ }
+
+ private void createSessionForConnection(AccessibilityServiceConnection connection) {
+ synchronized (mLock) {
+ if (mInputSessionRequested) {
+ connection.createImeSessionLocked();
+ }
+ }
+ }
+
+ private void bindAndStartInputForConnection(AccessibilityServiceConnection connection) {
+ synchronized (mLock) {
+ if (mInputBinding != null) {
+ connection.bindInputLocked(mInputBinding);
+ connection.startInputLocked(mStartInputToken, mInputContext, mEditorInfo,
+ mRestarting);
+ }
+ }
+ }
+
+ private void unbindInputForConnection(AccessibilityServiceConnection connection) {
+ InputMethodManagerInternal.get().unbindAccessibilityFromCurrentClient(connection.mId);
+ synchronized (mLock) {
+ connection.unbindInputLocked();
+ }
+ }
+
private void onDoubleTapAndHoldInternal(int displayId) {
synchronized (mLock) {
if (mHasInputFilter && mInputFilter != null) {
@@ -4268,4 +4358,100 @@
public AccessibilityTraceManager getTraceManager() {
return mTraceManager;
}
+
+ /**
+ * Bind input for accessibility services which request ime capabilities.
+ *
+ * @param binding Information given to an accessibility service about a client connecting to it.
+ */
+ public void bindInput(InputBinding binding) {
+ AccessibilityUserState userState;
+ synchronized (mLock) {
+ // Keep records of these in case new Accessibility Services are enabled.
+ mInputBinding = binding;
+ userState = getCurrentUserStateLocked();
+ for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
+ final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
+ if (service.requestImeApis()) {
+ service.bindInputLocked(binding);
+ }
+ }
+ }
+ }
+
+ /**
+ * Unbind input for accessibility services which request ime capabilities.
+ */
+ public void unbindInput() {
+ AccessibilityUserState userState;
+ // TODO(b/218182733): Resolve the Imf lock and mLock possible deadlock
+ synchronized (mLock) {
+ userState = getCurrentUserStateLocked();
+ for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
+ final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
+ if (service.requestImeApis()) {
+ service.unbindInputLocked();
+ }
+ }
+ }
+ }
+
+ /**
+ * Start input for accessibility services which request ime capabilities.
+ */
+ public void startInput(IBinder startInputToken, IInputContext inputContext,
+ EditorInfo editorInfo, boolean restarting) {
+ AccessibilityUserState userState;
+ synchronized (mLock) {
+ // Keep records of these in case new Accessibility Services are enabled.
+ mStartInputToken = startInputToken;
+ mInputContext = inputContext;
+ mEditorInfo = editorInfo;
+ mRestarting = restarting;
+ userState = getCurrentUserStateLocked();
+ for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
+ final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
+ if (service.requestImeApis()) {
+ service.startInputLocked(startInputToken, inputContext, editorInfo, restarting);
+ }
+ }
+ }
+ }
+
+ /**
+ * Request input sessions from all accessibility services which request ime capabilities and
+ * whose id is not in the ignoreSet
+ */
+ public void createImeSession(ArraySet<Integer> ignoreSet) {
+ AccessibilityUserState userState;
+ synchronized (mLock) {
+ mInputSessionRequested = true;
+ userState = getCurrentUserStateLocked();
+ for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
+ final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
+ if ((!ignoreSet.contains(service.mId)) && service.requestImeApis()) {
+ service.createImeSessionLocked();
+ }
+ }
+ }
+ }
+
+ /**
+ * Enable or disable the sessions.
+ *
+ * @param sessions Sessions to enable or disable.
+ * @param enabled True if enable the sessions or false if disable the sessions.
+ */
+ public void setImeSessionEnabled(SparseArray<IInputMethodSession> sessions, boolean enabled) {
+ AccessibilityUserState userState;
+ synchronized (mLock) {
+ userState = getCurrentUserStateLocked();
+ for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
+ final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
+ if (sessions.contains(service.mId) && service.requestImeApis()) {
+ service.setImeSessionEnabledLocked(sessions.get(service.mId), enabled);
+ }
+ }
+ }
+ }
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index 8f7260f..0631028 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -127,6 +127,9 @@
}
public void unbindLocked() {
+ if (requestImeApis()) {
+ mSystemSupport.unbindImeLocked(this);
+ }
mContext.unbindService(this);
AccessibilityUserState userState = mUserStateWeakReference.get();
if (userState == null) return;
@@ -188,6 +191,9 @@
// the new configuration (for example, initializing the input filter).
mMainHandler.sendMessage(obtainMessage(
AccessibilityServiceConnection::initializeService, this));
+ if (requestImeApis()) {
+ mSystemSupport.requestImeLocked(this);
+ }
}
}
@@ -371,6 +377,9 @@
if (!isConnectedLocked()) {
return;
}
+ if (requestImeApis()) {
+ mSystemSupport.unbindImeLocked(this);
+ }
mAccessibilityServiceInfo.crashed = true;
AccessibilityUserState userState = mUserStateWeakReference.get();
if (userState != null) {
@@ -512,6 +521,10 @@
mMainHandler.sendMessage(msg);
}
+ public boolean requestImeApis() {
+ return mRequestImeApis;
+ }
+
private void notifyMotionEventInternal(MotionEvent event) {
final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
if (listener != null) {
diff --git a/services/accessibility/java/com/android/server/accessibility/CaptioningManagerImpl.java b/services/accessibility/java/com/android/server/accessibility/CaptioningManagerImpl.java
index 39780d2..0fc6c8d 100644
--- a/services/accessibility/java/com/android/server/accessibility/CaptioningManagerImpl.java
+++ b/services/accessibility/java/com/android/server/accessibility/CaptioningManagerImpl.java
@@ -40,7 +40,7 @@
* @param userId The user Id.
*/
@Override
- public void setSystemAudioCaptioningRequested(boolean isEnabled, int userId) {
+ public void setSystemAudioCaptioningEnabled(boolean isEnabled, int userId) {
final long identity = Binder.clearCallingIdentity();
try {
Settings.Secure.putIntForUser(mContext.getContentResolver(),
@@ -57,7 +57,7 @@
* @return the system audio caption UI enabled state.
*/
@Override
- public boolean isSystemAudioCaptioningUiRequested(int userId) {
+ public boolean isSystemAudioCaptioningUiEnabled(int userId) {
final long identity = Binder.clearCallingIdentity();
try {
return Settings.Secure.getIntForUser(mContext.getContentResolver(),
@@ -75,7 +75,7 @@
* @param userId The user Id.
*/
@Override
- public void setSystemAudioCaptioningUiRequested(boolean isEnabled, int userId) {
+ public void setSystemAudioCaptioningUiEnabled(boolean isEnabled, int userId) {
final long identity = Binder.clearCallingIdentity();
try {
Settings.Secure.putIntForUser(mContext.getContentResolver(),
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
index b70ffb2..c376bf8 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
@@ -78,6 +78,7 @@
private static final boolean DEBUG = false;
private static final String TAG = "MagnificationController";
+
private final AccessibilityManagerService mAms;
private final PointF mTempPoint = new PointF();
private final Object mLock;
@@ -194,11 +195,10 @@
*/
public void transitionMagnificationModeLocked(int displayId, int targetMode,
@NonNull TransitionCallBack transitionCallBack) {
- final PointF magnificationCenter = getCurrentMagnificationBoundsCenterLocked(displayId,
- targetMode);
+ final PointF currentCenter = getCurrentMagnificationCenterLocked(displayId, targetMode);
final DisableMagnificationCallback animationCallback =
getDisableMagnificationEndRunnableLocked(displayId);
- if (magnificationCenter == null && animationCallback == null) {
+ if (currentCenter == null && animationCallback == null) {
transitionCallBack.onResult(displayId, true);
return;
}
@@ -213,7 +213,7 @@
}
}
- if (magnificationCenter == null) {
+ if (currentCenter == null) {
Slog.w(TAG, "Invalid center, ignore it");
transitionCallBack.onResult(displayId, true);
return;
@@ -221,10 +221,10 @@
final FullScreenMagnificationController screenMagnificationController =
getFullScreenMagnificationController();
final WindowMagnificationManager windowMagnificationMgr = getWindowMagnificationMgr();
- final float scale = mScaleProvider.getScale(displayId);
+ final float scale = getTargetModeScaleFromCurrentMagnification(displayId, targetMode);
final DisableMagnificationCallback animationEndCallback =
new DisableMagnificationCallback(transitionCallBack, displayId, targetMode,
- scale, magnificationCenter, true);
+ scale, currentCenter, true);
if (targetMode == ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) {
screenMagnificationController.reset(displayId, animationEndCallback);
} else {
@@ -247,17 +247,20 @@
*/
public void transitionMagnificationConfigMode(int displayId, MagnificationConfig config,
boolean animate, int id) {
+ if (DEBUG) {
+ Slog.d(TAG, "transitionMagnificationConfigMode displayId = " + displayId
+ + ", config = " + config);
+ }
synchronized (mLock) {
final int targetMode = config.getMode();
- final PointF currentBoundsCenter = getCurrentMagnificationBoundsCenterLocked(displayId,
- targetMode);
+ final PointF currentCenter = getCurrentMagnificationCenterLocked(displayId, targetMode);
final PointF magnificationCenter = new PointF(config.getCenterX(), config.getCenterY());
- if (currentBoundsCenter != null) {
+ if (currentCenter != null) {
final float centerX = Float.isNaN(config.getCenterX())
- ? currentBoundsCenter.x
+ ? currentCenter.x
: config.getCenterX();
final float centerY = Float.isNaN(config.getCenterY())
- ? currentBoundsCenter.y
+ ? currentCenter.y
: config.getCenterY();
magnificationCenter.set(centerX, centerY);
}
@@ -272,24 +275,36 @@
final FullScreenMagnificationController screenMagnificationController =
getFullScreenMagnificationController();
final WindowMagnificationManager windowMagnificationMgr = getWindowMagnificationMgr();
- final float scale = mScaleProvider.getScale(displayId);
+ final float targetScale = Float.isNaN(config.getScale())
+ ? getTargetModeScaleFromCurrentMagnification(displayId, targetMode)
+ : config.getScale();
if (targetMode == ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) {
screenMagnificationController.reset(displayId, false);
windowMagnificationMgr.enableWindowMagnification(displayId,
- scale, magnificationCenter.x, magnificationCenter.y,
+ targetScale, magnificationCenter.x, magnificationCenter.y,
animate ? STUB_ANIMATION_CALLBACK : null, id);
} else if (targetMode == ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN) {
windowMagnificationMgr.disableWindowMagnification(displayId, false, null);
if (!screenMagnificationController.isRegistered(displayId)) {
screenMagnificationController.register(displayId);
}
- screenMagnificationController.setScaleAndCenter(displayId, scale,
+ screenMagnificationController.setScaleAndCenter(displayId, targetScale,
magnificationCenter.x, magnificationCenter.y, animate,
id);
}
}
}
+ // We assume the target mode is different from the current mode, and there is only
+ // two modes, so we get the target scale from another mode.
+ private float getTargetModeScaleFromCurrentMagnification(int displayId, int targetMode) {
+ if (targetMode == ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) {
+ return getFullScreenMagnificationController().getScale(displayId);
+ } else {
+ return getWindowMagnificationMgr().getScale(displayId);
+ }
+ }
+
/**
* Return {@code true} if disable magnification animation callback of the display is running.
*
@@ -384,7 +399,7 @@
public void onSourceBoundsChanged(int displayId, Rect bounds) {
final MagnificationConfig config = new MagnificationConfig.Builder()
.setMode(MAGNIFICATION_MODE_WINDOW)
- .setScale(mScaleProvider.getScale(displayId))
+ .setScale(getWindowMagnificationMgr().getScale(displayId))
.setCenterX(bounds.exactCenterX())
.setCenterY(bounds.exactCenterY()).build();
mAms.notifyMagnificationChanged(displayId, new Region(bounds), config);
@@ -607,8 +622,7 @@
}
}
- private @Nullable
- PointF getCurrentMagnificationBoundsCenterLocked(int displayId, int targetMode) {
+ private @Nullable PointF getCurrentMagnificationCenterLocked(int displayId, int targetMode) {
if (targetMode == ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN) {
if (mWindowMagnificationMgr == null
|| !mWindowMagnificationMgr.isWindowMagnifierEnabled(displayId)) {
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java
index 9eb77b4..175182c 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java
@@ -26,6 +26,7 @@
import android.accessibilityservice.MagnificationConfig;
import android.annotation.NonNull;
import android.graphics.Region;
+import android.util.Slog;
import android.view.Display;
import java.io.PrintWriter;
@@ -56,6 +57,9 @@
*/
public class MagnificationProcessor {
+ private static final String TAG = "MagnificationProcessor";
+ private static final boolean DEBUG = false;
+
private final MagnificationController mController;
public MagnificationProcessor(MagnificationController controller) {
@@ -103,6 +107,9 @@
*/
public boolean setMagnificationConfig(int displayId, @NonNull MagnificationConfig config,
boolean animate, int id) {
+ if (DEBUG) {
+ Slog.d(TAG, "setMagnificationConfig config=" + config);
+ }
if (transitionModeIfNeeded(displayId, config, animate, id)) {
return true;
}
@@ -125,15 +132,13 @@
}
private boolean setScaleAndCenterForFullScreenMagnification(int displayId, float scale,
- float centerX, float centerY,
- boolean animate, int id) {
+ float centerX, float centerY, boolean animate, int id) {
+
if (!isRegistered(displayId)) {
register(displayId);
}
return mController.getFullScreenMagnificationController().setScaleAndCenter(
- displayId,
- scale,
- centerX, centerY, animate, id);
+ displayId, scale, centerX, centerY, animate, id);
}
/**
@@ -143,8 +148,12 @@
private boolean transitionModeIfNeeded(int displayId, MagnificationConfig config,
boolean animate, int id) {
int currentMode = getControllingMode(displayId);
- if (currentMode == config.getMode()
- || !mController.hasDisableMagnificationCallback(displayId)) {
+ if (config.getMode() == MagnificationConfig.MAGNIFICATION_MODE_DEFAULT) {
+ return false;
+ }
+ // Target mode is as same as current mode and is not transitioning.
+ if (currentMode == config.getMode() && !mController.hasDisableMagnificationCallback(
+ displayId)) {
return false;
}
mController.transitionMagnificationConfigMode(displayId, config, animate, id);
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
index 278f3f9..89910ea 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
@@ -177,6 +177,9 @@
* @param connection {@link IWindowMagnificationConnection}
*/
public void setConnection(@Nullable IWindowMagnificationConnection connection) {
+ if (DBG) {
+ Slog.d(TAG, "setConnection :" + connection);
+ }
synchronized (mLock) {
// Reset connectionWrapper.
if (mConnectionWrapper != null) {
@@ -223,6 +226,9 @@
* @return {@code true} if {@link IWindowMagnificationConnection} state is going to change.
*/
public boolean requestConnection(boolean connect) {
+ if (DBG) {
+ Slog.d(TAG, "requestConnection :" + connect);
+ }
synchronized (mLock) {
if (connect == isConnected()) {
return false;
@@ -485,10 +491,6 @@
final boolean enabled;
boolean previousEnabled;
synchronized (mLock) {
- if (mConnectionWrapper == null) {
- Slog.w(TAG, "enableWindowMagnification failed: connection null");
- return false;
- }
WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
if (magnifier == null) {
magnifier = createWindowMagnifier(displayId);
@@ -528,10 +530,10 @@
final boolean disabled;
synchronized (mLock) {
WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
- if (magnifier == null || mConnectionWrapper == null) {
- Slog.w(TAG, "disableWindowMagnification failed: connection " + mConnectionWrapper);
+ if (magnifier == null) {
return false;
}
+
disabled = magnifier.disableWindowMagnificationInternal(animationCallback);
if (clear) {
mWindowMagnifiers.delete(displayId);
@@ -1018,25 +1020,33 @@
}
}
+ @GuardedBy("mLock")
private boolean enableWindowMagnificationInternal(int displayId, float scale, float centerX,
float centerY, float magnificationFrameOffsetRatioX,
float magnificationFrameOffsetRatioY,
MagnificationAnimationCallback animationCallback) {
- synchronized (mLock) {
- return mConnectionWrapper != null && mConnectionWrapper.enableWindowMagnification(
- displayId, scale, centerX, centerY,
- magnificationFrameOffsetRatioX, magnificationFrameOffsetRatioY,
- animationCallback);
+ if (mConnectionWrapper == null) {
+ Slog.w(TAG, "enableWindowMagnificationInternal mConnectionWrapper is null");
+ return false;
}
+ return mConnectionWrapper.enableWindowMagnification(
+ displayId, scale, centerX, centerY,
+ magnificationFrameOffsetRatioX, magnificationFrameOffsetRatioY,
+ animationCallback);
}
private boolean setScaleInternal(int displayId, float scale) {
return mConnectionWrapper != null && mConnectionWrapper.setScale(displayId, scale);
}
+ @GuardedBy("mLock")
private boolean disableWindowMagnificationInternal(int displayId,
MagnificationAnimationCallback animationCallback) {
- return mConnectionWrapper != null && mConnectionWrapper.disableWindowMagnification(
+ if (mConnectionWrapper == null) {
+ Slog.w(TAG, "mConnectionWrapper is null");
+ return false;
+ }
+ return mConnectionWrapper.disableWindowMagnification(
displayId, animationCallback);
}
diff --git a/services/api/current.txt b/services/api/current.txt
index dcf7e64..e46c972 100644
--- a/services/api/current.txt
+++ b/services/api/current.txt
@@ -38,8 +38,8 @@
package com.android.server.am {
public interface ActivityManagerLocal {
+ method public boolean bindSupplementalProcessService(@NonNull android.content.Intent, @NonNull android.content.ServiceConnection, int, @NonNull String, int) throws android.os.RemoteException;
method public boolean canStartForegroundService(int, int, @NonNull String);
- method public boolean startAndBindSupplementalProcessService(@NonNull android.content.Intent, @NonNull android.content.ServiceConnection, int) throws android.os.TransactionTooLargeException;
}
}
diff --git a/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerService.java b/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerService.java
index dafe7a4..daead0a 100644
--- a/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerService.java
+++ b/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerService.java
@@ -58,11 +58,14 @@
private final ActivityTaskManagerInternal mActivityTaskManagerInternal;
+ private final Context mContext;
+
public CloudSearchManagerService(Context context) {
super(context, new FrameworkResourcesServiceNameResolver(context,
R.string.config_defaultCloudSearchService), null,
PACKAGE_UPDATE_POLICY_NO_REFRESH | PACKAGE_RESTART_POLICY_NO_REFRESH);
mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
+ mContext = context;
}
@Override
@@ -106,6 +109,8 @@
@Override
public void search(@NonNull SearchRequest searchRequest,
@NonNull ICloudSearchManagerCallback callBack) {
+ searchRequest.setSource(
+ mContext.getPackageManager().getNameForUid(Binder.getCallingUid()));
runForUserLocked("search", searchRequest.getRequestId(), (service) ->
service.onSearchLocked(searchRequest, callBack));
}
diff --git a/services/companion/java/com/android/server/companion/AssociationCleanUpService.java b/services/companion/java/com/android/server/companion/AssociationCleanUpService.java
index 0509e0c..55246e1 100644
--- a/services/companion/java/com/android/server/companion/AssociationCleanUpService.java
+++ b/services/companion/java/com/android/server/companion/AssociationCleanUpService.java
@@ -16,7 +16,9 @@
package com.android.server.companion;
-import static com.android.server.companion.CompanionDeviceManagerService.LOG_TAG;
+import static com.android.server.companion.CompanionDeviceManagerService.TAG;
+
+import static java.util.concurrent.TimeUnit.DAYS;
import android.app.job.JobInfo;
import android.app.job.JobParameters;
@@ -37,17 +39,16 @@
*/
public class AssociationCleanUpService extends JobService {
private static final int JOB_ID = AssociationCleanUpService.class.hashCode();
- private static final long ONE_DAY_INTERVAL = 3 * 24 * 60 * 60 * 1000; // 1 Day
- private CompanionDeviceManagerServiceInternal mCdmServiceInternal = LocalServices.getService(
- CompanionDeviceManagerServiceInternal.class);
+ private static final long ONE_DAY_INTERVAL = DAYS.toMillis(1);
@Override
public boolean onStartJob(final JobParameters params) {
- Slog.i(LOG_TAG, "Execute the Association CleanUp job");
+ Slog.i(TAG, "Execute the Association CleanUp job");
// Special policy for APP_STREAMING role that need to revoke associations if the device
// does not connect for 3 months.
AsyncTask.execute(() -> {
- mCdmServiceInternal.associationCleanUp(AssociationRequest.DEVICE_PROFILE_APP_STREAMING);
+ LocalServices.getService(CompanionDeviceManagerServiceInternal.class)
+ .associationCleanUp(AssociationRequest.DEVICE_PROFILE_APP_STREAMING);
jobFinished(params, false);
});
return true;
@@ -55,7 +56,7 @@
@Override
public boolean onStopJob(final JobParameters params) {
- Slog.i(LOG_TAG, "Association cleanup job stopped; id=" + params.getJobId()
+ Slog.i(TAG, "Association cleanup job stopped; id=" + params.getJobId()
+ ", reason="
+ JobParameters.getInternalReasonCodeDescription(
params.getInternalStopReasonCode()));
@@ -63,7 +64,7 @@
}
static void schedule(Context context) {
- Slog.i(LOG_TAG, "Scheduling the Association Cleanup job");
+ Slog.i(TAG, "Scheduling the Association Cleanup job");
final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
final JobInfo job = new JobInfo.Builder(JOB_ID,
new ComponentName(context, AssociationCleanUpService.class))
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index cef0e83..eaa99f7 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -18,31 +18,28 @@
package com.android.server.companion;
import static android.Manifest.permission.MANAGE_COMPANION_DEVICES;
-import static android.bluetooth.le.ScanSettings.CALLBACK_TYPE_ALL_MATCHES;
-import static android.bluetooth.le.ScanSettings.SCAN_MODE_LOW_POWER;
import static android.content.pm.PackageManager.CERT_INPUT_SHA256;
-import static android.content.pm.PackageManager.FEATURE_COMPANION_DEVICE_SETUP;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.os.Binder.getCallingUid;
import static android.os.Process.SYSTEM_UID;
import static android.os.UserHandle.getCallingUserId;
import static com.android.internal.util.CollectionUtils.any;
-import static com.android.internal.util.CollectionUtils.find;
import static com.android.internal.util.Preconditions.checkState;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
-import static com.android.internal.util.function.pooled.PooledLambda.obtainRunnable;
import static com.android.server.companion.AssociationStore.CHANGE_TYPE_UPDATED_ADDRESS_UNCHANGED;
-import static com.android.server.companion.PermissionsUtils.checkCallerCanManageAssociationsForPackage;
+import static com.android.server.companion.PackageUtils.enforceUsesCompanionDeviceFeature;
+import static com.android.server.companion.PackageUtils.getPackageInfo;
import static com.android.server.companion.PermissionsUtils.checkCallerCanManageCompanionDevice;
import static com.android.server.companion.PermissionsUtils.enforceCallerCanManageAssociationsForPackage;
import static com.android.server.companion.PermissionsUtils.enforceCallerCanManageCompanionDevice;
import static com.android.server.companion.PermissionsUtils.enforceCallerIsSystemOr;
import static com.android.server.companion.PermissionsUtils.enforceCallerIsSystemOrCanInteractWithUserId;
+import static com.android.server.companion.PermissionsUtils.sanitizeWithCallerChecks;
import static com.android.server.companion.RolesUtils.addRoleHolderForAssociation;
import static com.android.server.companion.RolesUtils.removeRoleHolderForAssociation;
import static java.util.Objects.requireNonNull;
+import static java.util.concurrent.TimeUnit.DAYS;
import static java.util.concurrent.TimeUnit.MINUTES;
import android.annotation.NonNull;
@@ -53,26 +50,15 @@
import android.app.AppOpsManager;
import android.app.NotificationManager;
import android.app.PendingIntent;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.le.BluetoothLeScanner;
-import android.bluetooth.le.ScanCallback;
-import android.bluetooth.le.ScanFilter;
-import android.bluetooth.le.ScanResult;
-import android.bluetooth.le.ScanSettings;
import android.companion.AssociationInfo;
import android.companion.AssociationRequest;
import android.companion.DeviceNotAssociatedException;
import android.companion.IAssociationRequestCallback;
import android.companion.ICompanionDeviceManager;
import android.companion.IOnAssociationsChangedListener;
-import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.content.SharedPreferences;
-import android.content.pm.FeatureInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
@@ -93,11 +79,10 @@
import android.os.ShellCallback;
import android.os.UserHandle;
import android.os.UserManager;
-import android.permission.PermissionControllerManager;
import android.text.BidiFormatter;
-import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.ExceptionUtils;
+import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -112,86 +97,49 @@
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.companion.presence.CompanionDevicePresenceMonitor;
import com.android.server.pm.UserManagerInternal;
-import com.android.server.wm.ActivityTaskManagerInternal;
import java.io.File;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
import java.util.Collections;
-import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.Set;
-import java.util.TimeZone;
-/** @hide */
@SuppressLint("LongLogTag")
-public class CompanionDeviceManagerService extends SystemService
- implements AssociationStore.OnChangeListener {
- static final String LOG_TAG = "CompanionDeviceManagerService";
+public class CompanionDeviceManagerService extends SystemService {
+ static final String TAG = "CompanionDeviceManagerService";
static final boolean DEBUG = false;
/** Range of Association IDs allocated for a user.*/
- static final int ASSOCIATIONS_IDS_PER_USER_RANGE = 100000;
-
- private static final long DEVICE_DISAPPEARED_TIMEOUT_MS = 10 * 1000;
- private static final long DEVICE_DISAPPEARED_UNBIND_TIMEOUT_MS = 10 * 60 * 1000;
-
- static final long DEVICE_LISTENER_DIED_REBIND_TIMEOUT_MS = 10 * 1000;
-
+ private static final int ASSOCIATIONS_IDS_PER_USER_RANGE = 100000;
private static final long PAIR_WITHOUT_PROMPT_WINDOW_MS = 10 * 60 * 1000; // 10 min
private static final String PREF_FILE_NAME = "companion_device_preferences.xml";
private static final String PREF_KEY_AUTO_REVOKE_GRANTS_DONE = "auto_revoke_grants_done";
- private static final long ASSOCIATION_CLEAN_UP_TIME_WINDOW =
- 90L * 24 * 60 * 60 * 1000; // 3 months
+ private static final long ASSOCIATION_CLEAN_UP_TIME_WINDOW = DAYS.toMillis(3 * 30); // 3 months
- private static DateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- static {
- sDateFormat.setTimeZone(TimeZone.getDefault());
- }
-
- // Persistent data store for all Associations.
private PersistentDataStore mPersistentStore;
- private final AssociationStoreImpl mAssociationStore = new AssociationStoreImpl();
+ private final PersistUserStateHandler mUserPersistenceHandler;
+
+ private final AssociationStoreImpl mAssociationStore;
private AssociationRequestsProcessor mAssociationRequestsProcessor;
+ private CompanionDevicePresenceMonitor mDevicePresenceMonitor;
+ private CompanionApplicationController mCompanionAppController;
- private PowerWhitelistManager mPowerWhitelistManager;
- private IAppOpsService mAppOpsManager;
- private BluetoothAdapter mBluetoothAdapter;
- private UserManager mUserManager;
-
- private ScanCallback mBleScanCallback = new BleScanCallback();
- PermissionControllerManager mPermissionControllerManager;
-
- private BluetoothDeviceConnectedListener mBluetoothDeviceConnectedListener =
- new BluetoothDeviceConnectedListener();
- private BleStateBroadcastReceiver mBleStateBroadcastReceiver = new BleStateBroadcastReceiver();
- private List<String> mCurrentlyConnectedDevices = new ArrayList<>();
- Set<Integer> mPresentSelfManagedDevices = new HashSet<>();
- private ArrayMap<String, Date> mDevicesLastNearby = new ArrayMap<>();
- private UnbindDeviceListenersRunnable
- mUnbindDeviceListenersRunnable = new UnbindDeviceListenersRunnable();
- private ArrayMap<String, TriggerDeviceDisappearedRunnable> mTriggerDeviceDisappearedRunnables =
- new ArrayMap<>();
- private final RemoteCallbackList<IOnAssociationsChangedListener> mListeners =
- new RemoteCallbackList<>();
- private final CompanionDeviceManagerServiceInternal mLocalService = new LocalService(this);
-
- final Handler mMainHandler = Handler.getMain();
- private final PersistUserStateHandler mUserPersistenceHandler = new PersistUserStateHandler();
- private CompanionDevicePresenceController mCompanionDevicePresenceController;
+ private final ActivityManagerInternal mAmInternal;
+ private final IAppOpsService mAppOpsManager;
+ private final PowerWhitelistManager mPowerWhitelistManager;
+ private final UserManager mUserManager;
+ final PackageManagerInternal mPackageManagerInternal;
/**
- * A structure that consist of two nested maps, and effectively maps (userId + packageName) to
+ * A structure that consists of two nested maps, and effectively maps (userId + packageName) to
* a list of IDs that have been previously assigned to associations for that package.
* We maintain this structure so that we never re-use association IDs for the same package
* (until it's uninstalled).
@@ -199,9 +147,8 @@
@GuardedBy("mPreviouslyUsedIds")
private final SparseArray<Map<String, Set<Integer>>> mPreviouslyUsedIds = new SparseArray<>();
- ActivityTaskManagerInternal mAtmInternal;
- ActivityManagerInternal mAmInternal;
- PackageManagerInternal mPackageManagerInternal;
+ private final RemoteCallbackList<IOnAssociationsChangedListener> mListeners =
+ new RemoteCallbackList<>();
public CompanionDeviceManagerService(Context context) {
super(context);
@@ -209,14 +156,12 @@
mPowerWhitelistManager = context.getSystemService(PowerWhitelistManager.class);
mAppOpsManager = IAppOpsService.Stub.asInterface(
ServiceManager.getService(Context.APP_OPS_SERVICE));
- mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
- mPermissionControllerManager = requireNonNull(
- context.getSystemService(PermissionControllerManager.class));
mUserManager = context.getSystemService(UserManager.class);
- LocalServices.addService(CompanionDeviceManagerServiceInternal.class, mLocalService);
+ mUserPersistenceHandler = new PersistUserStateHandler();
+ mAssociationStore = new AssociationStoreImpl();
}
@Override
@@ -224,14 +169,24 @@
mPersistentStore = new PersistentDataStore();
loadAssociationsFromDisk();
- mAssociationStore.registerListener(this);
+ mAssociationStore.registerListener(mAssociationStoreChangeListener);
- mCompanionDevicePresenceController = new CompanionDevicePresenceController(this);
- mAssociationRequestsProcessor = new AssociationRequestsProcessor(this, mAssociationStore);
+ mDevicePresenceMonitor = new CompanionDevicePresenceMonitor(
+ mAssociationStore, mDevicePresenceCallback);
- // Publish "binder service"
+ mAssociationRequestsProcessor = new AssociationRequestsProcessor(
+ /* cdmService */this, mAssociationStore);
+
+ final Context context = getContext();
+ mCompanionAppController = new CompanionApplicationController(
+ context, mApplicationControllerCallback);
+
+ // Publish "binder" service.
final CompanionDeviceManagerImpl impl = new CompanionDeviceManagerImpl();
publishBinderService(Context.COMPANION_DEVICE_SERVICE, impl);
+
+ // Publish "local" service.
+ LocalServices.addService(CompanionDeviceManagerServiceInternal.class, new LocalService());
}
void loadAssociationsFromDisk() {
@@ -248,21 +203,13 @@
@Override
public void onBootPhase(int phase) {
- if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
- registerPackageMonitor();
-
- // Init Bluetooth
- mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
- if (mBluetoothAdapter != null) {
- mBluetoothAdapter.registerBluetoothConnectionCallback(
- getContext().getMainExecutor(),
- mBluetoothDeviceConnectedListener);
- getContext().registerReceiver(
- mBleStateBroadcastReceiver, mBleStateBroadcastReceiver.mIntentFilter);
- initBleScanning();
- } else {
- Slog.w(LOG_TAG, "No BluetoothAdapter available");
- }
+ final Context context = getContext();
+ if (phase == PHASE_SYSTEM_SERVICES_READY) {
+ // WARNING: moving PackageMonitor to another thread (Looper) may introduce significant
+ // delays (even in case of the Main Thread). It may be fine overall, but would require
+ // updating the tests (adding a delay there).
+ mPackageMonitor.register(context, FgThread.get().getLooper(), UserHandle.ALL, true);
+ mDevicePresenceMonitor.init(context);
} else if (phase == PHASE_BOOT_COMPLETED) {
// Run the Association CleanUp job service daily.
AssociationCleanUpService.schedule(getContext());
@@ -288,76 +235,84 @@
@UserIdInt int userId, @NonNull String packageName, @NonNull String macAddress) {
final AssociationInfo association = mAssociationStore.getAssociationsForPackageWithAddress(
userId, packageName, macAddress);
- return sanitizeWithCallerChecks(association);
+ return sanitizeWithCallerChecks(getContext(), association);
}
@Nullable
AssociationInfo getAssociationWithCallerChecks(int associationId) {
final AssociationInfo association = mAssociationStore.getAssociationById(associationId);
- return sanitizeWithCallerChecks(association);
+ return sanitizeWithCallerChecks(getContext(), association);
}
- @Nullable
- private AssociationInfo sanitizeWithCallerChecks(@Nullable AssociationInfo association) {
- if (association == null) return null;
+ private void onDeviceAppearedInternal(int associationId) {
+ if (DEBUG) Log.i(TAG, "onDevice_Appeared_Internal() id=" + associationId);
+
+ final AssociationInfo association = mAssociationStore.getAssociationById(associationId);
+ if (DEBUG) Log.d(TAG, " association=" + associationId);
+
+ if (!association.shouldBindWhenPresent()) return;
final int userId = association.getUserId();
final String packageName = association.getPackageName();
- if (!checkCallerCanManageAssociationsForPackage(getContext(), userId, packageName)) {
- return null;
- }
- return association;
+ if (!mCompanionAppController.isCompanionApplicationBound(userId, packageName)) {
+ mCompanionAppController.bindCompanionApplication(userId, packageName);
+ } else if (DEBUG) {
+ Log.i(TAG, "u" + userId + "\\" + packageName + " is already bound");
+ }
+ mCompanionAppController.notifyCompanionApplicationDeviceAppeared(association);
}
- // Revoke associations if the selfManaged companion device does not connect for 3
- // months for specific profile.
- private void associationCleanUp(String profile) {
- for (AssociationInfo ai : mAssociationStore.getAssociations()) {
- if (ai.isSelfManaged()
- && profile.equals(ai.getDeviceProfile())
- && System.currentTimeMillis() - ai.getLastTimeConnectedMs()
- >= ASSOCIATION_CLEAN_UP_TIME_WINDOW) {
- Slog.d(LOG_TAG, "Removing the association for associationId: "
- + ai.getId()
- + " due to the device does not connect for 3 months."
- + " Current time: "
- + new Date(System.currentTimeMillis()));
- disassociateInternal(ai.getId());
- }
+ private void onDeviceDisappearedInternal(int associationId) {
+ if (DEBUG) Log.i(TAG, "onDevice_Disappeared_Internal() id=" + associationId);
+
+ final AssociationInfo association = mAssociationStore.getAssociationById(associationId);
+ if (DEBUG) Log.d(TAG, " association=" + associationId);
+
+ final int userId = association.getUserId();
+ final String packageName = association.getPackageName();
+
+ if (!mCompanionAppController.isCompanionApplicationBound(userId, packageName)) {
+ if (DEBUG) Log.w(TAG, "u" + userId + "\\" + packageName + " is NOT bound");
+ return;
}
+
+ if (association.shouldBindWhenPresent()) {
+ mCompanionAppController.notifyCompanionApplicationDeviceDisappeared(association);
+ }
+
+ // Check if there are other devices associated to the app that are present.
+ if (shouldBindPackage(userId, packageName)) return;
+
+ mCompanionAppController.unbindCompanionApplication(userId, packageName);
}
- void maybeGrantAutoRevokeExemptions() {
- Slog.d(LOG_TAG, "maybeGrantAutoRevokeExemptions()");
- PackageManager pm = getContext().getPackageManager();
- for (int userId : LocalServices.getService(UserManagerInternal.class).getUserIds()) {
- SharedPreferences pref = getContext().getSharedPreferences(
- new File(Environment.getUserSystemDirectory(userId), PREF_FILE_NAME),
- Context.MODE_PRIVATE);
- if (pref.getBoolean(PREF_KEY_AUTO_REVOKE_GRANTS_DONE, false)) {
- continue;
- }
-
- try {
- final List<AssociationInfo> associations =
- mAssociationStore.getAssociationsForUser(userId);
- for (AssociationInfo a : associations) {
- try {
- int uid = pm.getPackageUidAsUser(a.getPackageName(), userId);
- exemptFromAutoRevoke(a.getPackageName(), uid);
- } catch (PackageManager.NameNotFoundException e) {
- Slog.w(LOG_TAG, "Unknown companion package: " + a.getPackageName(), e);
- }
- }
- } finally {
- pref.edit().putBoolean(PREF_KEY_AUTO_REVOKE_GRANTS_DONE, true).apply();
- }
- }
+ private boolean onCompanionApplicationBindingDiedInternal(
+ @UserIdInt int userId, @NonNull String packageName) {
+ // TODO(b/218613015): implement.
+ return false;
}
- @Override
- public void onAssociationChanged(
+ private void onRebindCompanionApplicationTimeoutInternal(
+ @UserIdInt int userId, @NonNull String packageName) {
+ // TODO(b/218613015): implement.
+ }
+
+ /**
+ * @return whether the package should be bound (i.e. at least one of the devices associated with
+ * the package is currently present).
+ */
+ private boolean shouldBindPackage(@UserIdInt int userId, @NonNull String packageName) {
+ final List<AssociationInfo> packageAssociations =
+ mAssociationStore.getAssociationsForPackage(userId, packageName);
+ for (AssociationInfo association : packageAssociations) {
+ if (!association.shouldBindWhenPresent()) continue;
+ if (mDevicePresenceMonitor.isDevicePresent(association.getId())) return true;
+ }
+ return false;
+ }
+
+ private void onAssociationChangedInternal(
@AssociationStore.ChangeType int changeType, AssociationInfo association) {
final int id = association.getId();
final int userId = association.getUserId();
@@ -379,8 +334,6 @@
notifyListeners(userId, updatedAssociations);
}
updateAtm(userId, updatedAssociations);
-
- restartBleScan();
}
private void persistStateForUser(@UserIdInt int userId) {
@@ -417,15 +370,59 @@
}
}
- class CompanionDeviceManagerImpl extends ICompanionDeviceManager.Stub {
+ private void onPackageRemoveOrDataClearedInternal(
+ @UserIdInt int userId, @NonNull String packageName) {
+ if (DEBUG) {
+ Log.i(TAG, "onPackageRemove_Or_DataCleared() u" + userId + "/"
+ + packageName);
+ }
+ // Clear associations.
+ final List<AssociationInfo> associationsForPackage =
+ mAssociationStore.getAssociationsForPackage(userId, packageName);
+ for (AssociationInfo association : associationsForPackage) {
+ mAssociationStore.removeAssociation(association.getId());
+ }
+
+ mCompanionAppController.onPackagesChanged(userId);
+ }
+
+ private void onPackageModifiedInternal(@UserIdInt int userId, @NonNull String packageName) {
+ if (DEBUG) Log.i(TAG, "onPackageModified() u" + userId + "/" + packageName);
+
+ final List<AssociationInfo> associationsForPackage =
+ mAssociationStore.getAssociationsForPackage(userId, packageName);
+ for (AssociationInfo association : associationsForPackage) {
+ updateSpecialAccessPermissionForAssociatedPackage(association);
+ }
+
+ mCompanionAppController.onPackagesChanged(userId);
+ }
+
+ // Revoke associations if the selfManaged companion device does not connect for 3
+ // months for specific profile.
+ private void associationCleanUp(String profile) {
+ for (AssociationInfo ai : mAssociationStore.getAssociations()) {
+ if (ai.isSelfManaged()
+ && profile.equals(ai.getDeviceProfile())
+ && System.currentTimeMillis() - ai.getLastTimeConnectedMs()
+ >= ASSOCIATION_CLEAN_UP_TIME_WINDOW) {
+ Slog.i(TAG, "Removing the association for associationId: "
+ + ai.getId()
+ + " due to the device does not connect for 3 months.");
+ disassociateInternal(ai.getId());
+ }
+ }
+ }
+
+ class CompanionDeviceManagerImpl extends ICompanionDeviceManager.Stub {
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
try {
return super.onTransact(code, data, reply, flags);
} catch (Throwable e) {
- Slog.e(LOG_TAG, "Error during IPC", e);
+ Slog.e(TAG, "Error during IPC", e);
throw ExceptionUtils.propagate(e, RemoteException.class);
}
}
@@ -433,7 +430,7 @@
@Override
public void associate(AssociationRequest request, IAssociationRequestCallback callback,
String packageName, int userId) throws RemoteException {
- Slog.i(LOG_TAG, "associate() "
+ Slog.i(TAG, "associate() "
+ "request=" + request + ", "
+ "package=u" + userId + "/" + packageName);
enforceCallerCanManageAssociationsForPackage(getContext(), userId, packageName,
@@ -451,7 +448,7 @@
if (!checkCallerCanManageCompanionDevice(getContext())) {
// If the caller neither is system nor holds MANAGE_COMPANION_DEVICES: it needs to
// request the feature (also: the caller is the app itself).
- checkUsesFeature(packageName, getCallingUserId());
+ enforceUsesCompanionDeviceFeature(getContext(), userId, packageName);
}
return mAssociationStore.getAssociationsForPackage(userId, packageName);
@@ -487,6 +484,11 @@
@Override
public void legacyDisassociate(String deviceMacAddress, String packageName, int userId) {
+ if (DEBUG) {
+ Log.i(TAG, "legacyDisassociate() pkg=u" + userId + "/" + packageName
+ + ", macAddress=" + deviceMacAddress);
+ }
+
requireNonNull(deviceMacAddress);
requireNonNull(packageName);
@@ -503,6 +505,8 @@
@Override
public void disassociate(int associationId) {
+ if (DEBUG) Log.i(TAG, "disassociate() associationId=" + associationId);
+
final AssociationInfo association = getAssociationWithCallerChecks(associationId);
if (association == null) {
throw new IllegalArgumentException("Association with ID " + associationId + " "
@@ -519,9 +523,9 @@
throws RemoteException {
String callingPackage = component.getPackageName();
checkCanCallNotificationApi(callingPackage);
- //TODO: check userId.
+ // TODO: check userId.
String packageTitle = BidiFormatter.getInstance().unicodeWrap(
- getPackageInfo(callingPackage, userId)
+ getPackageInfo(getContext(), userId, callingPackage)
.applicationInfo
.loadSafeLabel(getContext().getPackageManager(),
PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX,
@@ -575,26 +579,28 @@
@Override
public void registerDevicePresenceListenerService(String deviceAddress,
String callingPackage, int userId) throws RemoteException {
- //TODO: take the userId into account.
+ // TODO: take the userId into account.
registerDevicePresenceListenerActive(callingPackage, deviceAddress, true);
}
@Override
public void unregisterDevicePresenceListenerService(String deviceAddress,
String callingPackage, int userId) throws RemoteException {
- //TODO: take the userId into account.
+ // TODO: take the userId into account.
registerDevicePresenceListenerActive(callingPackage, deviceAddress, false);
}
@Override
public void dispatchMessage(int messageId, int associationId, byte[] message)
throws RemoteException {
- //TODO: b/199427116
+ // TODO(b/199427116): implement.
}
@Override
public void notifyDeviceAppeared(int associationId) {
- final AssociationInfo association = getAssociationWithCallerChecks(associationId);
+ if (DEBUG) Log.i(TAG, "notifyDevice_Appeared() id=" + associationId);
+
+ AssociationInfo association = getAssociationWithCallerChecks(associationId);
if (association == null) {
throw new IllegalArgumentException("Association with ID " + associationId + " "
+ "does not exist "
@@ -607,23 +613,20 @@
+ " is not self-managed. notifyDeviceAppeared(int) can only be called for"
+ " self-managed associations.");
}
-
- if (!mPresentSelfManagedDevices.add(associationId)) {
- Slog.w(LOG_TAG, "Association with ID " + associationId + " is already present");
- return;
- }
-
- AssociationInfo updatedAssociationInfo = AssociationInfo.builder(association)
+ // AssociationInfo class is immutable: create a new AssociationInfo object with updated
+ // timestamp.
+ association = AssociationInfo.builder(association)
.setLastTimeConnected(System.currentTimeMillis())
.build();
- mAssociationStore.updateAssociation(updatedAssociationInfo);
+ mAssociationStore.updateAssociation(association);
- mCompanionDevicePresenceController.onDeviceNotifyAppeared(
- updatedAssociationInfo, getContext(), mMainHandler);
+ mDevicePresenceMonitor.onSelfManagedDeviceConnected(associationId);
}
@Override
public void notifyDeviceDisappeared(int associationId) {
+ if (DEBUG) Log.i(TAG, "notifyDevice_Disappeared() id=" + associationId);
+
final AssociationInfo association = getAssociationWithCallerChecks(associationId);
if (association == null) {
throw new IllegalArgumentException("Association with ID " + associationId + " "
@@ -638,14 +641,7 @@
+ " self-managed associations.");
}
- if (!mPresentSelfManagedDevices.contains(associationId)) {
- Slog.w(LOG_TAG, "Association with ID " + associationId + " is not connected");
- return;
- }
-
- mPresentSelfManagedDevices.remove(associationId);
- mCompanionDevicePresenceController.onDeviceNotifyDisappearedAndUnbind(
- association, getContext(), mMainHandler);
+ mDevicePresenceMonitor.onSelfManagedDeviceDisconnected(associationId);
}
private void registerDevicePresenceListenerActive(String packageName, String deviceAddress,
@@ -656,8 +652,7 @@
final int userId = getCallingUserId();
enforceCallerIsSystemOr(userId, packageName);
- final AssociationInfo association =
- mAssociationStore.getAssociationsForPackageWithAddress(
+ AssociationInfo association = mAssociationStore.getAssociationsForPackageWithAddress(
userId, packageName, deviceAddress);
if (association == null) {
@@ -666,10 +661,14 @@
+ " for user " + userId));
}
- AssociationInfo updatedAssociationInfo = AssociationInfo.builder(association)
+ // AssociationInfo class is immutable: create a new AssociationInfo object with updated
+ // flag.
+ association = AssociationInfo.builder(association)
.setNotifyOnDeviceNearby(active)
.build();
- mAssociationStore.updateAssociation(updatedAssociationInfo);
+ mAssociationStore.updateAssociation(association);
+
+ // TODO(b/218615198): correctly handle the case when the device is currently present.
}
@Override
@@ -677,7 +676,7 @@
byte[] certificate) {
if (!getContext().getPackageManager().hasSigningCertificate(
packageName, certificate, CERT_INPUT_SHA256)) {
- Slog.e(LOG_TAG, "Given certificate doesn't match the package certificate.");
+ Slog.e(TAG, "Given certificate doesn't match the package certificate.");
return;
}
@@ -691,10 +690,12 @@
final int userId = getCallingUserId();
enforceCallerIsSystemOr(userId, callingPackage);
+ if (getCallingUid() == SYSTEM_UID) return;
+
+ enforceUsesCompanionDeviceFeature(getContext(), userId, callingPackage);
checkState(!ArrayUtils.isEmpty(
mAssociationStore.getAssociationsForPackage(userId, callingPackage)),
"App must have an association before calling this API");
- checkUsesFeature(callingPackage, userId);
}
@Override
@@ -720,47 +721,20 @@
}
@Override
- public void dump(@NonNull FileDescriptor fd,
- @NonNull PrintWriter fout,
+ public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter out,
@Nullable String[] args) {
- if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), LOG_TAG, fout)) {
+ if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, out)) {
return;
}
- fout.append("Companion Device Associations:").append('\n');
+ // TODO(b/218615185): mAssociationStore.dump() instead
+ out.append("Companion Device Associations:").append('\n');
for (AssociationInfo a : mAssociationStore.getAssociations()) {
- fout.append(" ").append(a.toString()).append('\n');
+ out.append(" ").append(a.toString()).append('\n');
}
- fout.append("Currently Connected Devices:").append('\n');
- for (int i = 0, size = mCurrentlyConnectedDevices.size(); i < size; i++) {
- fout.append(" ").append(mCurrentlyConnectedDevices.get(i)).append('\n');
- }
-
- fout.append("Currently SelfManaged Connected Devices associationId:").append('\n');
- for (Integer associationId : mPresentSelfManagedDevices) {
- fout.append(" ").append("AssociationId: ").append(
- String.valueOf(associationId)).append('\n');
- }
-
- fout.append("Devices Last Nearby:").append('\n');
- for (int i = 0, size = mDevicesLastNearby.size(); i < size; i++) {
- String device = mDevicesLastNearby.keyAt(i);
- Date time = mDevicesLastNearby.valueAt(i);
- fout.append(" ").append(device).append(" -> ")
- .append(sDateFormat.format(time)).append('\n');
- }
-
- fout.append("Device Listener Services State:").append('\n');
- for (int i = 0, size = mCompanionDevicePresenceController.mBoundServices.size();
- i < size; i++) {
- int userId = mCompanionDevicePresenceController.mBoundServices.keyAt(i);
- fout.append(" ")
- .append("u").append(Integer.toString(userId)).append(": ")
- .append(Objects.toString(
- mCompanionDevicePresenceController.mBoundServices.valueAt(i)))
- .append('\n');
- }
+ // TODO(b/218615185): mDevicePresenceMonitor.dump()
+ // TODO(b/218615185): mCompanionAppController.dump()
}
}
@@ -784,7 +758,7 @@
final AssociationInfo association = new AssociationInfo(id, userId, packageName,
macAddress, displayName, deviceProfile, selfManaged, false, timestamp,
Long.MAX_VALUE);
- Slog.i(LOG_TAG, "New CDM association created=" + association);
+ Slog.i(TAG, "New CDM association created=" + association);
mAssociationStore.addAssociation(association);
// If the "Device Profile" is specified, make the companion application a holder of the
@@ -862,52 +836,50 @@
}
}
- //TODO: also revoke notification access
+ // TODO: also revoke notification access
void disassociateInternal(int associationId) {
- onAssociationPreRemove(associationId);
- mAssociationStore.removeAssociation(associationId);
- }
-
- void onAssociationPreRemove(int associationId) {
final AssociationInfo association = mAssociationStore.getAssociationById(associationId);
- if (association.isNotifyOnDeviceNearby()
- || (association.isSelfManaged()
- && mPresentSelfManagedDevices.contains(association.getId()))) {
- mCompanionDevicePresenceController.unbindDevicePresenceListener(
- association.getPackageName(), association.getUserId());
- }
+ final int userId = association.getUserId();
+ final String packageName = association.getPackageName();
+ final String deviceProfile = association.getDeviceProfile();
- String deviceProfile = association.getDeviceProfile();
+ final boolean wasPresent = mDevicePresenceMonitor.isDevicePresent(associationId);
+
+ // Removing the association.
+ mAssociationStore.removeAssociation(associationId);
+
+ final List<AssociationInfo> otherAssociations =
+ mAssociationStore.getAssociationsForPackage(userId, packageName);
+
+ // Check if the package is associated with other devices with the same profile.
+ // If not: take away the role.
if (deviceProfile != null) {
- AssociationInfo otherAssociationWithDeviceProfile = find(
- mAssociationStore.getAssociationsForUser(association.getUserId()),
- a -> !a.equals(association) && deviceProfile.equals(a.getDeviceProfile()));
- if (otherAssociationWithDeviceProfile != null) {
- Slog.i(LOG_TAG, "Not revoking " + deviceProfile
- + " for " + association
- + " - profile still present in " + otherAssociationWithDeviceProfile);
- } else {
- Binder.withCleanCallingIdentity(
- () -> removeRoleHolderForAssociation(getContext(), association));
+ final boolean shouldKeepTheRole = any(otherAssociations,
+ it -> deviceProfile.equals(it.getDeviceProfile()));
+ if (!shouldKeepTheRole) {
+ Binder.withCleanCallingIdentity(() ->
+ removeRoleHolderForAssociation(getContext(), association));
}
}
+
+ if (!wasPresent || !association.isNotifyOnDeviceNearby()) return;
+ // The device was connected and the app was notified: check if we need to unbind the app
+ // now.
+ final boolean shouldStayBound = any(otherAssociations,
+ it -> it.isNotifyOnDeviceNearby()
+ && mDevicePresenceMonitor.isDevicePresent(it.getId()));
+ if (shouldStayBound) return;
+ mCompanionAppController.unbindCompanionApplication(userId, packageName);
}
private void updateSpecialAccessPermissionForAssociatedPackage(AssociationInfo association) {
- PackageInfo packageInfo = getPackageInfo(
- association.getPackageName(),
- association.getUserId());
- if (packageInfo == null) {
- return;
- }
+ final PackageInfo packageInfo =
+ getPackageInfo(getContext(), association.getUserId(), association.getPackageName());
- Binder.withCleanCallingIdentity(obtainRunnable(CompanionDeviceManagerService::
- updateSpecialAccessPermissionAsSystem, this, association, packageInfo)
- .recycleOnUse());
+ Binder.withCleanCallingIdentity(() -> updateSpecialAccessPermissionAsSystem(packageInfo));
}
- private void updateSpecialAccessPermissionAsSystem(
- AssociationInfo association, PackageInfo packageInfo) {
+ private void updateSpecialAccessPermissionAsSystem(PackageInfo packageInfo) {
if (containsEither(packageInfo.requestedPermissions,
android.Manifest.permission.RUN_IN_BACKGROUND,
android.Manifest.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND)) {
@@ -916,7 +888,7 @@
try {
mPowerWhitelistManager.removeFromWhitelist(packageInfo.packageName);
} catch (UnsupportedOperationException e) {
- Slog.w(LOG_TAG, packageInfo.packageName + " can't be removed from power save"
+ Slog.w(TAG, packageInfo.packageName + " can't be removed from power save"
+ " whitelist. It might due to the package is whitelisted by the system.");
}
}
@@ -935,10 +907,6 @@
}
exemptFromAutoRevoke(packageInfo.packageName, packageInfo.applicationInfo.uid);
-
- if (association.isNotifyOnDeviceNearby()) {
- restartBleScan();
- }
}
private void exemptFromAutoRevoke(String packageName, int uid) {
@@ -949,23 +917,10 @@
packageName,
AppOpsManager.MODE_IGNORED);
} catch (RemoteException e) {
- Slog.w(LOG_TAG,
- "Error while granting auto revoke exemption for " + packageName, e);
+ Slog.w(TAG, "Error while granting auto revoke exemption for " + packageName, e);
}
}
- private static <T> boolean containsEither(T[] array, T a, T b) {
- return ArrayUtils.contains(array, a) || ArrayUtils.contains(array, b);
- }
-
- @Nullable
- private PackageInfo getPackageInfo(String packageName, int userId) {
- final int flags = PackageManager.GET_PERMISSIONS | PackageManager.GET_CONFIGURATIONS;
- return Binder.withCleanCallingIdentity(
- () -> getContext().getPackageManager()
- .getPackageInfoAsUser(packageName, flags , userId));
- }
-
private void updateAtm(int userId, List<AssociationInfo> associations) {
final Set<Integer> companionAppUids = new ArraySet<>();
for (AssociationInfo association : associations) {
@@ -981,263 +936,86 @@
}
}
- void onDeviceConnected(String address) {
- Slog.d(LOG_TAG, "onDeviceConnected(address = " + address + ")");
- mCurrentlyConnectedDevices.add(address);
- onDeviceNearby(address);
- }
+ private void maybeGrantAutoRevokeExemptions() {
+ Slog.d(TAG, "maybeGrantAutoRevokeExemptions()");
- void onDeviceDisconnected(String address) {
- Slog.d(LOG_TAG, "onDeviceDisconnected(address = " + address + ")");
-
- mCurrentlyConnectedDevices.remove(address);
-
- Date lastSeen = mDevicesLastNearby.get(address);
- if (isDeviceDisappeared(lastSeen)) {
- onDeviceDisappeared(address);
- unscheduleTriggerDeviceDisappearedRunnable(address);
- }
- }
-
- private boolean isDeviceDisappeared(Date lastSeen) {
- return lastSeen == null || System.currentTimeMillis() - lastSeen.getTime()
- >= DEVICE_DISAPPEARED_UNBIND_TIMEOUT_MS;
- }
-
- private class BleScanCallback extends ScanCallback {
- @Override
- public void onScanResult(int callbackType, ScanResult result) {
- if (DEBUG) {
- Slog.i(LOG_TAG, "onScanResult(callbackType = "
- + callbackType + ", result = " + result + ")");
- }
-
- onDeviceNearby(result.getDevice().getAddress());
- }
-
- @Override
- public void onBatchScanResults(List<ScanResult> results) {
- for (int i = 0, size = results.size(); i < size; i++) {
- onScanResult(CALLBACK_TYPE_ALL_MATCHES, results.get(i));
- }
- }
-
- @Override
- public void onScanFailed(int errorCode) {
- if (errorCode == SCAN_FAILED_ALREADY_STARTED) {
- // ignore - this might happen if BT tries to auto-restore scans for us in the
- // future
- Slog.i(LOG_TAG, "Ignoring BLE scan error: SCAN_FAILED_ALREADY_STARTED");
- } else {
- Slog.w(LOG_TAG, "Failed to start BLE scan: error " + errorCode);
- }
- }
- }
-
- private class BleStateBroadcastReceiver extends BroadcastReceiver {
-
- final IntentFilter mIntentFilter =
- new IntentFilter(BluetoothAdapter.ACTION_BLE_STATE_CHANGED);
-
- @Override
- public void onReceive(Context context, Intent intent) {
- int previousState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, -1);
- int newState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
- Slog.d(LOG_TAG, "Received BT state transition broadcast: "
- + BluetoothAdapter.nameForState(previousState)
- + " -> " + BluetoothAdapter.nameForState(newState));
-
- boolean bleOn = newState == BluetoothAdapter.STATE_ON
- || newState == BluetoothAdapter.STATE_BLE_ON;
- if (bleOn) {
- if (mBluetoothAdapter.getBluetoothLeScanner() != null) {
- startBleScan();
- } else {
- Slog.wtf(LOG_TAG, "BLE on, but BluetoothLeScanner == null");
- }
- }
- }
- }
-
- private class UnbindDeviceListenersRunnable implements Runnable {
-
- public String getJobId(String address) {
- return "CDM_deviceGone_unbind_" + address;
- }
-
- @Override
- public void run() {
- int size = mDevicesLastNearby.size();
- for (int i = 0; i < size; i++) {
- String address = mDevicesLastNearby.keyAt(i);
- Date lastNearby = mDevicesLastNearby.valueAt(i);
-
- if (isDeviceDisappeared(lastNearby)) {
- final List<AssociationInfo> associations =
- mAssociationStore.getAssociationsByAddress(address);
- for (AssociationInfo association : associations) {
- if (association.isNotifyOnDeviceNearby()) {
- mCompanionDevicePresenceController.unbindDevicePresenceListener(
- association.getPackageName(), association.getUserId());
- }
- }
- }
- }
- }
- }
-
- private class TriggerDeviceDisappearedRunnable implements Runnable {
-
- private final String mAddress;
-
- TriggerDeviceDisappearedRunnable(String address) {
- mAddress = address;
- }
-
- public void schedule() {
- mMainHandler.removeCallbacks(this);
- mMainHandler.postDelayed(this, this, DEVICE_DISAPPEARED_TIMEOUT_MS);
- }
-
- @Override
- public void run() {
- Slog.d(LOG_TAG, "TriggerDeviceDisappearedRunnable.run(address = " + mAddress + ")");
- if (!mCurrentlyConnectedDevices.contains(mAddress)) {
- onDeviceDisappeared(mAddress);
- }
- }
- }
-
- private void unscheduleTriggerDeviceDisappearedRunnable(String address) {
- Runnable r = mTriggerDeviceDisappearedRunnables.get(address);
- if (r != null) {
- Slog.d(LOG_TAG,
- "unscheduling TriggerDeviceDisappearedRunnable(address = " + address + ")");
- mMainHandler.removeCallbacks(r);
- }
- }
-
- private void onDeviceNearby(String address) {
- Date timestamp = new Date();
- Date oldTimestamp = mDevicesLastNearby.put(address, timestamp);
-
- cancelUnbindDeviceListener(address);
-
- mTriggerDeviceDisappearedRunnables
- .computeIfAbsent(address, addr -> new TriggerDeviceDisappearedRunnable(address))
- .schedule();
-
- // Avoid spamming the app if device is already known to be nearby
- boolean justAppeared = oldTimestamp == null
- || timestamp.getTime() - oldTimestamp.getTime() >= DEVICE_DISAPPEARED_TIMEOUT_MS;
- if (justAppeared) {
- Slog.i(LOG_TAG, "onDeviceNearby(justAppeared, address = " + address + ")");
- final List<AssociationInfo> associations =
- mAssociationStore.getAssociationsByAddress(address);
- for (AssociationInfo association : associations) {
- if (association.isNotifyOnDeviceNearby()) {
- mCompanionDevicePresenceController.onDeviceNotifyAppeared(association,
- getContext(), mMainHandler);
- }
- }
- }
- }
-
- private void onDeviceDisappeared(String address) {
- Slog.i(LOG_TAG, "onDeviceDisappeared(address = " + address + ")");
-
- boolean hasDeviceListeners = false;
- final List<AssociationInfo> associations =
- mAssociationStore.getAssociationsByAddress(address);
- for (AssociationInfo association : associations) {
- if (association.isNotifyOnDeviceNearby()) {
- mCompanionDevicePresenceController.onDeviceNotifyDisappeared(
- association, getContext(), mMainHandler);
- hasDeviceListeners = true;
- }
- }
-
- cancelUnbindDeviceListener(address);
- if (hasDeviceListeners) {
- mMainHandler.postDelayed(
- mUnbindDeviceListenersRunnable,
- mUnbindDeviceListenersRunnable.getJobId(address),
- DEVICE_DISAPPEARED_UNBIND_TIMEOUT_MS);
- }
- }
-
- private void cancelUnbindDeviceListener(String address) {
- mMainHandler.removeCallbacks(
- mUnbindDeviceListenersRunnable, mUnbindDeviceListenersRunnable.getJobId(address));
- }
-
- private void initBleScanning() {
- Slog.i(LOG_TAG, "initBleScanning()");
-
- boolean bluetoothReady = mBluetoothAdapter.registerServiceLifecycleCallback(
- new BluetoothAdapter.ServiceLifecycleCallback() {
- @Override
- public void onBluetoothServiceUp() {
- Slog.i(LOG_TAG, "Bluetooth stack is up");
- startBleScan();
- }
-
- @Override
- public void onBluetoothServiceDown() {
- Slog.w(LOG_TAG, "Bluetooth stack is down");
- }
- });
- if (bluetoothReady) {
- startBleScan();
- }
- }
-
- void startBleScan() {
- Slog.i(LOG_TAG, "startBleScan()");
-
- List<ScanFilter> filters = getBleScanFilters();
- if (filters.isEmpty()) {
- return;
- }
- BluetoothLeScanner scanner = mBluetoothAdapter.getBluetoothLeScanner();
- if (scanner == null) {
- Slog.w(LOG_TAG, "scanner == null (likely BLE isn't ON yet)");
- } else {
- scanner.startScan(
- filters,
- new ScanSettings.Builder().setScanMode(SCAN_MODE_LOW_POWER).build(),
- mBleScanCallback);
- }
- }
-
- void restartBleScan() {
- if (mBluetoothAdapter.getBluetoothLeScanner() != null) {
- mBluetoothAdapter.getBluetoothLeScanner().stopScan(mBleScanCallback);
- startBleScan();
- } else {
- Slog.w(LOG_TAG, "BluetoothLeScanner is null (likely BLE isn't ON yet).");
- }
- }
-
- private List<ScanFilter> getBleScanFilters() {
- ArrayList<ScanFilter> result = new ArrayList<>();
- ArraySet<String> addressesSeen = new ArraySet<>();
- for (AssociationInfo association : mAssociationStore.getAssociations()) {
- if (association.isSelfManaged()) {
+ PackageManager pm = getContext().getPackageManager();
+ for (int userId : LocalServices.getService(UserManagerInternal.class).getUserIds()) {
+ SharedPreferences pref = getContext().getSharedPreferences(
+ new File(Environment.getUserSystemDirectory(userId), PREF_FILE_NAME),
+ Context.MODE_PRIVATE);
+ if (pref.getBoolean(PREF_KEY_AUTO_REVOKE_GRANTS_DONE, false)) {
continue;
}
- String address = association.getDeviceMacAddressAsString();
- if (addressesSeen.contains(address)) {
- continue;
- }
- if (association.isNotifyOnDeviceNearby()) {
- result.add(new ScanFilter.Builder().setDeviceAddress(address).build());
- addressesSeen.add(address);
+
+ try {
+ final List<AssociationInfo> associations =
+ mAssociationStore.getAssociationsForUser(userId);
+ for (AssociationInfo a : associations) {
+ try {
+ int uid = pm.getPackageUidAsUser(a.getPackageName(), userId);
+ exemptFromAutoRevoke(a.getPackageName(), uid);
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.w(TAG, "Unknown companion package: " + a.getPackageName(), e);
+ }
+ }
+ } finally {
+ pref.edit().putBoolean(PREF_KEY_AUTO_REVOKE_GRANTS_DONE, true).apply();
}
}
- return result;
}
+ private final AssociationStore.OnChangeListener mAssociationStoreChangeListener =
+ new AssociationStore.OnChangeListener() {
+ @Override
+ public void onAssociationChanged(int changeType, AssociationInfo association) {
+ onAssociationChangedInternal(changeType, association);
+ }
+ };
+
+ private final CompanionDevicePresenceMonitor.Callback mDevicePresenceCallback =
+ new CompanionDevicePresenceMonitor.Callback() {
+ @Override
+ public void onDeviceAppeared(int associationId) {
+ onDeviceAppearedInternal(associationId);
+ }
+
+ @Override
+ public void onDeviceDisappeared(int associationId) {
+ onDeviceDisappearedInternal(associationId);
+ }
+ };
+
+ private final CompanionApplicationController.Callback mApplicationControllerCallback =
+ new CompanionApplicationController.Callback() {
+ @Override
+ public boolean onCompanionApplicationBindingDied(int userId, @NonNull String packageName) {
+ return onCompanionApplicationBindingDiedInternal(userId, packageName);
+ }
+
+ @Override
+ public void onRebindCompanionApplicationTimeout(int userId, @NonNull String packageName) {
+ onRebindCompanionApplicationTimeoutInternal(userId, packageName);
+ }
+ };
+
+ private final PackageMonitor mPackageMonitor = new PackageMonitor() {
+ @Override
+ public void onPackageRemoved(String packageName, int uid) {
+ onPackageRemoveOrDataClearedInternal(getChangingUserId(), packageName);
+ }
+
+ @Override
+ public void onPackageDataCleared(String packageName, int uid) {
+ onPackageRemoveOrDataClearedInternal(getChangingUserId(), packageName);
+ }
+
+ @Override
+ public void onPackageModified(String packageName) {
+ onPackageModifiedInternal(getChangingUserId(), packageName);
+ }
+ };
+
static int getFirstAssociationIdForUser(@UserIdInt int userId) {
// We want the IDs to start from 1, not 0.
return userId * ASSOCIATIONS_IDS_PER_USER_RANGE + 1;
@@ -1247,82 +1025,6 @@
return (userId + 1) * ASSOCIATIONS_IDS_PER_USER_RANGE;
}
- private class BluetoothDeviceConnectedListener
- extends BluetoothAdapter.BluetoothConnectionCallback {
- @Override
- public void onDeviceConnected(BluetoothDevice device) {
- CompanionDeviceManagerService.this.onDeviceConnected(device.getAddress());
- }
-
- @Override
- 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());
- }
- }
-
- void checkUsesFeature(@NonNull String pkg, @UserIdInt int userId) {
- if (getCallingUid() == SYSTEM_UID) return;
-
- final FeatureInfo[] requestedFeatures = getPackageInfo(pkg, userId).reqFeatures;
- if (requestedFeatures != null) {
- for (int i = 0; i < requestedFeatures.length; i++) {
- if (FEATURE_COMPANION_DEVICE_SETUP.equals(requestedFeatures[i].name)) return;
- }
- }
-
- throw new IllegalStateException("Must declare uses-feature "
- + FEATURE_COMPANION_DEVICE_SETUP
- + " in manifest to use this API");
- }
-
- private void registerPackageMonitor() {
- new PackageMonitor() {
- @Override
- public void onPackageRemoved(String packageName, int uid) {
- final int userId = getChangingUserId();
- Slog.i(LOG_TAG, "onPackageRemoved() u" + userId + "/" + packageName);
-
- clearAssociationForPackage(userId, packageName);
- }
-
- @Override
- public void onPackageDataCleared(String packageName, int uid) {
- final int userId = getChangingUserId();
- Slog.i(LOG_TAG, "onPackageDataCleared() u" + userId + "/" + packageName);
-
- clearAssociationForPackage(userId, packageName);
- }
-
- @Override
- public void onPackageModified(String packageName) {
- final int userId = getChangingUserId();
- Slog.i(LOG_TAG, "onPackageModified() u" + userId + "/" + packageName);
-
- final List<AssociationInfo> associationsForPackage =
- mAssociationStore.getAssociationsForPackage(userId, packageName);
- for (AssociationInfo association : associationsForPackage) {
- updateSpecialAccessPermissionForAssociatedPackage(association);
- }
- }
- }.register(getContext(), FgThread.get().getLooper(), UserHandle.ALL, true);
- }
-
- private void clearAssociationForPackage(@UserIdInt int userId, @NonNull String packageName) {
- if (DEBUG) Slog.d(LOG_TAG, "clearAssociationForPackage() u" + userId + "/" + packageName);
-
- // First, unbind CompanionService if needed.
- mCompanionDevicePresenceController.unbindDevicePresenceListener(packageName, userId);
-
- // Clear associations.
- final List<AssociationInfo> associationsForPackage =
- mAssociationStore.getAssociationsForPackage(userId, packageName);
- for (AssociationInfo association : associationsForPackage) {
- mAssociationStore.removeAssociation(association.getId());
- }
- }
-
private static Map<String, Set<Integer>> deepUnmodifiableCopy(Map<String, Set<Integer>> orig) {
final Map<String, Set<Integer>> copy = new HashMap<>();
@@ -1334,16 +1036,14 @@
return Collections.unmodifiableMap(copy);
}
- private final class LocalService extends CompanionDeviceManagerServiceInternal {
- private final CompanionDeviceManagerService mService;
+ private static <T> boolean containsEither(T[] array, T a, T b) {
+ return ArrayUtils.contains(array, a) || ArrayUtils.contains(array, b);
+ }
- LocalService(CompanionDeviceManagerService service) {
- mService = service;
- }
-
+ private class LocalService extends CompanionDeviceManagerServiceInternal {
@Override
public void associationCleanUp(String profile) {
- mService.associationCleanUp(profile);
+ CompanionDeviceManagerService.this.associationCleanUp(profile);
}
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDevicePresenceController.java b/services/companion/java/com/android/server/companion/CompanionDevicePresenceController.java
deleted file mode 100644
index fc66817..0000000
--- a/services/companion/java/com/android/server/companion/CompanionDevicePresenceController.java
+++ /dev/null
@@ -1,238 +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.companion;
-
-import static android.Manifest.permission.BIND_COMPANION_DEVICE_SERVICE;
-import static android.content.Context.BIND_IMPORTANT;
-
-import static com.android.internal.util.CollectionUtils.filter;
-
-import android.annotation.NonNull;
-import android.companion.AssociationInfo;
-import android.companion.CompanionDeviceService;
-import android.companion.ICompanionDeviceService;
-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.Handler;
-import android.util.ArrayMap;
-import android.util.Slog;
-
-import com.android.internal.infra.PerUser;
-import com.android.internal.infra.ServiceConnector;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * This class creates/removes {@link ServiceConnector}s between {@link CompanionDeviceService} and
- * the companion apps. The controller also will notify the companion apps with device status.
- */
-public class CompanionDevicePresenceController {
- private static final String LOG_TAG = "CompanionDevicePresenceController";
- PerUser<ArrayMap<String, List<BoundService>>> mBoundServices;
- private static final String META_DATA_KEY_PRIMARY = "android.companion.primary";
- private final CompanionDeviceManagerService mService;
-
- public CompanionDevicePresenceController(CompanionDeviceManagerService service) {
- mService = service;
- mBoundServices = new PerUser<ArrayMap<String, List<BoundService>>>() {
- @NonNull
- @Override
- protected ArrayMap<String, List<BoundService>> create(int userId) {
- return new ArrayMap<>();
- }
- };
- }
-
- void onDeviceNotifyAppeared(AssociationInfo association, Context context, Handler handler) {
- for (BoundService boundService : getDeviceListenerServiceConnector(
- association, context, handler)) {
- if (boundService.mIsPrimary) {
- Slog.i(LOG_TAG,
- "Sending onDeviceAppeared to " + association.getPackageName() + ")");
- boundService.mServiceConnector.run(
- service -> service.onDeviceAppeared(association));
- } else {
- Slog.i(LOG_TAG, "Connecting to " + boundService.mComponentName);
- boundService.mServiceConnector.connect();
- }
- }
- }
-
- void onDeviceNotifyDisappeared(AssociationInfo association, Context context, Handler handler) {
- for (BoundService boundService : getDeviceListenerServiceConnector(
- association, context, handler)) {
- if (boundService.mIsPrimary) {
- Slog.i(LOG_TAG,
- "Sending onDeviceDisappeared to " + association.getPackageName() + ")");
- boundService.mServiceConnector.run(service ->
- service.onDeviceDisappeared(association));
- }
- }
- }
-
- void onDeviceNotifyDisappearedAndUnbind(AssociationInfo association,
- Context context, Handler handler) {
- for (BoundService boundService : getDeviceListenerServiceConnector(
- association, context, handler)) {
- if (boundService.mIsPrimary) {
- Slog.i(LOG_TAG,
- "Sending onDeviceDisappeared to " + association.getPackageName() + ")");
- boundService.mServiceConnector.post(
- service -> {
- service.onDeviceDisappeared(association);
- }).thenRun(() -> unbindDevicePresenceListener(
- association.getPackageName(), association.getUserId()));
- }
- }
- }
-
- void unbindDevicePresenceListener(String packageName, int userId) {
- List<BoundService> boundServices = mBoundServices.forUser(userId)
- .remove(packageName);
- if (boundServices != null) {
- for (BoundService boundService: boundServices) {
- Slog.d(LOG_TAG, "Unbinding the serviceConnector: " + boundService.mComponentName);
- boundService.mServiceConnector.unbind();
- }
- }
- }
-
- private List<BoundService> getDeviceListenerServiceConnector(AssociationInfo a, Context context,
- Handler handler) {
- return mBoundServices.forUser(a.getUserId()).computeIfAbsent(
- a.getPackageName(),
- pkg -> createDeviceListenerServiceConnector(a, context, handler));
- }
-
- private List<BoundService> createDeviceListenerServiceConnector(AssociationInfo a,
- Context context, Handler handler) {
- List<ResolveInfo> resolveInfos = context
- .getPackageManager()
- .queryIntentServicesAsUser(new Intent(CompanionDeviceService.SERVICE_INTERFACE),
- PackageManager.GET_META_DATA, a.getUserId());
- List<ResolveInfo> packageResolveInfos = filter(resolveInfos,
- info -> Objects.equals(info.serviceInfo.packageName, a.getPackageName()));
- List<BoundService> serviceConnectors = new ArrayList<>();
- if (!validatePackageInfo(packageResolveInfos, a)) {
- return serviceConnectors;
- }
- for (ResolveInfo packageResolveInfo : packageResolveInfos) {
- boolean isPrimary = (packageResolveInfo.serviceInfo.metaData != null
- && packageResolveInfo.serviceInfo.metaData.getBoolean(META_DATA_KEY_PRIMARY))
- || packageResolveInfos.size() == 1;
- ComponentName componentName = packageResolveInfo.serviceInfo.getComponentName();
-
- Slog.i(LOG_TAG, "Initializing CompanionDeviceService binding for " + componentName);
-
- ServiceConnector<ICompanionDeviceService> serviceConnector =
- new ServiceConnector.Impl<ICompanionDeviceService>(context,
- new Intent(CompanionDeviceService.SERVICE_INTERFACE).setComponent(
- componentName), BIND_IMPORTANT, a.getUserId(),
- ICompanionDeviceService.Stub::asInterface) {
- @Override
- protected long getAutoDisconnectTimeoutMs() {
- // Service binding is managed manually based on corresponding device
- // being nearby
- return -1;
- }
-
- @Override
- public void binderDied() {
- super.binderDied();
- if (a.isSelfManaged()) {
- mBoundServices.forUser(a.getUserId()).remove(a.getPackageName());
- mService.mPresentSelfManagedDevices.remove(a.getId());
- } else {
- // Re-connect to the service if process gets killed
- handler.postDelayed(
- this::connect,
- CompanionDeviceManagerService
- .DEVICE_LISTENER_DIED_REBIND_TIMEOUT_MS);
- }
- }
- };
-
- serviceConnectors.add(new BoundService(componentName, isPrimary, serviceConnector));
- }
- return serviceConnectors;
- }
-
- private boolean validatePackageInfo(List<ResolveInfo> packageResolveInfos,
- AssociationInfo association) {
- if (packageResolveInfos.size() == 0 || packageResolveInfos.size() > 5) {
- Slog.e(LOG_TAG, "Device presence listener package must have at least one and not "
- + "more than five CompanionDeviceService(s) declared. But "
- + association.getPackageName()
- + " has " + packageResolveInfos.size());
- return false;
- }
-
- int primaryCount = 0;
- for (ResolveInfo packageResolveInfo : packageResolveInfos) {
- String servicePermission = packageResolveInfo.serviceInfo.permission;
- if (!BIND_COMPANION_DEVICE_SERVICE.equals(servicePermission)) {
- Slog.e(LOG_TAG, "Binding CompanionDeviceService must have "
- + BIND_COMPANION_DEVICE_SERVICE + " permission.");
- return false;
- }
-
- if (packageResolveInfo.serviceInfo.metaData != null
- && packageResolveInfo.serviceInfo.metaData.getBoolean(META_DATA_KEY_PRIMARY)) {
- primaryCount++;
- if (primaryCount > 1) {
- Slog.e(LOG_TAG, "Must have exactly one primary CompanionDeviceService "
- + "to be bound but "
- + association.getPackageName() + "has " + primaryCount);
- return false;
- }
- }
- }
-
- if (packageResolveInfos.size() > 1 && primaryCount == 0) {
- Slog.e(LOG_TAG, "Must have exactly one primary CompanionDeviceService "
- + "to be bound when declare more than one CompanionDeviceService but "
- + association.getPackageName() + " has " + primaryCount);
- return false;
- }
-
- if (packageResolveInfos.size() == 1 && primaryCount != 0) {
- Slog.w(LOG_TAG, "Do not need the primary metadata if there's only one"
- + " CompanionDeviceService " + "but " + association.getPackageName()
- + " has " + primaryCount);
- }
-
- return true;
- }
-
- private static class BoundService {
- private final ComponentName mComponentName;
- private final boolean mIsPrimary;
- private final ServiceConnector<ICompanionDeviceService> mServiceConnector;
-
- BoundService(ComponentName componentName,
- boolean isPrimary, ServiceConnector<ICompanionDeviceService> serviceConnector) {
- this.mComponentName = componentName;
- this.mIsPrimary = isPrimary;
- this.mServiceConnector = serviceConnector;
- }
- }
-}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java b/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
index 777917c..f2a58b7 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
@@ -17,6 +17,7 @@
package com.android.server.companion;
import static android.content.Context.BIND_IMPORTANT;
+import static android.os.Process.THREAD_PRIORITY_DEFAULT;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -28,10 +29,12 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import com.android.internal.infra.ServiceConnector;
+import com.android.server.ServiceThread;
/**
* Manages a connection (binding) to an instance of {@link CompanionDeviceService} running in the
@@ -106,6 +109,19 @@
return ICompanionDeviceService.Stub.asInterface(service);
}
+ /**
+ * Overrides {@link ServiceConnector.Impl#getJobHandler()} to provide an alternative Thread
+ * ("in form of" a {@link Handler}) to process jobs on.
+ * <p>
+ * (By default, {@link ServiceConnector.Impl} process jobs on the
+ * {@link android.os.Looper#getMainLooper() MainThread} which is a shared singleton thread
+ * within system_server and thus tends to get heavily congested)
+ */
+ @Override
+ protected @NonNull Handler getJobHandler() {
+ return getServiceThread().getThreadHandler();
+ }
+
@Override
protected long getAutoDisconnectTimeoutMs() {
// Do NOT auto-disconnect.
@@ -116,4 +132,25 @@
return new Intent(CompanionDeviceService.SERVICE_INTERFACE)
.setComponent(componentName);
}
+
+ private static @NonNull ServiceThread getServiceThread() {
+ if (sServiceThread == null) {
+ synchronized (CompanionDeviceManagerService.class) {
+ if (sServiceThread == null) {
+ sServiceThread = new ServiceThread("companion-device-service-connector",
+ THREAD_PRIORITY_DEFAULT, /* allowIo */ false);
+ sServiceThread.start();
+ }
+ }
+ }
+ return sServiceThread;
+ }
+
+ /**
+ * A worker thread for the {@link ServiceConnector} to process jobs on.
+ *
+ * <p>
+ * Do NOT reference directly, use {@link #getServiceThread()} method instead.
+ */
+ private static volatile @Nullable ServiceThread sServiceThread;
}
diff --git a/services/companion/java/com/android/server/companion/PackageUtils.java b/services/companion/java/com/android/server/companion/PackageUtils.java
index fcb14a4..a2b2059 100644
--- a/services/companion/java/com/android/server/companion/PackageUtils.java
+++ b/services/companion/java/com/android/server/companion/PackageUtils.java
@@ -18,10 +18,9 @@
import static android.content.pm.PackageManager.FEATURE_COMPANION_DEVICE_SETUP;
import static android.content.pm.PackageManager.GET_CONFIGURATIONS;
-import static android.content.pm.PackageManager.GET_META_DATA;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
-import static com.android.server.companion.CompanionDeviceManagerService.LOG_TAG;
+import static com.android.server.companion.CompanionDeviceManagerService.TAG;
import android.Manifest;
import android.annotation.NonNull;
@@ -53,7 +52,8 @@
final class PackageUtils {
private static final Intent COMPANION_SERVICE_INTENT =
new Intent(CompanionDeviceService.SERVICE_INTERFACE);
- private static final String META_DATA_PRIMARY_TAG = "android.companion.primary";
+ private static final String PROPERTY_PRIMARY_TAG =
+ "android.companion.PROPERTY_PRIMARY_COMPANION_DEVICE_SERVICE";
static @Nullable PackageInfo getPackageInfo(@NonNull Context context,
@UserIdInt int userId, @NonNull String packageName) {
@@ -84,9 +84,8 @@
static @NonNull Map<String, List<ComponentName>> getCompanionServicesForUser(
@NonNull Context context, @UserIdInt int userId) {
final PackageManager pm = context.getPackageManager();
- final ResolveInfoFlags flags = ResolveInfoFlags.of(GET_META_DATA);
- final List<ResolveInfo> companionServices =
- pm.queryIntentServicesAsUser(COMPANION_SERVICE_INTENT, flags, userId);
+ final List<ResolveInfo> companionServices = pm.queryIntentServicesAsUser(
+ COMPANION_SERVICE_INTENT, ResolveInfoFlags.of(0), userId);
final Map<String, List<ComponentName>> packageNameToServiceInfoList = new HashMap<>();
@@ -96,7 +95,7 @@
final boolean requiresPermission = Manifest.permission.BIND_COMPANION_DEVICE_SERVICE
.equals(resolveInfo.serviceInfo.permission);
if (!requiresPermission) {
- Slog.w(LOG_TAG, "CompanionDeviceService "
+ Slog.w(TAG, "CompanionDeviceService "
+ service.getComponentName().flattenToShortString() + " must require "
+ "android.permission.BIND_COMPANION_DEVICE_SERVICE");
continue;
@@ -109,7 +108,8 @@
service.packageName, it -> new LinkedList<>());
final ComponentName componentName = service.getComponentName();
- if (isPrimaryCompanionDeviceService(service)) {
+
+ if (isPrimaryCompanionDeviceService(pm, componentName)) {
// "Primary" service should be at the head of the list.
services.addFirst(componentName);
} else {
@@ -120,7 +120,12 @@
return packageNameToServiceInfoList;
}
- private static boolean isPrimaryCompanionDeviceService(ServiceInfo service) {
- return service.metaData != null && service.metaData.getBoolean(META_DATA_PRIMARY_TAG);
+ private static boolean isPrimaryCompanionDeviceService(@NonNull PackageManager pm,
+ @NonNull ComponentName componentName) {
+ try {
+ return pm.getProperty(PROPERTY_PRIMARY_TAG, componentName).getBoolean();
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
}
}
diff --git a/services/companion/java/com/android/server/companion/PermissionsUtils.java b/services/companion/java/com/android/server/companion/PermissionsUtils.java
index 0e593e1..ac1bf1b 100644
--- a/services/companion/java/com/android/server/companion/PermissionsUtils.java
+++ b/services/companion/java/com/android/server/companion/PermissionsUtils.java
@@ -36,6 +36,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.companion.AssociationInfo;
import android.companion.AssociationRequest;
import android.companion.CompanionDeviceManager;
import android.content.Context;
@@ -190,6 +191,19 @@
return checkCallerCanManageCompanionDevice(context);
}
+ static @Nullable AssociationInfo sanitizeWithCallerChecks(@NonNull Context context,
+ @Nullable AssociationInfo association) {
+ if (association == null) return null;
+
+ final int userId = association.getUserId();
+ final String packageName = association.getPackageName();
+ if (!checkCallerCanManageAssociationsForPackage(context, userId, packageName)) {
+ return null;
+ }
+
+ return association;
+ }
+
private static boolean checkPackage(@UserIdInt int uid, @NonNull String packageName) {
try {
return getAppOpsService().checkPackage(uid, packageName) == MODE_ALLOWED;
diff --git a/services/companion/java/com/android/server/companion/RolesUtils.java b/services/companion/java/com/android/server/companion/RolesUtils.java
index 904283f..35488a8 100644
--- a/services/companion/java/com/android/server/companion/RolesUtils.java
+++ b/services/companion/java/com/android/server/companion/RolesUtils.java
@@ -19,6 +19,7 @@
import static android.app.role.RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP;
import static com.android.server.companion.CompanionDeviceManagerService.DEBUG;
+import static com.android.server.companion.CompanionDeviceManagerService.TAG;
import android.annotation.NonNull;
import android.annotation.SuppressLint;
@@ -35,7 +36,6 @@
/** Utility methods for accessing {@link RoleManager} APIs. */
@SuppressLint("LongLogTag")
final class RolesUtils {
- private static final String TAG = CompanionDeviceManagerService.LOG_TAG;
static boolean isRoleHolder(@NonNull Context context, @UserIdInt int userId,
@NonNull String packageName, @NonNull String role) {
diff --git a/services/companion/java/com/android/server/companion/virtual/CameraAccessController.java b/services/companion/java/com/android/server/companion/virtual/CameraAccessController.java
new file mode 100644
index 0000000..2c42c91
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/virtual/CameraAccessController.java
@@ -0,0 +1,212 @@
+/*
+ * 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.companion.virtual;
+
+import static android.hardware.camera2.CameraInjectionSession.InjectionStatusCallback.ERROR_INJECTION_UNSUPPORTED;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraInjectionSession;
+import android.hardware.camera2.CameraManager;
+import android.util.ArrayMap;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+
+/**
+ * Handles blocking access to the camera for apps running on virtual devices.
+ */
+class CameraAccessController extends CameraManager.AvailabilityCallback {
+ private static final String TAG = "CameraAccessController";
+
+ private final Object mLock = new Object();
+
+ private final Context mContext;
+ private VirtualDeviceManagerInternal mVirtualDeviceManagerInternal;
+ CameraAccessBlockedCallback mBlockedCallback;
+ private CameraManager mCameraManager;
+ private boolean mListeningForCameraEvents;
+ private PackageManager mPackageManager;
+
+ @GuardedBy("mLock")
+ private ArrayMap<String, InjectionSessionData> mPackageToSessionData = new ArrayMap<>();
+
+ static class InjectionSessionData {
+ public int appUid;
+ public ArrayMap<String, CameraInjectionSession> cameraIdToSession = new ArrayMap<>();
+ }
+
+ interface CameraAccessBlockedCallback {
+ /**
+ * Called whenever an app was blocked from accessing a camera.
+ * @param appUid uid for the app which was blocked
+ */
+ void onCameraAccessBlocked(int appUid);
+ }
+
+ CameraAccessController(Context context,
+ VirtualDeviceManagerInternal virtualDeviceManagerInternal,
+ CameraAccessBlockedCallback blockedCallback) {
+ mContext = context;
+ mVirtualDeviceManagerInternal = virtualDeviceManagerInternal;
+ mBlockedCallback = blockedCallback;
+ mCameraManager = mContext.getSystemService(CameraManager.class);
+ mPackageManager = mContext.getPackageManager();
+ }
+
+ /**
+ * Starts watching for camera access by uids running on a virtual device, if we were not
+ * already doing so.
+ */
+ public void startObservingIfNeeded() {
+ synchronized (mLock) {
+ if (!mListeningForCameraEvents) {
+ mCameraManager.registerAvailabilityCallback(mContext.getMainExecutor(), this);
+ mListeningForCameraEvents = true;
+ }
+ }
+ }
+
+ /**
+ * Stop watching for camera access.
+ */
+ public void stopObserving() {
+ synchronized (mLock) {
+ mCameraManager.unregisterAvailabilityCallback(this);
+ mListeningForCameraEvents = false;
+ }
+ }
+
+ @Override
+ public void onCameraOpened(@NonNull String cameraId, @NonNull String packageName) {
+ synchronized (mLock) {
+ try {
+ final ApplicationInfo ainfo =
+ mPackageManager.getApplicationInfo(packageName, 0);
+ InjectionSessionData data = mPackageToSessionData.get(packageName);
+ if (!mVirtualDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(ainfo.uid)) {
+ CameraInjectionSession existingSession =
+ (data != null) ? data.cameraIdToSession.get(cameraId) : null;
+ if (existingSession != null) {
+ existingSession.close();
+ data.cameraIdToSession.remove(cameraId);
+ if (data.cameraIdToSession.isEmpty()) {
+ mPackageToSessionData.remove(packageName);
+ }
+ }
+ return;
+ }
+ if (data == null) {
+ data = new InjectionSessionData();
+ data.appUid = ainfo.uid;
+ mPackageToSessionData.put(packageName, data);
+ }
+ if (data.cameraIdToSession.containsKey(cameraId)) {
+ return;
+ }
+ startBlocking(packageName, cameraId);
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.e(TAG, "onCameraOpened - unknown package " + packageName, e);
+ return;
+ }
+ }
+ }
+
+ @Override
+ public void onCameraClosed(@NonNull String cameraId) {
+ synchronized (mLock) {
+ for (int i = mPackageToSessionData.size() - 1; i >= 0; i--) {
+ InjectionSessionData data = mPackageToSessionData.valueAt(i);
+ CameraInjectionSession session = data.cameraIdToSession.get(cameraId);
+ if (session != null) {
+ session.close();
+ data.cameraIdToSession.remove(cameraId);
+ if (data.cameraIdToSession.isEmpty()) {
+ mPackageToSessionData.removeAt(i);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Turns on blocking for a particular camera and package.
+ */
+ private void startBlocking(String packageName, String cameraId) {
+ try {
+ mCameraManager.injectCamera(packageName, cameraId, /* externalCamId */ "",
+ mContext.getMainExecutor(),
+ new CameraInjectionSession.InjectionStatusCallback() {
+ @Override
+ public void onInjectionSucceeded(
+ @NonNull CameraInjectionSession session) {
+ CameraAccessController.this.onInjectionSucceeded(cameraId, packageName,
+ session);
+ }
+
+ @Override
+ public void onInjectionError(@NonNull int errorCode) {
+ CameraAccessController.this.onInjectionError(cameraId, packageName,
+ errorCode);
+ }
+ });
+ } catch (CameraAccessException e) {
+ Slog.e(TAG,
+ "Failed to injectCamera for cameraId:" + cameraId + " package:" + packageName,
+ e);
+ }
+ }
+
+ private void onInjectionSucceeded(String cameraId, String packageName,
+ @NonNull CameraInjectionSession session) {
+ synchronized (mLock) {
+ InjectionSessionData data = mPackageToSessionData.get(packageName);
+ if (data == null) {
+ Slog.e(TAG, "onInjectionSucceeded didn't find expected entry for package "
+ + packageName);
+ session.close();
+ return;
+ }
+ CameraInjectionSession existingSession = data.cameraIdToSession.put(cameraId, session);
+ if (existingSession != null) {
+ Slog.e(TAG, "onInjectionSucceeded found unexpected existing session for camera "
+ + cameraId);
+ existingSession.close();
+ }
+ }
+ }
+
+ private void onInjectionError(String cameraId, String packageName, @NonNull int errorCode) {
+ if (errorCode != ERROR_INJECTION_UNSUPPORTED) {
+ // ERROR_INJECTION_UNSUPPORTED means that there wasn't an external camera to map to the
+ // internal camera, which is expected when using the injection interface as we are in
+ // this class to simply block camera access. Any other error is unexpected.
+ Slog.e(TAG, "Unexpected injection error code:" + errorCode + " for camera:" + cameraId
+ + " and package:" + packageName);
+ return;
+ }
+ synchronized (mLock) {
+ InjectionSessionData data = mPackageToSessionData.get(packageName);
+ if (data != null) {
+ mBlockedCallback.onCameraAccessBlocked(data.appUid);
+ }
+ }
+ }
+}
diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
index dafcc60..4afa96c 100644
--- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
+++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
@@ -47,9 +47,17 @@
/**
* A controller to control the policies of the windows that can be displayed on the virtual display.
*/
-class GenericWindowPolicyController extends DisplayWindowPolicyController {
+public class GenericWindowPolicyController extends DisplayWindowPolicyController {
- private static final String TAG = "VirtualDeviceManager";
+ private static final String TAG = "GenericWindowPolicyController";
+
+ /** Interface to listen running applications change on virtual display. */
+ public interface RunningAppsChangedListener {
+ /**
+ * Notifies the running applications change.
+ */
+ void onRunningAppsChanged(ArraySet<Integer> runningUids);
+ }
private static final ComponentName BLOCKED_APP_STREAMING_COMPONENT =
new ComponentName("android", BlockedAppStreamingActivity.class.getName());
@@ -74,6 +82,9 @@
@Nullable private final ActivityListener mActivityListener;
private final Handler mHandler = new Handler(Looper.getMainLooper());
+ @Nullable
+ private RunningAppsChangedListener mRunningAppsChangedListener;
+
/**
* Creates a window policy controller that is generic to the different use cases of virtual
* device.
@@ -84,7 +95,7 @@
* @param activityListener Activity listener to listen for activity changes. The display ID
* is not populated in this callback and is always {@link Display#INVALID_DISPLAY}.
*/
- GenericWindowPolicyController(int windowFlags, int systemWindowFlags,
+ public GenericWindowPolicyController(int windowFlags, int systemWindowFlags,
@NonNull ArraySet<UserHandle> allowedUsers,
@Nullable Set<ComponentName> allowedActivities,
@Nullable Set<ComponentName> blockedActivities,
@@ -98,6 +109,11 @@
mActivityListener = activityListener;
}
+ /** Sets listener for running applications change. */
+ public void setRunningAppsChangedListener(@Nullable RunningAppsChangedListener listener) {
+ mRunningAppsChangedListener = listener;
+ }
+
@Override
public boolean canContainActivities(@NonNull List<ActivityInfo> activities) {
// Can't display all the activities if any of them don't want to be displayed.
@@ -139,6 +155,9 @@
// Post callback on the main thread so it doesn't block activity launching
mHandler.post(() -> mActivityListener.onDisplayEmpty(Display.INVALID_DISPLAY));
}
+ if (mRunningAppsChangedListener != null) {
+ mRunningAppsChangedListener.onRunningAppsChanged(runningUids);
+ }
}
/**
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 5f3a030..387d911 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -23,6 +23,8 @@
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.StringRes;
import android.app.Activity;
import android.app.ActivityOptions;
import android.app.PendingIntent;
@@ -32,6 +34,7 @@
import android.companion.virtual.IVirtualDeviceActivityListener;
import android.companion.virtual.VirtualDeviceManager.ActivityListener;
import android.companion.virtual.VirtualDeviceParams;
+import android.companion.virtual.audio.IAudioSessionCallback;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -55,11 +58,14 @@
import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
+import android.view.Display;
+import android.widget.Toast;
import android.window.DisplayWindowPolicyController;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.BlockedAppStreamingActivity;
+import com.android.server.companion.virtual.audio.VirtualAudioController;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -78,6 +84,7 @@
private final PendingTrampolineCallback mPendingTrampolineCallback;
private final int mOwnerUid;
private final InputController mInputController;
+ private VirtualAudioController mVirtualAudioController;
@VisibleForTesting
final Set<Integer> mVirtualDisplayIds = new ArraySet<>();
private final OnDeviceCloseListener mListener;
@@ -215,6 +222,10 @@
@Override // Binder call
public void close() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CREATE_VIRTUAL_DEVICE,
+ "Permission required to close the virtual device");
+
synchronized (mVirtualDeviceLock) {
if (!mPerDisplayWakelocks.isEmpty()) {
mPerDisplayWakelocks.forEach((displayId, wakeLock) -> {
@@ -227,7 +238,13 @@
}
mListener.onClose(mAssociationInfo.getId());
mAppToken.unlinkToDeath(this, 0);
- mInputController.close();
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mInputController.close();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
@Override
@@ -235,6 +252,46 @@
close();
}
+ @VisibleForTesting
+ VirtualAudioController getVirtualAudioControllerForTesting() {
+ return mVirtualAudioController;
+ }
+
+ @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
+ @Override // Binder call
+ public void onAudioSessionStarting(int displayId, IAudioSessionCallback callback) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CREATE_VIRTUAL_DEVICE,
+ "Permission required to start audio session");
+ synchronized (mVirtualDeviceLock) {
+ if (!mVirtualDisplayIds.contains(displayId)) {
+ throw new SecurityException(
+ "Cannot start audio session for a display not associated with this virtual "
+ + "device");
+ }
+
+ if (mVirtualAudioController == null) {
+ mVirtualAudioController = new VirtualAudioController(mContext);
+ GenericWindowPolicyController gwpc = mWindowPolicyControllers.get(displayId);
+ mVirtualAudioController.startListening(gwpc, callback);
+ }
+ }
+ }
+
+ @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
+ @Override // Binder call
+ public void onAudioSessionEnded() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CREATE_VIRTUAL_DEVICE,
+ "Permission required to stop audio session");
+ synchronized (mVirtualDeviceLock) {
+ if (mVirtualAudioController != null) {
+ mVirtualAudioController.stopListening();
+ mVirtualAudioController = null;
+ }
+ }
+ }
+
@Override // Binder call
public void createVirtualKeyboard(
int displayId,
@@ -529,6 +586,30 @@
return false;
}
+ /**
+ * Shows a toast on virtual displays owned by this device which have a given uid running.
+ */
+ void showToastWhereUidIsRunning(int uid, @StringRes int resId, @Toast.Duration int duration) {
+ synchronized (mVirtualDeviceLock) {
+ DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
+ final int size = mWindowPolicyControllers.size();
+ for (int i = 0; i < size; i++) {
+ if (mWindowPolicyControllers.valueAt(i).containsUid(uid)) {
+ int displayId = mWindowPolicyControllers.keyAt(i);
+ Display display = displayManager.getDisplay(displayId);
+ if (display != null && display.isValid()) {
+ Toast.makeText(mContext.createDisplayContext(display), resId,
+ duration).show();
+ }
+ }
+ }
+ }
+ }
+
+ boolean isDisplayOwnedByVirtualDevice(int displayId) {
+ return mVirtualDisplayIds.contains(displayId);
+ }
+
interface OnDeviceCloseListener {
void onClose(int associationId);
}
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
index b507110..c7d8daa 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -39,6 +39,7 @@
import android.util.ExceptionUtils;
import android.util.Slog;
import android.util.SparseArray;
+import android.widget.Toast;
import android.window.DisplayWindowPolicyController;
import com.android.internal.annotations.GuardedBy;
@@ -62,8 +63,10 @@
private final Object mVirtualDeviceManagerLock = new Object();
private final VirtualDeviceManagerImpl mImpl;
+ private VirtualDeviceManagerInternal mLocalService;
private final Handler mHandler = new Handler(Looper.getMainLooper());
private final PendingTrampolineMap mPendingTrampolines = new PendingTrampolineMap(mHandler);
+ private final CameraAccessController mCameraAccessController;
/**
* Mapping from CDM association IDs to virtual devices. Only one virtual device is allowed for
@@ -90,6 +93,9 @@
public VirtualDeviceManagerService(Context context) {
super(context);
mImpl = new VirtualDeviceManagerImpl();
+ mLocalService = new LocalService();
+ mCameraAccessController = new CameraAccessController(getContext(), mLocalService,
+ this::onCameraAccessBlocked);
}
private final ActivityInterceptorCallback mActivityInterceptorCallback =
@@ -118,8 +124,7 @@
@Override
public void onStart() {
publishBinderService(Context.VIRTUAL_DEVICE_SERVICE, mImpl);
- publishLocalService(VirtualDeviceManagerInternal.class, new LocalService());
-
+ publishLocalService(VirtualDeviceManagerInternal.class, mLocalService);
ActivityTaskManagerInternal activityTaskManagerInternal = getLocalService(
ActivityTaskManagerInternal.class);
activityTaskManagerInternal.registerActivityStartInterceptor(
@@ -169,6 +174,16 @@
}
}
+ void onCameraAccessBlocked(int appUid) {
+ synchronized (mVirtualDeviceManagerLock) {
+ int size = mVirtualDevices.size();
+ for (int i = 0; i < size; i++) {
+ mVirtualDevices.valueAt(i).showToastWhereUidIsRunning(appUid,
+ com.android.internal.R.string.vdm_camera_access_denied, Toast.LENGTH_LONG);
+ }
+ }
+ }
+
class VirtualDeviceManagerImpl extends IVirtualDeviceManager.Stub implements
VirtualDeviceImpl.PendingTrampolineCallback {
@@ -205,10 +220,14 @@
public void onClose(int associationId) {
synchronized (mVirtualDeviceManagerLock) {
mVirtualDevices.remove(associationId);
+ if (mVirtualDevices.size() == 0) {
+ mCameraAccessController.stopObserving();
+ }
}
}
},
this, activityListener, params);
+ mCameraAccessController.startObservingIfNeeded();
mVirtualDevices.put(associationInfo.getId(), virtualDevice);
return virtualDevice;
}
@@ -329,6 +348,19 @@
}
return false;
}
+
+ @Override
+ public boolean isDisplayOwnedByAnyVirtualDevice(int displayId) {
+ synchronized (mVirtualDeviceManagerLock) {
+ int size = mVirtualDevices.size();
+ for (int i = 0; i < size; i++) {
+ if (mVirtualDevices.valueAt(i).isDisplayOwnedByVirtualDevice(displayId)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
}
private static final class PendingTrampolineMap {
diff --git a/services/companion/java/com/android/server/companion/virtual/audio/AudioPlaybackDetector.java b/services/companion/java/com/android/server/companion/virtual/audio/AudioPlaybackDetector.java
new file mode 100644
index 0000000..2d72913
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/virtual/audio/AudioPlaybackDetector.java
@@ -0,0 +1,65 @@
+/*
+ * 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.companion.virtual.audio;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.media.AudioManager;
+import android.media.AudioPlaybackConfiguration;
+
+import java.util.List;
+
+/**
+ * Wrapper class for other classes to listen {@link #onPlaybackConfigChanged(List)} by implementing
+ * {@link AudioPlaybackCallback} instead of inheriting the
+ * {@link AudioManager.AudioPlaybackCallback}.
+ */
+final class AudioPlaybackDetector extends AudioManager.AudioPlaybackCallback {
+
+ /**
+ * Interface to listen {@link #onPlaybackConfigChanged(List)} from
+ * {@link AudioManager.AudioPlaybackCallback}.
+ */
+ interface AudioPlaybackCallback {
+ void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs);
+ }
+
+ private final AudioManager mAudioManager;
+ private AudioPlaybackCallback mAudioPlaybackCallback;
+
+ AudioPlaybackDetector(Context context) {
+ mAudioManager = context.getSystemService(AudioManager.class);
+ }
+
+ void register(@NonNull AudioPlaybackCallback callback) {
+ mAudioPlaybackCallback = callback;
+ mAudioManager.registerAudioPlaybackCallback(/* cb= */ this, /* handler= */ null);
+ }
+
+ void unregister() {
+ mAudioPlaybackCallback = null;
+ mAudioManager.unregisterAudioPlaybackCallback(/* cb= */ this);
+ }
+
+ @Override
+ public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {
+ super.onPlaybackConfigChanged(configs);
+ if (mAudioPlaybackCallback != null) {
+ mAudioPlaybackCallback.onPlaybackConfigChanged(configs);
+ }
+ }
+}
diff --git a/services/companion/java/com/android/server/companion/virtual/audio/AudioRecordingDetector.java b/services/companion/java/com/android/server/companion/virtual/audio/AudioRecordingDetector.java
new file mode 100644
index 0000000..c204145
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/virtual/audio/AudioRecordingDetector.java
@@ -0,0 +1,65 @@
+/*
+ * 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.companion.virtual.audio;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.media.AudioManager;
+import android.media.AudioRecordingConfiguration;
+
+import java.util.List;
+
+/**
+ * Wrapper class for other classes to listen {@link #onRecordingConfigChanged(List)} by implementing
+ * {@link AudioRecordingCallback} instead of inheriting the
+ * {@link AudioManager.AudioRecordingCallback}.
+ */
+final class AudioRecordingDetector extends AudioManager.AudioRecordingCallback {
+
+ /**
+ * Interface to listen {@link #onRecordingConfigChanged(List)} from
+ * {@link AudioManager.AudioRecordingCallback}.
+ */
+ interface AudioRecordingCallback {
+ void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs);
+ }
+
+ private final AudioManager mAudioManager;
+ private AudioRecordingCallback mAudioRecordingCallback;
+
+ AudioRecordingDetector(Context context) {
+ mAudioManager = context.getSystemService(AudioManager.class);
+ }
+
+ void register(@NonNull AudioRecordingCallback callback) {
+ mAudioRecordingCallback = callback;
+ mAudioManager.registerAudioRecordingCallback(/* cb= */ this, /* handler= */ null);
+ }
+
+ void unregister() {
+ mAudioRecordingCallback = null;
+ mAudioManager.unregisterAudioRecordingCallback(/* cb= */ this);
+ }
+
+ @Override
+ public void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs) {
+ super.onRecordingConfigChanged(configs);
+ if (mAudioRecordingCallback != null) {
+ mAudioRecordingCallback.onRecordingConfigChanged(configs);
+ }
+ }
+}
diff --git a/services/companion/java/com/android/server/companion/virtual/audio/VirtualAudioController.java b/services/companion/java/com/android/server/companion/virtual/audio/VirtualAudioController.java
new file mode 100644
index 0000000..1dc87d6
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/virtual/audio/VirtualAudioController.java
@@ -0,0 +1,294 @@
+/*
+ * 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.companion.virtual.audio;
+
+import static android.media.AudioPlaybackConfiguration.PLAYER_STATE_STARTED;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.companion.virtual.audio.IAudioSessionCallback;
+import android.content.Context;
+import android.media.AudioManager;
+import android.media.AudioPlaybackConfiguration;
+import android.media.AudioRecordingConfiguration;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.companion.virtual.GenericWindowPolicyController;
+import com.android.server.companion.virtual.GenericWindowPolicyController.RunningAppsChangedListener;
+import com.android.server.companion.virtual.audio.AudioPlaybackDetector.AudioPlaybackCallback;
+import com.android.server.companion.virtual.audio.AudioRecordingDetector.AudioRecordingCallback;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Manages audio streams associated with a {@link VirtualAudioDevice}. Responsible for monitoring
+ * running applications and playback configuration changes in order to correctly re-route audio and
+ * then notify clients of these changes.
+ */
+public final class VirtualAudioController implements AudioPlaybackCallback,
+ AudioRecordingCallback, RunningAppsChangedListener {
+ private static final String TAG = "VirtualAudioController";
+ private static final int UPDATE_REROUTING_APPS_DELAY_MS = 2000;
+
+ private final Context mContext;
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
+ private final Runnable mUpdateAudioRoutingRunnable = this::notifyAppsNeedingAudioRoutingChanged;
+ private final AudioPlaybackDetector mAudioPlaybackDetector;
+ private final AudioRecordingDetector mAudioRecordingDetector;
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
+ private final ArraySet<Integer> mRunningAppUids = new ArraySet<>();
+ @GuardedBy("mLock")
+ private ArraySet<Integer> mPlayingAppUids = new ArraySet<>();
+ private GenericWindowPolicyController mGenericWindowPolicyController;
+ private final Object mCallbackLock = new Object();
+ @Nullable
+ @GuardedBy("mCallbackLock")
+ private IAudioSessionCallback mCallback;
+
+ public VirtualAudioController(Context context) {
+ mContext = context;
+ mAudioPlaybackDetector = new AudioPlaybackDetector(context);
+ mAudioRecordingDetector = new AudioRecordingDetector(context);
+ }
+
+ /**
+ * Starts to listen to running applications and audio configuration changes on virtual display
+ * for audio capture and injection.
+ */
+ public void startListening(
+ @NonNull GenericWindowPolicyController genericWindowPolicyController,
+ @Nullable IAudioSessionCallback callback) {
+ mGenericWindowPolicyController = genericWindowPolicyController;
+ mGenericWindowPolicyController.setRunningAppsChangedListener(/* listener= */ this);
+ synchronized (mCallbackLock) {
+ mCallback = callback;
+ }
+ synchronized (mLock) {
+ mRunningAppUids.clear();
+ mPlayingAppUids.clear();
+ }
+ mAudioPlaybackDetector.register(/* callback= */ this);
+ mAudioRecordingDetector.register(/* callback= */ this);
+ }
+
+ /**
+ * Stops listening to running applications and audio configuration changes on virtual display
+ * for audio capture and injection.
+ */
+ public void stopListening() {
+ if (mHandler.hasCallbacks(mUpdateAudioRoutingRunnable)) {
+ mHandler.removeCallbacks(mUpdateAudioRoutingRunnable);
+ }
+ mAudioPlaybackDetector.unregister();
+ mAudioRecordingDetector.unregister();
+ if (mGenericWindowPolicyController != null) {
+ mGenericWindowPolicyController.setRunningAppsChangedListener(/* listener= */ null);
+ mGenericWindowPolicyController = null;
+ }
+ synchronized (mCallbackLock) {
+ mCallback = null;
+ }
+ }
+
+ @Override
+ public void onRunningAppsChanged(ArraySet<Integer> runningUids) {
+ synchronized (mLock) {
+ if (mRunningAppUids.equals(runningUids)) {
+ // Ignore no-op events.
+ return;
+ }
+ mRunningAppUids.clear();
+ mRunningAppUids.addAll(runningUids);
+
+ ArraySet<Integer> oldPlayingAppUids = mPlayingAppUids;
+
+ // Update the list of playing apps after caching the old list, and before checking if
+ // the list of playing apps is empty. This is a subset of the running apps, so we need
+ // to update this here as well.
+ AudioManager audioManager = mContext.getSystemService(AudioManager.class);
+ List<AudioPlaybackConfiguration> configs =
+ audioManager.getActivePlaybackConfigurations();
+ mPlayingAppUids = findPlayingAppUids(configs, mRunningAppUids);
+
+ // Do not change rerouted applications while any application is playing, or the sound
+ // will be leaked from phone during the transition. Delay the change until we detect
+ // there is no application is playing in onPlaybackConfigChanged().
+ if (!mPlayingAppUids.isEmpty()) {
+ Slog.i(TAG, "Audio is playing, do not change rerouted apps");
+ return;
+ }
+
+ // An application previously playing audio was removed from the display.
+ if (!oldPlayingAppUids.isEmpty()) {
+ // Delay changing the rerouted application when the last application playing audio
+ // was removed from virtual device, or the sound will be leaked from phone side
+ // during the transition.
+ Slog.i(TAG, "The last playing app removed, delay change rerouted apps");
+ if (mHandler.hasCallbacks(mUpdateAudioRoutingRunnable)) {
+ mHandler.removeCallbacks(mUpdateAudioRoutingRunnable);
+ }
+ mHandler.postDelayed(mUpdateAudioRoutingRunnable, UPDATE_REROUTING_APPS_DELAY_MS);
+ return;
+ }
+ }
+
+ // Normal case with no application playing, just update routing.
+ notifyAppsNeedingAudioRoutingChanged();
+ }
+
+ @Override
+ public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {
+ updatePlayingApplications(configs);
+
+ List<AudioPlaybackConfiguration> audioPlaybackConfigurations;
+ synchronized (mLock) {
+ // Filter configurations of applications running on virtual device.
+ audioPlaybackConfigurations = findPlaybackConfigurations(configs, mRunningAppUids);
+ }
+ synchronized (mCallbackLock) {
+ if (mCallback != null) {
+ try {
+ mCallback.onPlaybackConfigChanged(audioPlaybackConfigurations);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException when calling onPlaybackConfigChanged", e);
+ }
+ }
+ }
+ }
+
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @Override
+ public void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs) {
+ List<AudioRecordingConfiguration> audioRecordingConfigurations;
+ synchronized (mLock) {
+ // Filter configurations of applications running on virtual device.
+ audioRecordingConfigurations = findRecordingConfigurations(configs, mRunningAppUids);
+ }
+ synchronized (mCallbackLock) {
+ if (mCallback != null) {
+ try {
+ mCallback.onRecordingConfigChanged(audioRecordingConfigurations);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException when calling onRecordingConfigChanged", e);
+ }
+ }
+ }
+ }
+
+ private void updatePlayingApplications(List<AudioPlaybackConfiguration> configs) {
+ synchronized (mLock) {
+ ArraySet<Integer> playingAppUids = findPlayingAppUids(configs, mRunningAppUids);
+ if (mPlayingAppUids.equals(playingAppUids)) {
+ return;
+ }
+ mPlayingAppUids = playingAppUids;
+ }
+
+ // Updated rerouted apps, even if the app is already playing. It originally should be done
+ // when onRunningAppsChanged() is called, but we don't want to interrupt the audio
+ // streaming and cause the sound leak from phone when it's playing, so delay until here.
+ notifyAppsNeedingAudioRoutingChanged();
+ }
+
+ private void notifyAppsNeedingAudioRoutingChanged() {
+ if (mHandler.hasCallbacks(mUpdateAudioRoutingRunnable)) {
+ mHandler.removeCallbacks(mUpdateAudioRoutingRunnable);
+ }
+
+ int[] runningUids;
+ synchronized (mLock) {
+ runningUids = new int[mRunningAppUids.size()];
+ for (int i = 0; i < mRunningAppUids.size(); i++) {
+ runningUids[i] = mRunningAppUids.valueAt(i);
+ }
+ }
+
+ synchronized (mCallbackLock) {
+ if (mCallback != null) {
+ try {
+ mCallback.onAppsNeedingAudioRoutingChanged(runningUids);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException when calling updateReroutingApps", e);
+ }
+ }
+ }
+ }
+
+ /**
+ * Finds uid of playing applications from the given running applications.
+ *
+ * @param configs a list of playback configs which get from {@link AudioManager}
+ */
+ private static ArraySet<Integer> findPlayingAppUids(List<AudioPlaybackConfiguration> configs,
+ ArraySet<Integer> runningAppUids) {
+ ArraySet<Integer> playingAppUids = new ArraySet<>();
+ for (AudioPlaybackConfiguration config : configs) {
+ if (runningAppUids.contains(config.getClientUid())
+ && config.getPlayerState() == PLAYER_STATE_STARTED) {
+ playingAppUids.add(config.getClientUid());
+ }
+ }
+ return playingAppUids;
+ }
+
+ /** Finds a list of {@link AudioPlaybackConfiguration} for the given running applications. */
+ private static List<AudioPlaybackConfiguration> findPlaybackConfigurations(
+ List<AudioPlaybackConfiguration> configs,
+ ArraySet<Integer> runningAppUids) {
+ List<AudioPlaybackConfiguration> runningConfigs = new ArrayList<>();
+ for (AudioPlaybackConfiguration config : configs) {
+ if (runningAppUids.contains(config.getClientUid())) {
+ runningConfigs.add(config);
+ }
+ }
+ return runningConfigs;
+ }
+
+ /** Finds a list of {@link AudioRecordingConfiguration} for the given running applications. */
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ private static List<AudioRecordingConfiguration> findRecordingConfigurations(
+ List<AudioRecordingConfiguration> configs, ArraySet<Integer> runningAppUids) {
+ List<AudioRecordingConfiguration> runningConfigs = new ArrayList<>();
+ for (AudioRecordingConfiguration config : configs) {
+ if (runningAppUids.contains(config.getClientUid())) {
+ runningConfigs.add(config);
+ }
+ }
+ return runningConfigs;
+ }
+
+ @VisibleForTesting
+ boolean hasPendingRunnable() {
+ return mHandler.hasCallbacks(mUpdateAudioRoutingRunnable);
+ }
+
+ @VisibleForTesting
+ void addPlayingAppsForTesting(int appUid) {
+ synchronized (mLock) {
+ mPlayingAppUids.add(appUid);
+ }
+ }
+}
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index a8eeaf8..e335a16 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -49,6 +49,7 @@
import com.android.server.pm.pkg.AndroidPackageApi;
import com.android.server.pm.pkg.PackageState;
import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.pkg.SharedUserApi;
import com.android.server.pm.pkg.component.ParsedMainComponent;
import com.android.server.pm.pkg.mutate.PackageStateMutator;
@@ -1262,6 +1263,21 @@
boolean migrateAppsData);
/**
+ * Returns an array of PackageStateInternal that are all part of a shared user setting which is
+ * denoted by the app ID. Returns an empty set if the shared user setting doesn't exist or does
+ * not contain any package.
+ */
+ @NonNull
+ public abstract ArraySet<PackageStateInternal> getSharedUserPackages(int sharedUserAppId);
+
+ /**
+ * Returns the SharedUserApi denoted by the app ID of the shared user setting. Returns null if
+ * the corresponding shared user setting doesn't exist.
+ */
+ @Nullable
+ public abstract SharedUserApi getSharedUserApi(int sharedUserAppId);
+
+ /**
* Initiates a package state mutation request, returning the current state as known by
* PackageManager. This allows the later commit request to compare the initial values and
* determine if any state was changed or any packages were updated since the whole request
diff --git a/services/core/java/com/android/server/AccessibilityManagerInternal.java b/services/core/java/com/android/server/AccessibilityManagerInternal.java
new file mode 100644
index 0000000..28f6db1
--- /dev/null
+++ b/services/core/java/com/android/server/AccessibilityManagerInternal.java
@@ -0,0 +1,86 @@
+/*
+ * 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.annotation.NonNull;
+import android.os.IBinder;
+import android.util.ArraySet;
+import android.util.SparseArray;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputBinding;
+
+import com.android.internal.view.IInputContext;
+import com.android.internal.view.IInputMethodSession;
+
+/**
+ * Accessibility manager local system service interface.
+ */
+public abstract class AccessibilityManagerInternal {
+ /** Enable or disable the sessions. */
+ public abstract void setImeSessionEnabled(SparseArray<IInputMethodSession> sessions,
+ boolean enabled);
+
+ /** Unbind input for all accessibility services which require ime capabilities. */
+ public abstract void unbindInput();
+
+ /** Bind input for all accessibility services which require ime capabilities. */
+ public abstract void bindInput(InputBinding binding);
+
+ /**
+ * Request input session from all accessibility services which require ime capabilities and
+ * whose id is not in the ignoreSet.
+ */
+ public abstract void createImeSession(ArraySet<Integer> ignoreSet);
+
+ /** Start input for all accessibility services which require ime capabilities. */
+ public abstract void startInput(IBinder startInputToken, IInputContext inputContext,
+ EditorInfo editorInfo, boolean restarting);
+
+ private static final AccessibilityManagerInternal NOP = new AccessibilityManagerInternal() {
+ @Override
+ public void setImeSessionEnabled(SparseArray<IInputMethodSession> sessions,
+ boolean enabled) {
+ }
+
+ @Override
+ public void unbindInput() {
+ }
+
+ @Override
+ public void bindInput(InputBinding binding) {
+ }
+
+ @Override
+ public void createImeSession(ArraySet<Integer> ignoreSet) {
+ }
+
+ @Override
+ public void startInput(IBinder startInputToken, IInputContext inputContext,
+ EditorInfo editorInfo, boolean restarting) {
+ }
+ };
+
+ /**
+ * @return Global instance if exists. Otherwise, a fallback no-op instance.
+ */
+ @NonNull
+ public static AccessibilityManagerInternal get() {
+ final AccessibilityManagerInternal instance =
+ LocalServices.getService(AccessibilityManagerInternal.class);
+ return instance != null ? instance : NOP;
+ }
+}
diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java
index 91d2f55..6c220f6 100644
--- a/services/core/java/com/android/server/BinaryTransparencyService.java
+++ b/services/core/java/com/android/server/BinaryTransparencyService.java
@@ -45,6 +45,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.Executors;
import java.util.stream.Collectors;
/**
@@ -369,10 +370,13 @@
// we are only interested in doing things at PHASE_BOOT_COMPLETED
if (phase == PHASE_BOOT_COMPLETED) {
- // due to potentially long computation that holds up boot time, apex sha computations
- // are deferred to first call
Slog.i(TAG, "Boot completed. Getting VBMeta Digest.");
getVBMetaDigestInformation();
+
+ // due to potentially long computation that may hold up boot time, SHA256 computations
+ // for APEXs and Modules will be executed via threads.
+ Slog.i(TAG, "Executing APEX & Module digest computations");
+ computeApexAndModuleDigests();
}
}
@@ -382,6 +386,12 @@
FrameworkStatsLog.write(FrameworkStatsLog.VBMETA_DIGEST_REPORTED, mVbmetaDigest);
}
+ private void computeApexAndModuleDigests() {
+ // using Executors will allow the computations to be done asynchronously, thus not holding
+ // up boot time.
+ Executors.defaultThreadFactory().newThread(() -> updateBinaryMeasurements()).start();
+ }
+
@NonNull
private List<PackageInfo> getInstalledApexs() {
List<PackageInfo> results = new ArrayList<PackageInfo>();
diff --git a/services/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java
index a0575cf..26d76a84 100644
--- a/services/core/java/com/android/server/BootReceiver.java
+++ b/services/core/java/com/android/server/BootReceiver.java
@@ -51,15 +51,12 @@
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 @@
// 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 @@
* 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 @@
* 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 @@
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 @@
}
- /**
- * 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);
}
diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java
index e29e894..e924012 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 @@
}
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 @@
}
@Override
+ @EnforcePermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
public boolean startInstallation(String dsuSlot) throws RemoteException {
IGsiService service = getGsiService();
mGsiService = service;
@@ -124,6 +118,7 @@
}
@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 @@
}
@Override
+ @EnforcePermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
public boolean closePartition() throws RemoteException {
IGsiService service = getGsiService();
if (service.closePartition() != 0) {
@@ -145,6 +141,7 @@
}
@Override
+ @EnforcePermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
public boolean finishInstallation() throws RemoteException {
IGsiService service = getGsiService();
if (service.closeInstall() != 0) {
@@ -155,21 +152,25 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@Override
+ @EnforcePermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
public boolean submitFromAshmem(long size) {
try {
return getGsiService().commitGsiChunkFromAshmem(size);
@@ -238,6 +244,7 @@
}
@Override
+ @EnforcePermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
public boolean getAvbPublicKey(AvbPublicKey dst) {
try {
return getGsiService().getAvbPublicKey(dst) == 0;
@@ -247,6 +254,7 @@
}
@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 39ac5ef..b59cd4c 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.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_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 @@
*/
@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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 32a6558..c194527 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -134,6 +134,7 @@
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.TimeUtils;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
@@ -190,6 +191,7 @@
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
+import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -471,6 +473,9 @@
@GuardedBy("mLock")
private String mMoveTargetUuid;
+ @GuardedBy("mCloudMediaProviders")
+ private final SparseArray<String> mCloudMediaProviders = new SparseArray<>();
+
private volatile int mMediaStoreAuthorityAppId = -1;
private volatile int mDownloadsAuthorityAppId = -1;
@@ -752,6 +757,7 @@
private static final int H_BOOT_COMPLETED = 13;
private static final int H_COMPLETE_UNLOCK_USER = 14;
private static final int H_VOLUME_STATE_CHANGED = 15;
+ private static final int H_CLOUD_MEDIA_PROVIDER_CHANGED = 16;
class StorageManagerServiceHandler extends Handler {
public StorageManagerServiceHandler(Looper looper) {
@@ -872,13 +878,24 @@
break;
}
case H_COMPLETE_UNLOCK_USER: {
- completeUnlockUser((int) msg.obj);
+ completeUnlockUser(msg.arg1);
break;
}
case H_VOLUME_STATE_CHANGED: {
final SomeArgs args = (SomeArgs) msg.obj;
- onVolumeStateChangedAsync((VolumeInfo) args.arg1, (int) args.arg2,
- (int) args.arg3);
+ onVolumeStateChangedAsync((VolumeInfo) args.arg1, args.argi1, args.argi2);
+ args.recycle();
+ break;
+ }
+ case H_CLOUD_MEDIA_PROVIDER_CHANGED: {
+ final Object listener = msg.obj;
+ if (listener instanceof StorageManagerInternal.CloudProviderChangeListener) {
+ notifyCloudMediaProviderChangedAsync(
+ (StorageManagerInternal.CloudProviderChangeListener) listener);
+ } else {
+ onCloudMediaProviderChangedAsync(msg.arg1);
+ }
+ break;
}
}
}
@@ -1205,7 +1222,8 @@
Slog.w(TAG, "UNLOCK_USER lost from vold reset, will retry, user:" + userId);
mVold.onUserStarted(userId);
mStoraged.onUserStarted(userId);
- mHandler.obtainMessage(H_COMPLETE_UNLOCK_USER, userId).sendToTarget();
+ mHandler.obtainMessage(H_COMPLETE_UNLOCK_USER, userId, /* arg2 (unusued) */ 0)
+ .sendToTarget();
}
}
@@ -1263,7 +1281,8 @@
Slog.wtf(TAG, e);
}
- mHandler.obtainMessage(H_COMPLETE_UNLOCK_USER, userId).sendToTarget();
+ mHandler.obtainMessage(H_COMPLETE_UNLOCK_USER, userId, /* arg2 (unusued) */ 0)
+ .sendToTarget();
if (mRemountCurrentUserVolumesOnUnlock && userId == mCurrentUserId) {
maybeRemountVolumes(userId);
mRemountCurrentUserVolumesOnUnlock = false;
@@ -1493,18 +1512,17 @@
}
@Override
- public void onVolumeStateChanged(String volId, int state) {
+ public void onVolumeStateChanged(String volId, final int newState) {
synchronized (mLock) {
final VolumeInfo vol = mVolumes.get(volId);
if (vol != null) {
final int oldState = vol.state;
- final int newState = state;
vol.state = newState;
final VolumeInfo vInfo = new VolumeInfo(vol);
final SomeArgs args = SomeArgs.obtain();
args.arg1 = vInfo;
- args.arg2 = oldState;
- args.arg3 = newState;
+ args.argi1 = oldState;
+ args.argi2 = newState;
mHandler.obtainMessage(H_VOLUME_STATE_CHANGED, args).sendToTarget();
onVolumeStateChangedLocked(vInfo, oldState, newState);
}
@@ -1696,7 +1714,6 @@
return true;
}
-
private void onVolumeStateChangedLocked(VolumeInfo vol, int oldState, int newState) {
if (vol.type == VolumeInfo.TYPE_EMULATED) {
if (newState != VolumeInfo.STATE_MOUNTED) {
@@ -1835,6 +1852,27 @@
}
}
+ private void notifyCloudMediaProviderChangedAsync(
+ @NonNull StorageManagerInternal.CloudProviderChangeListener listener) {
+ synchronized (mCloudMediaProviders) {
+ for (int i = mCloudMediaProviders.size() - 1; i >= 0; --i) {
+ listener.onCloudProviderChanged(
+ mCloudMediaProviders.keyAt(i), mCloudMediaProviders.valueAt(i));
+ }
+ }
+ }
+
+ private void onCloudMediaProviderChangedAsync(int userId) {
+ final String authority;
+ synchronized (mCloudMediaProviders) {
+ authority = mCloudMediaProviders.get(userId);
+ }
+ for (StorageManagerInternal.CloudProviderChangeListener listener :
+ mStorageManagerInternal.mCloudProviderChangeListeners) {
+ listener.onCloudProviderChanged(userId, authority);
+ }
+ }
+
private void maybeLogMediaMount(VolumeInfo vol, int newState) {
if (!SecurityLog.isLoggingEnabled()) {
return;
@@ -3772,7 +3810,7 @@
Binder.restoreCallingIdentity(token);
}
}
-
+
@Override
public void notifyAppIoBlocked(String volumeUuid, int uid, int tid, int reason) {
enforceExternalStorageService();
@@ -3793,11 +3831,46 @@
return isAppIoBlocked(uid);
}
-
private boolean isAppIoBlocked(int uid) {
return mStorageSessionController.isAppIoBlocked(uid);
}
+ @Override
+ public void setCloudMediaProvider(@Nullable String authority) {
+ enforceExternalStorageService();
+
+ final int userId = UserHandle.getUserId(Binder.getCallingUid());
+ synchronized (mCloudMediaProviders) {
+ final String oldAuthority = mCloudMediaProviders.get(userId);
+ if (!Objects.equals(authority, oldAuthority)) {
+ mCloudMediaProviders.put(userId, authority);
+ mHandler.obtainMessage(H_CLOUD_MEDIA_PROVIDER_CHANGED, userId, 0, authority)
+ .sendToTarget();
+ }
+ }
+ }
+
+ @Override
+ @Nullable
+ public String getCloudMediaProvider() {
+ final int callingUid = Binder.getCallingUid();
+ final int userId = UserHandle.getUserId(callingUid);
+ final String authority;
+ synchronized (mCloudMediaProviders) {
+ authority = mCloudMediaProviders.get(userId);
+ }
+ if (authority == null) {
+ return null;
+ }
+ final ProviderInfo pi = mPmInternal.resolveContentProvider(
+ authority, 0, userId, callingUid);
+ if (pi == null
+ || mPmInternal.filterAppAccess(pi.packageName, callingUid, userId)) {
+ return null;
+ }
+ return authority;
+ }
+
/**
* Enforces that the caller is the {@link ExternalStorageService}
*
@@ -4071,7 +4144,7 @@
|| (includeSharedProfile && vol.isVisibleForWrite(userIdSharingMedia));
} else {
match = vol.isVisibleForUser(userId)
- || (includeInvisible && vol.getPath() != null)
+ || (!vol.isVisible() && includeInvisible && vol.getPath() != null)
|| (includeSharedProfile && vol.isVisibleForRead(userIdSharingMedia));
}
if (!match) continue;
@@ -4674,7 +4747,7 @@
private int getMountModeInternal(int uid, String packageName) {
try {
// Get some easy cases out of the way first
- if (Process.isIsolated(uid)) {
+ if (Process.isIsolated(uid) || Process.isSupplemental(uid)) {
return StorageManager.MOUNT_MODE_EXTERNAL_NONE;
}
@@ -4950,6 +5023,12 @@
pw.decreaseIndent();
}
+ synchronized (mCloudMediaProviders) {
+ pw.println();
+ pw.print("Media cloud providers: ");
+ pw.println(mCloudMediaProviders);
+ }
+
pw.println();
pw.print("Last maintenance: ");
pw.println(TimeUtils.formatForLogging(mLastMaintenance));
@@ -4970,6 +5049,9 @@
private final List<StorageManagerInternal.ResetListener> mResetListeners =
new ArrayList<>();
+ private final CopyOnWriteArraySet<StorageManagerInternal.CloudProviderChangeListener>
+ mCloudProviderChangeListeners = new CopyOnWriteArraySet<>();
+
@Override
public boolean isFuseMounted(int userId) {
synchronized (mLock) {
@@ -5192,5 +5274,12 @@
return mCeStoragePreparedUsers.contains(userId);
}
}
+
+ @Override
+ public void registerCloudProviderChangeListener(
+ @NonNull StorageManagerInternal.CloudProviderChangeListener listener) {
+ mCloudProviderChangeListeners.add(listener);
+ mHandler.obtainMessage(H_CLOUD_MEDIA_PROVIDER_CHANGED, listener);
+ }
}
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 9353dd8..092172a 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2721,8 +2721,8 @@
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
- String instanceName, boolean isSupplementalProcessService, String callingPackage,
- final int userId)
+ String instanceName, boolean isSupplementalProcessService, int supplementedAppUid,
+ String callingPackage, final int userId)
throws TransactionTooLargeException {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "bindService: " + service
+ " type=" + resolvedType + " conn=" + connection.asBinder()
@@ -2807,8 +2807,8 @@
final boolean allowInstant = (flags & Context.BIND_ALLOW_INSTANT) != 0;
ServiceLookupResult res = retrieveServiceLocked(service, instanceName,
- isSupplementalProcessService, resolvedType, callingPackage, callingPid, callingUid,
- userId, true, callerFg, isBindExternal, allowInstant);
+ isSupplementalProcessService, supplementedAppUid, resolvedType, callingPackage,
+ callingPid, callingUid, userId, true, callerFg, isBindExternal, allowInstant);
if (res == null) {
return 0;
}
@@ -3228,13 +3228,14 @@
int callingPid, int callingUid, int userId,
boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal,
boolean allowInstant) {
- return retrieveServiceLocked(service, instanceName, false, resolvedType, callingPackage,
+ return retrieveServiceLocked(service, instanceName, false, 0, resolvedType, callingPackage,
callingPid, callingUid, userId, createIfNeeded, callingFromFg, isBindExternal,
allowInstant);
}
private ServiceLookupResult retrieveServiceLocked(Intent service,
- String instanceName, boolean isSupplementalProcessService, String resolvedType,
+ String instanceName, boolean isSupplementalProcessService, int supplementedAppUid,
+ String resolvedType,
String callingPackage, int callingPid, int callingUid, int userId,
boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal,
boolean allowInstant) {
@@ -3411,9 +3412,11 @@
final Intent.FilterComparison filter
= new Intent.FilterComparison(service.cloneFilter());
final ServiceRestarter res = new ServiceRestarter();
+ String supplementalProcessName = isSupplementalProcessService ? instanceName
+ : null;
r = new ServiceRecord(mAm, className, name, definingPackageName,
definingUid, filter, sInfo, callingFromFg, res,
- isSupplementalProcessService);
+ supplementalProcessName, supplementedAppUid);
res.setService(r);
smap.mServicesByInstanceName.put(name, r);
smap.mServicesByIntent.put(filter, r);
@@ -4187,8 +4190,16 @@
if (app == null && !permissionsReviewRequired && !packageFrozen) {
// TODO (chriswailes): Change the Zygote policy flags based on if the launch-for-service
// was initiated from a notification tap or not.
- if ((app = mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
- hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, false, isolated)) == null) {
+ if (r.supplemental) {
+ final int uid = Process.toSupplementalUid(r.supplementedAppUid);
+ app = mAm.startSupplementalProcessLocked(procName, r.appInfo, true, intentFlags,
+ hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, uid);
+ r.isolationHostProc = app;
+ } else {
+ app = mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
+ hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, false, isolated);
+ }
+ if (app == null) {
String msg = "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 940ad73..e2e53cb 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -20,6 +20,8 @@
import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_NONE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER_QUICK;
+import static com.android.server.am.BroadcastConstants.DEFER_BOOT_COMPLETED_BROADCAST_BACKGROUND_RESTRICTED_ONLY;
+import static com.android.server.am.BroadcastConstants.DEFER_BOOT_COMPLETED_BROADCAST_TARGET_T_ONLY;
import android.annotation.NonNull;
import android.app.ActivityThread;
@@ -203,6 +205,10 @@
private static final boolean DEFAULT_ENABLE_COMPONENT_ALIAS = false;
private static final String DEFAULT_COMPONENT_ALIAS_OVERRIDES = "";
+ private static final int DEFAULT_DEFER_BOOT_COMPLETED_BROADCAST =
+ DEFER_BOOT_COMPLETED_BROADCAST_BACKGROUND_RESTRICTED_ONLY
+ | DEFER_BOOT_COMPLETED_BROADCAST_TARGET_T_ONLY;
+
// Flag stored in the DeviceConfig API.
/**
* Maximum number of cached processes.
@@ -292,6 +298,9 @@
*/
private static final String KEY_PROCESS_KILL_TIMEOUT = "process_kill_timeout";
+ private static final String KEY_DEFER_BOOT_COMPLETED_BROADCAST =
+ "defer_boot_completed_broadcast";
+
// Maximum number of cached processes we will allow.
public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES;
@@ -603,6 +612,15 @@
volatile boolean mEnableComponentAlias = DEFAULT_ENABLE_COMPONENT_ALIAS;
/**
+ * Where or not to defer LOCKED_BOOT_COMPLETED and BOOT_COMPLETED broadcasts until the first
+ * time the process of the UID is started.
+ * Defined in {@link BroadcastConstants#DeferBootCompletedBroadcastType}
+ */
+ @GuardedBy("mService")
+ volatile @BroadcastConstants.DeferBootCompletedBroadcastType int mDeferBootCompletedBroadcast =
+ DEFAULT_DEFER_BOOT_COMPLETED_BROADCAST;
+
+ /**
* Defines component aliases. Format
* ComponentName ":" ComponentName ( "," ComponentName ":" ComponentName )*
*/
@@ -846,6 +864,9 @@
case KEY_PROCESS_KILL_TIMEOUT:
updateProcessKillTimeout();
break;
+ case KEY_DEFER_BOOT_COMPLETED_BROADCAST:
+ updateDeferBootCompletedBroadcast();
+ break;
default:
break;
}
@@ -1258,6 +1279,13 @@
}
}
+ private void updateDeferBootCompletedBroadcast() {
+ mDeferBootCompletedBroadcast = DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_DEFER_BOOT_COMPLETED_BROADCAST,
+ DEFAULT_DEFER_BOOT_COMPLETED_BROADCAST);
+ }
+
private long[] parseLongArray(@NonNull String key, @NonNull long[] def) {
final String val = DeviceConfig.getString(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
key, null);
@@ -1529,6 +1557,8 @@
pw.print("="); pw.println(mEnableComponentAlias);
pw.print(" "); pw.print(KEY_COMPONENT_ALIAS_OVERRIDES);
pw.print("="); pw.println(mComponentAliasOverrides);
+ pw.print(" "); pw.print(KEY_DEFER_BOOT_COMPLETED_BROADCAST);
+ pw.print("="); pw.println(mDeferBootCompletedBroadcast);
pw.println();
if (mOverrideMaxCachedProcesses >= 0) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerLocal.java b/services/core/java/com/android/server/am/ActivityManagerLocal.java
index d9ee7d9..535340b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerLocal.java
+++ b/services/core/java/com/android/server/am/ActivityManagerLocal.java
@@ -17,10 +17,12 @@
package com.android.server.am;
import android.annotation.NonNull;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
-import android.os.TransactionTooLargeException;
+import android.os.RemoteException;
/**
* Interface for in-process calls into
@@ -63,22 +65,28 @@
void tempAllowWhileInUsePermissionInFgs(int uid, long durationMs);
/**
- * Starts a supplemental process service and binds to it. You can through the arguments here
- * have the system bring up multiple concurrent processes hosting their own instance of that
- * service. The <var>userAppUid</var> you provide here identifies the different instances - each
- * unique uid is attributed to a supplemental process.
+ * Binds to a supplemental process service, creating it if needed. You can through the arguments
+ * here have the system bring up multiple concurrent processes hosting their own instance of
+ * that service. The {@code processName} you provide here identifies the different instances.
*
* @param service Identifies the supplemental process service to connect to. The Intent must
* specify an explicit component name. This value cannot be null.
* @param conn Receives information as the service is started and stopped.
* This must be a valid ServiceConnection object; it must not be null.
* @param userAppUid Uid of the app for which the supplemental process needs to be spawned.
+ * @param processName 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.
+ * @param flags Operation options provided by Context class for the binding.
* @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.
+ * @throws RemoteException If the service could not be brought up.
+ * @see Context#bindService(Intent, ServiceConnection, int)
*/
- boolean startAndBindSupplementalProcessService(@NonNull Intent service,
- @NonNull ServiceConnection conn, int userAppUid) throws TransactionTooLargeException;
-
+ @SuppressLint("RethrowRemoteException")
+ boolean bindSupplementalProcessService(@NonNull Intent service, @NonNull ServiceConnection conn,
+ int userAppUid, @NonNull String processName, @Context.BindServiceFlags int flags)
+ throws RemoteException;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5cc163d..2371101 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1892,6 +1892,8 @@
ProcessRecord app = mProcessList.newProcessRecordLocked(info, info.processName,
false,
0,
+ false,
+ 0,
new HostingRecord("system"));
app.setPersistent(true);
app.setPid(MY_PID);
@@ -2780,18 +2782,32 @@
false /* knownToBeDead */, 0 /* intentFlags */,
sNullHostingRecord /* hostingRecord */, ZYGOTE_POLICY_FLAG_EMPTY,
true /* allowWhileBooting */, true /* isolated */,
- uid, abiOverride, entryPoint, entryPointArgs, crashHandler);
+ uid, false /* supplemental */, 0 /* supplementalUid */,
+ abiOverride, entryPoint, entryPointArgs, crashHandler);
return proc != null;
}
}
@GuardedBy("this")
+ final ProcessRecord startSupplementalProcessLocked(String processName,
+ ApplicationInfo info, boolean knownToBeDead, int intentFlags,
+ HostingRecord hostingRecord, int zygotePolicyFlags, int supplementalUid) {
+ return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
+ hostingRecord, zygotePolicyFlags, false /* allowWhileBooting */,
+ false /* isolated */, 0 /* isolatedUid */,
+ true /* supplemental */, supplementalUid,
+ null /* ABI override */, null /* entryPoint */,
+ null /* entryPointArgs */, null /* crashHandler */);
+ }
+
+ @GuardedBy("this")
final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
HostingRecord hostingRecord, int zygotePolicyFlags, boolean allowWhileBooting,
boolean isolated) {
return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
hostingRecord, zygotePolicyFlags, allowWhileBooting, isolated, 0 /* isolatedUid */,
+ false /* supplemental */, 0 /* supplementalUid */,
null /* ABI override */, null /* entryPoint */,
null /* entryPointArgs */, null /* crashHandler */);
}
@@ -4840,6 +4856,10 @@
}
}
+ if (!badApp) {
+ updateUidReadyForBootCompletedBroadcastLocked(app.uid);
+ }
+
// Check if a next-broadcast receiver is in this process...
if (!badApp && isPendingBroadcastProcessLocked(pid)) {
try {
@@ -6466,7 +6486,8 @@
return isBackgroundRestrictedNoCheck(callingUid, packageName);
}
- boolean isBackgroundRestrictedNoCheck(final int uid, final String packageName) {
+ @VisibleForTesting
+ public boolean isBackgroundRestrictedNoCheck(final int uid, final String packageName) {
final int mode = getAppOpsManager().checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
uid, packageName);
return mode != AppOpsManager.MODE_ALLOWED;
@@ -6521,6 +6542,7 @@
if (app == null) {
app = mProcessList.newProcessRecordLocked(info, customProcess, isolated, 0,
+ false, 0,
new HostingRecord("added application",
customProcess != null ? customProcess : info.processName));
updateLruProcessLocked(app, false, null);
@@ -12346,12 +12368,13 @@
String resolvedType, IServiceConnection connection, int flags, String instanceName,
String callingPackage, int userId) throws TransactionTooLargeException {
return bindServiceInstance(caller, token, service, resolvedType, connection, flags,
- instanceName, false, callingPackage, userId);
+ instanceName, false, 0, callingPackage, userId);
}
private int bindServiceInstance(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags, String instanceName,
- boolean isSupplementalProcessService, String callingPackage, int userId)
+ boolean isSupplementalProcessService, int supplementedAppUid, String callingPackage,
+ int userId)
throws TransactionTooLargeException {
enforceNotIsolatedCaller("bindService");
@@ -12382,7 +12405,8 @@
synchronized(this) {
return mServices.bindServiceLocked(caller, token, service, resolvedType, connection,
- flags, instanceName, isSupplementalProcessService, callingPackage, userId);
+ flags, instanceName, isSupplementalProcessService, supplementedAppUid,
+ callingPackage, userId);
}
}
@@ -12745,6 +12769,13 @@
return didSomething;
}
+ void updateUidReadyForBootCompletedBroadcastLocked(int uid) {
+ for (BroadcastQueue queue : mBroadcastQueues) {
+ queue.updateUidReadyForBootCompletedBroadcastLocked(uid);
+ queue.scheduleBroadcastsLocked();
+ }
+ }
+
/**
* @deprecated Use {@link #registerReceiverWithFeature}
*/
@@ -13370,10 +13401,8 @@
}
}
- // TODO (206518114): We need to use the "real" package name which sent the broadcast,
- // in case the broadcast is sent via PendingIntent.
if (brOptions.getIdForResponseEvent() > 0) {
- enforceUsageStatsPermission(callerPackage, realCallingUid, realCallingPid,
+ enforceUsageStatsPermission(callerPackage, callingUid, callingPid,
"recordResponseEventWhileInBackground()");
}
}
@@ -15951,14 +15980,17 @@
}
@Override
- public boolean startAndBindSupplementalProcessService(Intent service,
- ServiceConnection conn, int userAppUid) throws TransactionTooLargeException {
+ public boolean bindSupplementalProcessService(Intent service, ServiceConnection conn,
+ int userAppUid, String processName, int flags) throws RemoteException {
if (service == null) {
throw new IllegalArgumentException("intent is null");
}
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
+ if (processName == null) {
+ throw new IllegalArgumentException("processName is null");
+ }
if (service.getComponent() == null) {
throw new IllegalArgumentException("service must specify explicit component");
}
@@ -15967,15 +15999,14 @@
}
Handler handler = mContext.getMainThreadHandler();
- int flags = Context.BIND_AUTO_CREATE;
final IServiceConnection sd = mContext.getServiceDispatcher(conn, handler, flags);
service.prepareToLeaveProcess(mContext);
return ActivityManagerService.this.bindServiceInstance(
- mContext.getIApplicationThread(), mContext.getActivityToken(), service,
- service.resolveTypeIfNeeded(mContext.getContentResolver()), sd, flags,
- Integer.toString(userAppUid), /*isSupplementalProcessService*/ true,
- mContext.getOpPackageName(), UserHandle.getUserId(userAppUid)) != 0;
+ mContext.getIApplicationThread(), mContext.getActivityToken(), service,
+ service.resolveTypeIfNeeded(mContext.getContentResolver()), sd, flags,
+ processName, /*isSupplementalProcessService*/ true, userAppUid,
+ mContext.getOpPackageName(), UserHandle.getUserId(userAppUid)) != 0;
}
@Override
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 97727b0..08508b2 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -31,6 +31,7 @@
import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_NORMAL;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATTERY_USAGE_COUNT;
import static com.android.server.am.LowMemDetector.ADJ_MEM_FACTOR_NOTHING;
import android.app.ActivityManager;
@@ -3256,12 +3257,12 @@
return -1;
}
if (arg == null) {
- batteryTracker.mDebugUidPercentages.clear();
+ batteryTracker.clearDebugUidPercentage();
return 0;
}
String[] pairs = arg.split(",");
int[] uids = new int[pairs.length];
- double[] values = new double[pairs.length];
+ double[][] values = new double[pairs.length][];
try {
for (int i = 0; i < pairs.length; i++) {
String[] pair = pairs[i].split("=");
@@ -3270,16 +3271,21 @@
return -1;
}
uids[i] = Integer.parseInt(pair[0]);
- values[i] = Double.parseDouble(pair[1]);
+ final String[] vals = pair[1].split(":");
+ if (vals.length != BATTERY_USAGE_COUNT) {
+ getErrPrintWriter().println("Malformed input");
+ return -1;
+ }
+ values[i] = new double[vals.length];
+ for (int j = 0; j < vals.length; j++) {
+ values[i][j] = Double.parseDouble(vals[j]);
+ }
}
} catch (NumberFormatException e) {
getErrPrintWriter().println("Malformed input");
return -1;
}
- batteryTracker.mDebugUidPercentages.clear();
- for (int i = 0; i < pairs.length; i++) {
- batteryTracker.mDebugUidPercentages.put(uids[i], values[i]);
- }
+ batteryTracker.setDebugUidPercentage(uids, values);
return 0;
}
diff --git a/services/core/java/com/android/server/am/AppBatteryExemptionTracker.java b/services/core/java/com/android/server/am/AppBatteryExemptionTracker.java
index 75de3a1..d1cf004 100644
--- a/services/core/java/com/android/server/am/AppBatteryExemptionTracker.java
+++ b/services/core/java/com/android/server/am/AppBatteryExemptionTracker.java
@@ -18,8 +18,9 @@
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.AppBatteryTracker.BATTERY_USAGE_NONE;
import static com.android.server.am.AppRestrictionController.DEVICE_CONFIG_SUBNAMESPACE_PREFIX;
-import static com.android.server.am.BaseAppStateDurationsTracker.EVENT_NUM;
+import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_NUM;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -28,13 +29,16 @@
import android.util.Pair;
import android.util.Slog;
+import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.am.AppBatteryExemptionTracker.AppBatteryExemptionPolicy;
import com.android.server.am.AppBatteryExemptionTracker.UidBatteryStates;
import com.android.server.am.AppBatteryTracker.AppBatteryPolicy;
-import com.android.server.am.BaseAppStateDurationsTracker.EventListener;
+import com.android.server.am.AppBatteryTracker.BatteryUsage;
+import com.android.server.am.AppBatteryTracker.ImmutableBatteryUsage;
import com.android.server.am.BaseAppStateTimeEvents.BaseTimeEvent;
import com.android.server.am.BaseAppStateTracker.Injector;
+import com.android.server.am.BaseAppStateTracker.StateListener;
import java.io.PrintWriter;
import java.lang.reflect.Constructor;
@@ -53,13 +57,13 @@
*/
final class AppBatteryExemptionTracker
extends BaseAppStateDurationsTracker<AppBatteryExemptionPolicy, UidBatteryStates>
- implements BaseAppStateEvents.Factory<UidBatteryStates>, EventListener {
+ implements BaseAppStateEvents.Factory<UidBatteryStates>, StateListener {
private static final String TAG = TAG_WITH_CLASS_NAME ? "AppBatteryExemptionTracker" : TAG_AM;
private static final boolean DEBUG_BACKGROUND_BATTERY_EXEMPTION_TRACKER = false;
// As it's a UID-based tracker, anywhere which requires a package name, use this default name.
- private static final String DEFAULT_NAME = "";
+ static final String DEFAULT_NAME = "";
AppBatteryExemptionTracker(Context context, AppRestrictionController controller) {
this(context, controller, null, null);
@@ -76,9 +80,7 @@
void onSystemReady() {
super.onSystemReady();
mAppRestrictionController.forEachTracker(tracker -> {
- if (tracker instanceof BaseAppStateDurationsTracker) {
- ((BaseAppStateDurationsTracker) tracker).registerEventListener(this);
- }
+ tracker.registerStateListener(this);
});
}
@@ -93,18 +95,20 @@
}
@Override
- public void onNewEvent(int uid, String packageName, boolean start, long now, int eventType) {
+ public void onStateChange(int uid, String packageName, boolean start, long now, int stateType) {
if (!mInjector.getPolicy().isEnabled()) {
return;
}
- final double batteryUsage = mAppRestrictionController.getUidBatteryUsage(uid);
+ final ImmutableBatteryUsage batteryUsage = mAppRestrictionController
+ .getUidBatteryUsage(uid);
+ final int stateTypeIndex = stateTypeToIndex(stateType);
synchronized (mLock) {
UidBatteryStates pkg = mPkgEvents.get(uid, DEFAULT_NAME);
if (pkg == null) {
pkg = createAppStateEvents(uid, DEFAULT_NAME);
mPkgEvents.put(uid, DEFAULT_NAME, pkg);
}
- pkg.addEvent(start, now, batteryUsage, eventType);
+ pkg.addEvent(start, now, batteryUsage, stateTypeIndex);
}
}
@@ -120,22 +124,24 @@
* @return The to-be-exempted battery usage of the given UID in the given duration; it could
* be considered as "exempted" due to various use cases, i.e. media playback.
*/
- double getUidBatteryExemptedUsageSince(int uid, long since, long now) {
+ ImmutableBatteryUsage getUidBatteryExemptedUsageSince(int uid, long since, long now,
+ int types) {
if (!mInjector.getPolicy().isEnabled()) {
- return 0.0d;
+ return BATTERY_USAGE_NONE;
}
- Pair<Double, Double> result;
+ Pair<ImmutableBatteryUsage, ImmutableBatteryUsage> result;
synchronized (mLock) {
final UidBatteryStates pkg = mPkgEvents.get(uid, DEFAULT_NAME);
if (pkg == null) {
- return 0.0d;
+ return BATTERY_USAGE_NONE;
}
- result = pkg.getBatteryUsageSince(since, now);
+ result = pkg.getBatteryUsageSince(since, now, types);
}
- if (result.second > 0.0d) {
+ if (!result.second.isEmpty()) {
// We have an open event (just start, no stop), get the battery usage till now.
- final double batteryUsage = mAppRestrictionController.getUidBatteryUsage(uid);
- return result.first + batteryUsage - result.second;
+ final ImmutableBatteryUsage batteryUsage = mAppRestrictionController
+ .getUidBatteryUsage(uid);
+ return result.first.mutate().add(batteryUsage).subtract(result.second).unmutate();
}
return result.first;
}
@@ -143,7 +149,7 @@
static final class UidBatteryStates extends BaseAppStateDurations<UidStateEventWithBattery> {
UidBatteryStates(int uid, @NonNull String tag,
@NonNull MaxTrackingDurationConfig maxTrackingDurationConfig) {
- super(uid, DEFAULT_NAME, EVENT_NUM, tag, maxTrackingDurationConfig);
+ super(uid, DEFAULT_NAME, STATE_TYPE_NUM, tag, maxTrackingDurationConfig);
}
UidBatteryStates(@NonNull UidBatteryStates other) {
@@ -154,9 +160,9 @@
* @param start {@code true} if it's a start event.
* @param now The timestamp when this event occurred.
* @param batteryUsage The background current drain since the system boots.
- * @param eventType One of EVENT_TYPE_* defined in the class BaseAppStateDurationsTracker.
+ * @param eventType One of STATE_TYPE_INDEX_* defined in the class BaseAppStateTracker.
*/
- void addEvent(boolean start, long now, double batteryUsage, int eventType) {
+ void addEvent(boolean start, long now, ImmutableBatteryUsage batteryUsage, int eventType) {
if (start) {
addEvent(start, new UidStateEventWithBattery(start, now, batteryUsage, null),
eventType);
@@ -169,7 +175,8 @@
return;
}
addEvent(start, new UidStateEventWithBattery(start, now,
- batteryUsage - last.getBatteryUsage(), last), eventType);
+ batteryUsage.mutate().subtract(last.getBatteryUsage()).unmutate(), last),
+ eventType);
}
}
@@ -177,43 +184,40 @@
return mEvents[eventType] != null ? mEvents[eventType].peekLast() : null;
}
- /**
- * @return The pair of bg battery usage of given duration; the first value in the pair
- * is the aggregated battery usage of all event pairs in this duration; while
- * the second value is the battery usage since the system boots, if there is
- * an open event(just start, no stop) at the end of the duration.
- */
- Pair<Double, Double> getBatteryUsageSince(long since, long now, int eventType) {
- return getBatteryUsageSince(since, now, mEvents[eventType]);
- }
-
- private Pair<Double, Double> getBatteryUsageSince(long since, long now,
- LinkedList<UidStateEventWithBattery> events) {
+ private Pair<ImmutableBatteryUsage, ImmutableBatteryUsage> getBatteryUsageSince(long since,
+ long now, LinkedList<UidStateEventWithBattery> events) {
if (events == null || events.size() == 0) {
- return Pair.create(0.0d, 0.0d);
+ return Pair.create(BATTERY_USAGE_NONE, BATTERY_USAGE_NONE);
}
- double batteryUsage = 0.0d;
+ final BatteryUsage batteryUsage = new BatteryUsage();
UidStateEventWithBattery lastEvent = null;
for (UidStateEventWithBattery event : events) {
lastEvent = event;
if (event.getTimestamp() < since || event.isStart()) {
continue;
}
- batteryUsage += event.getBatteryUsage(since, Math.min(now, event.getTimestamp()));
+ batteryUsage.add(event.getBatteryUsage(since, Math.min(now, event.getTimestamp())));
if (now <= event.getTimestamp()) {
break;
}
}
- return Pair.create(batteryUsage, lastEvent.isStart() ? lastEvent.getBatteryUsage() : 0);
+ return Pair.create(batteryUsage.unmutate(), lastEvent.isStart()
+ ? lastEvent.getBatteryUsage() : BATTERY_USAGE_NONE);
}
/**
- * @return The aggregated battery usage amongst all the event types we're tracking.
+ * @return The pair of bg battery usage of given duration; the first value in the pair
+ * is the aggregated battery usage of selected events in this duration; while
+ * the second value is the battery usage since the system boots, if there is
+ * an open event(just start, no stop) at the end of the duration.
*/
- Pair<Double, Double> getBatteryUsageSince(long since, long now) {
+ Pair<ImmutableBatteryUsage, ImmutableBatteryUsage> getBatteryUsageSince(long since,
+ long now, int types) {
LinkedList<UidStateEventWithBattery> result = new LinkedList<>();
for (int i = 0; i < mEvents.length; i++) {
- result = add(result, mEvents[i]);
+ if ((types & stateIndexToType(i)) != 0) {
+ result = add(result, mEvents[i]);
+ }
}
return getBatteryUsageSince(since, now, result);
}
@@ -236,7 +240,7 @@
UidStateEventWithBattery l = itl.next(), r = itr.next();
LinkedList<UidStateEventWithBattery> dest = new LinkedList<>();
boolean actl = false, actr = false, overlapping = false;
- double batteryUsage = 0.0d;
+ final BatteryUsage batteryUsage = new BatteryUsage();
long recentActTs = 0, overlappingDuration = 0;
for (long lts = l.getTimestamp(), rts = r.getTimestamp();
lts != Long.MAX_VALUE || rts != Long.MAX_VALUE;) {
@@ -245,8 +249,8 @@
if (lts == rts) {
earliest = l;
// we'll deal with the double counting problem later.
- batteryUsage += actl ? l.getBatteryUsage() : 0.0d;
- batteryUsage += actr ? r.getBatteryUsage() : 0.0d;
+ if (actl) batteryUsage.add(l.getBatteryUsage());
+ if (actr) batteryUsage.add(r.getBatteryUsage());
overlappingDuration += overlapping && (actl || actr)
? (lts - recentActTs) : 0;
actl = !actl;
@@ -255,13 +259,13 @@
rts = itr.hasNext() ? (r = itr.next()).getTimestamp() : Long.MAX_VALUE;
} else if (lts < rts) {
earliest = l;
- batteryUsage += actl ? l.getBatteryUsage() : 0.0d;
+ if (actl) batteryUsage.add(l.getBatteryUsage());
overlappingDuration += overlapping && actl ? (lts - recentActTs) : 0;
actl = !actl;
lts = itl.hasNext() ? (l = itl.next()).getTimestamp() : Long.MAX_VALUE;
} else {
earliest = r;
- batteryUsage += actr ? r.getBatteryUsage() : 0.0d;
+ if (actr) batteryUsage.add(r.getBatteryUsage());
overlappingDuration += overlapping && actr ? (rts - recentActTs) : 0;
actr = !actr;
rts = itr.hasNext() ? (r = itr.next()).getTimestamp() : Long.MAX_VALUE;
@@ -281,12 +285,12 @@
final long durationWithOverlapping = duration + overlappingDuration;
// Get the proportional batteryUsage.
if (durationWithOverlapping != 0) {
- batteryUsage *= duration * 1.0d / durationWithOverlapping;
+ batteryUsage.scale(duration * 1.0d / durationWithOverlapping);
+ event.update(lastEvent, new ImmutableBatteryUsage(batteryUsage));
} else {
- batteryUsage = 0.0d;
+ event.update(lastEvent, BATTERY_USAGE_NONE);
}
- event.update(lastEvent, batteryUsage);
- batteryUsage = 0.0d;
+ batteryUsage.setTo(BATTERY_USAGE_NONE);
overlappingDuration = 0;
}
dest.add(event);
@@ -322,14 +326,15 @@
* the system boots if the {@link #mIsStart} is true, but will be the delta of the bg
* battery usage since the start event if the {@link #mIsStart} is false.
*/
- private double mBatteryUsage;
+ private @NonNull ImmutableBatteryUsage mBatteryUsage;
/**
* The peer event of this pair (a pair of start/stop events).
*/
private @Nullable UidStateEventWithBattery mPeer;
- UidStateEventWithBattery(boolean isStart, long now, double batteryUsage,
+ UidStateEventWithBattery(boolean isStart, long now,
+ @NonNull ImmutableBatteryUsage batteryUsage,
@Nullable UidStateEventWithBattery peer) {
super(now);
mIsStart = isStart;
@@ -355,15 +360,19 @@
}
if (mPeer != null) {
// Reduce the bg battery usage proportionally.
- final double batteryUsage = mPeer.getBatteryUsage();
+ final ImmutableBatteryUsage batteryUsage = mPeer.getBatteryUsage();
mPeer.mBatteryUsage = mPeer.getBatteryUsage(timestamp, mPeer.mTimestamp);
// Update the battery data of the start event too.
- mBatteryUsage += batteryUsage - mPeer.mBatteryUsage;
+ mBatteryUsage = mBatteryUsage.mutate()
+ .add(batteryUsage)
+ .subtract(mPeer.mBatteryUsage)
+ .unmutate();
}
mTimestamp = timestamp;
}
- void update(@NonNull UidStateEventWithBattery peer, double batteryUsage) {
+ void update(@NonNull UidStateEventWithBattery peer,
+ @NonNull ImmutableBatteryUsage batteryUsage) {
mPeer = peer;
peer.mPeer = this;
mBatteryUsage = batteryUsage;
@@ -373,18 +382,19 @@
return mIsStart;
}
- double getBatteryUsage(long start, long end) {
+ @NonNull ImmutableBatteryUsage getBatteryUsage(long start, long end) {
if (mIsStart || start >= mTimestamp || end <= start) {
- return 0.0d;
+ return BATTERY_USAGE_NONE;
}
start = Math.max(start, mPeer.mTimestamp);
end = Math.min(end, mTimestamp);
final long totalDur = mTimestamp - mPeer.mTimestamp;
final long inputDur = end - start;
- return totalDur != 0 ? mBatteryUsage * (1.0d * inputDur) / totalDur : 0.0d;
+ return totalDur != 0 ? (totalDur == inputDur ? mBatteryUsage : mBatteryUsage.mutate()
+ .scale((1.0d * inputDur) / totalDur).unmutate()) : BATTERY_USAGE_NONE;
}
- double getBatteryUsage() {
+ @NonNull ImmutableBatteryUsage getBatteryUsage() {
return mBatteryUsage;
}
@@ -404,14 +414,20 @@
final UidStateEventWithBattery otherEvent = (UidStateEventWithBattery) other;
return otherEvent.mIsStart == mIsStart
&& otherEvent.mTimestamp == mTimestamp
- && Double.compare(otherEvent.mBatteryUsage, mBatteryUsage) == 0;
+ && mBatteryUsage.equals(otherEvent.mBatteryUsage);
+ }
+
+ @Override
+ public String toString() {
+ return "UidStateEventWithBattery(" + mIsStart + ", " + mTimestamp
+ + ", " + mBatteryUsage + ")";
}
@Override
public int hashCode() {
return (Boolean.hashCode(mIsStart) * 31
+ Long.hashCode(mTimestamp)) * 31
- + Double.hashCode(mBatteryUsage);
+ + mBatteryUsage.hashCode();
}
}
@@ -433,7 +449,8 @@
super(injector, tracker,
KEY_BG_BATTERY_EXEMPTION_ENABLED, DEFAULT_BG_BATTERY_EXEMPTION_ENABLED,
AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_WINDOW,
- AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_WINDOW_MS);
+ tracker.mContext.getResources()
+ .getInteger(R.integer.config_bg_current_drain_window));
}
@Override
diff --git a/services/core/java/com/android/server/am/AppBatteryTracker.java b/services/core/java/com/android/server/am/AppBatteryTracker.java
index b8f5c50..655e309 100644
--- a/services/core/java/com/android/server/am/AppBatteryTracker.java
+++ b/services/core/java/com/android/server/am/AppBatteryTracker.java
@@ -28,23 +28,28 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.BatteryConsumer.POWER_COMPONENT_ANY;
import static android.os.BatteryConsumer.PROCESS_STATE_BACKGROUND;
+import static android.os.BatteryConsumer.PROCESS_STATE_COUNT;
import static android.os.BatteryConsumer.PROCESS_STATE_FOREGROUND;
import static android.os.BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE;
+import static android.os.BatteryConsumer.PROCESS_STATE_UNSPECIFIED;
import static android.os.PowerExemptionManager.REASON_DENIED;
import static android.util.TimeUtils.formatTime;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.AppRestrictionController.DEVICE_CONFIG_SUBNAMESPACE_PREFIX;
-import static com.android.server.am.BaseAppStateTracker.ONE_DAY;
import static com.android.server.am.BaseAppStateTracker.ONE_MINUTE;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManager.RestrictionLevel;
import android.content.Context;
import android.content.pm.ServiceInfo;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.os.BatteryConsumer;
+import android.os.BatteryConsumer.Dimensions;
import android.os.BatteryStatsInternal;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
@@ -58,9 +63,9 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
-import android.util.SparseDoubleArray;
import android.util.TimeUtils;
+import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
@@ -98,12 +103,7 @@
static final long BATTERY_USAGE_STATS_POLLING_MIN_INTERVAL_MS_LONG = 5 * ONE_MINUTE; // 5 mins
static final long BATTERY_USAGE_STATS_POLLING_MIN_INTERVAL_MS_DEBUG = 2_000L; // 2s
- static final BatteryConsumer.Dimensions BATT_DIMEN_FG =
- new BatteryConsumer.Dimensions(POWER_COMPONENT_ANY, PROCESS_STATE_FOREGROUND);
- static final BatteryConsumer.Dimensions BATT_DIMEN_BG =
- new BatteryConsumer.Dimensions(POWER_COMPONENT_ANY, PROCESS_STATE_BACKGROUND);
- static final BatteryConsumer.Dimensions BATT_DIMEN_FGS =
- new BatteryConsumer.Dimensions(POWER_COMPONENT_ANY, PROCESS_STATE_FOREGROUND_SERVICE);
+ static final ImmutableBatteryUsage BATTERY_USAGE_NONE = new ImmutableBatteryUsage();
private final Runnable mBgBatteryUsageStatsPolling = this::updateBatteryUsageStatsAndCheck;
private final Runnable mBgBatteryUsageStatsCheck = this::checkBatteryUsageStats;
@@ -132,29 +132,30 @@
* the last battery stats reset prior to that (whoever is earlier).
*/
@GuardedBy("mLock")
- private final SparseDoubleArray mUidBatteryUsage = new SparseDoubleArray();
+ private final SparseArray<BatteryUsage> mUidBatteryUsage = new SparseArray<>();
/**
* The battery usage for each UID, in the rolling window of the past.
*/
@GuardedBy("mLock")
- private final SparseDoubleArray mUidBatteryUsageInWindow = new SparseDoubleArray();
+ private final SparseArray<ImmutableBatteryUsage> mUidBatteryUsageInWindow = new SparseArray<>();
/**
* The uid battery usage stats data from our last query, it consists of the data since
* last battery stats reset.
*/
@GuardedBy("mLock")
- private final SparseDoubleArray mLastUidBatteryUsage = new SparseDoubleArray();
+ private final SparseArray<ImmutableBatteryUsage> mLastUidBatteryUsage = new SparseArray<>();
// No lock is needed.
- private final SparseDoubleArray mTmpUidBatteryUsage = new SparseDoubleArray();
+ private final SparseArray<BatteryUsage> mTmpUidBatteryUsage = new SparseArray<>();
// No lock is needed.
- private final SparseDoubleArray mTmpUidBatteryUsage2 = new SparseDoubleArray();
+ private final SparseArray<ImmutableBatteryUsage> mTmpUidBatteryUsage2 = new SparseArray<>();
// No lock is needed.
- private final SparseDoubleArray mTmpUidBatteryUsageInWindow = new SparseDoubleArray();
+ private final SparseArray<ImmutableBatteryUsage> mTmpUidBatteryUsageInWindow =
+ new SparseArray<>();
// No lock is needed.
private final ArraySet<UserHandle> mTmpUserIds = new ArraySet<>();
@@ -166,7 +167,7 @@
private long mLastUidBatteryUsageStartTs;
// For debug only.
- final SparseDoubleArray mDebugUidPercentages = new SparseDoubleArray();
+ private final SparseArray<BatteryUsage> mDebugUidPercentages = new SparseArray<>();
AppBatteryTracker(Context context, AppRestrictionController controller) {
this(context, controller, null, null);
@@ -277,18 +278,24 @@
* </p>
*/
@Override
- public double getUidBatteryUsage(int uid) {
+ @NonNull
+ public ImmutableBatteryUsage getUidBatteryUsage(int uid) {
final long now = mInjector.currentTimeMillis();
final boolean updated = updateBatteryUsageStatsIfNecessary(now, false);
synchronized (mLock) {
if (updated) {
// We just got fresh data, schedule a check right a way.
mBgHandler.removeCallbacks(mBgBatteryUsageStatsPolling);
- if (!mBgHandler.hasCallbacks(mBgBatteryUsageStatsCheck)) {
- mBgHandler.post(mBgBatteryUsageStatsCheck);
- }
+ scheduleBgBatteryUsageStatsCheck();
}
- return mUidBatteryUsage.get(uid, 0.0d);
+ final BatteryUsage usage = mUidBatteryUsage.get(uid);
+ return usage != null ? new ImmutableBatteryUsage(usage) : BATTERY_USAGE_NONE;
+ }
+ }
+
+ private void scheduleBgBatteryUsageStatsCheck() {
+ if (!mBgHandler.hasCallbacks(mBgBatteryUsageStatsCheck)) {
+ mBgHandler.post(mBgBatteryUsageStatsCheck);
}
}
@@ -309,27 +316,33 @@
final long now = SystemClock.elapsedRealtime();
final AppBatteryPolicy bgPolicy = mInjector.getPolicy();
try {
- final SparseDoubleArray uidConsumers = mTmpUidBatteryUsageInWindow;
+ final SparseArray<ImmutableBatteryUsage> uidConsumers = mTmpUidBatteryUsageInWindow;
synchronized (mLock) {
copyUidBatteryUsage(mUidBatteryUsageInWindow, uidConsumers);
}
final long since = Math.max(0, now - bgPolicy.mBgCurrentDrainWindowMs);
for (int i = 0, size = uidConsumers.size(); i < size; i++) {
final int uid = uidConsumers.keyAt(i);
- final double actualUsage = uidConsumers.valueAt(i);
- final double exemptedUsage = mAppRestrictionController
- .getUidBatteryExemptedUsageSince(uid, since, now);
+ final ImmutableBatteryUsage actualUsage = uidConsumers.valueAt(i);
+ final ImmutableBatteryUsage exemptedUsage = mAppRestrictionController
+ .getUidBatteryExemptedUsageSince(uid, since, now,
+ bgPolicy.mBgCurrentDrainExemptedTypes);
// It's possible the exemptedUsage could be larger than actualUsage,
// as the former one is an approximate value.
- final double bgUsage = Math.max(0.0d, actualUsage - exemptedUsage);
- final double percentage = bgPolicy.getPercentage(uid, bgUsage);
+ final BatteryUsage bgUsage = actualUsage.mutate()
+ .subtract(exemptedUsage)
+ .calcPercentage(uid, bgPolicy);
if (DEBUG_BACKGROUND_BATTERY_TRACKER) {
Slog.i(TAG, String.format(
- "UID %d: %.3f mAh (or %4.2f%%) %.3f %.3f over the past %s",
- uid, bgUsage, percentage, exemptedUsage, actualUsage,
+ "UID %d: %s (%s) | %s | %s over the past %s",
+ uid,
+ bgUsage.toString(),
+ bgUsage.percentageToString(),
+ exemptedUsage.toString(),
+ actualUsage.toString(),
TimeUtils.formatDuration(bgPolicy.mBgCurrentDrainWindowMs)));
}
- bgPolicy.handleUidBatteryUsage(uid, percentage);
+ bgPolicy.handleUidBatteryUsage(uid, bgUsage);
}
// For debugging only.
for (int i = 0, size = mDebugUidPercentages.size(); i < size; i++) {
@@ -384,7 +397,7 @@
private void updateBatteryUsageStatsOnce(long now) {
final AppBatteryPolicy bgPolicy = mInjector.getPolicy();
final ArraySet<UserHandle> userIds = mTmpUserIds;
- final SparseDoubleArray buf = mTmpUidBatteryUsage;
+ final SparseArray<BatteryUsage> buf = mTmpUidBatteryUsage;
final BatteryStatsInternal batteryStatsInternal = mInjector.getBatteryStatsInternal();
final long windowSize = bgPolicy.mBgCurrentDrainWindowMs;
@@ -453,26 +466,26 @@
for (int i = 0, size = buf.size(); i < size; i++) {
final int uid = buf.keyAt(i);
final int index = mUidBatteryUsage.indexOfKey(uid);
- final double lastUsage = mLastUidBatteryUsage.get(uid, 0.0d);
- final double curUsage = buf.valueAt(i);
- final double before;
+ final BatteryUsage lastUsage = mLastUidBatteryUsage.get(uid, BATTERY_USAGE_NONE);
+ final BatteryUsage curUsage = buf.valueAt(i);
+ final BatteryUsage before;
if (index >= 0) {
before = mUidBatteryUsage.valueAt(index);
- mUidBatteryUsage.setValueAt(index, before - lastUsage + curUsage);
+ before.subtract(lastUsage).add(curUsage);
} else {
- before = 0.0d;
+ before = BATTERY_USAGE_NONE;
mUidBatteryUsage.put(uid, curUsage);
}
if (DEBUG_BACKGROUND_BATTERY_TRACKER) {
- final double actualDelta = curUsage - lastUsage;
+ final BatteryUsage actualDelta = new BatteryUsage(curUsage).subtract(lastUsage);
String msg = "Updating mUidBatteryUsage uid=" + uid + ", before=" + before
- + ", after=" + mUidBatteryUsage.get(uid, 0.0d)
+ + ", after=" + mUidBatteryUsage.get(uid, BATTERY_USAGE_NONE)
+ ", delta=" + actualDelta
+ ", last=" + lastUsage
+ ", curStart=" + curStart
+ ", lastLastStart=" + lastUidBatteryUsageStartTs
+ ", thisLastStart=" + mLastUidBatteryUsageStartTs;
- if (actualDelta < 0.0d) {
+ if (!actualDelta.isValid()) {
// Something is wrong, the battery usage shouldn't be negative.
Slog.e(TAG, msg);
} else {
@@ -508,8 +521,8 @@
}
}
- private static BatteryUsageStats updateBatteryUsageStatsOnceInternal(long expectedDuration,
- SparseDoubleArray buf, BatteryUsageStatsQuery.Builder builder,
+ private BatteryUsageStats updateBatteryUsageStatsOnceInternal(long expectedDuration,
+ SparseArray<BatteryUsage> buf, BatteryUsageStatsQuery.Builder builder,
ArraySet<UserHandle> userIds, BatteryStatsInternal batteryStatsInternal) {
for (int i = 0, size = userIds.size(); i < size; i++) {
builder.addUser(userIds.valueAt(i));
@@ -527,16 +540,19 @@
final long end = stats.getStatsEndTimestamp();
final double scale = expectedDuration > 0
? (expectedDuration * 1.0d) / (end - start) : 1.0d;
+ final AppBatteryPolicy bgPolicy = mInjector.getPolicy();
for (UidBatteryConsumer uidConsumer : uidConsumers) {
// TODO: b/200326767 - as we are not supporting per proc state attribution yet,
// we couldn't distinguish between a real FGS vs. a bound FGS proc state.
final int uid = uidConsumer.getUid();
- final double bgUsage = getBgUsage(uidConsumer) * scale;
+ final BatteryUsage bgUsage = new BatteryUsage(uidConsumer, bgPolicy)
+ .scale(scale);
int index = buf.indexOfKey(uid);
if (index < 0) {
buf.put(uid, bgUsage);
} else {
- buf.setValueAt(index, buf.valueAt(index) + bgUsage);
+ final BatteryUsage before = buf.valueAt(index);
+ before.add(bgUsage);
}
if (DEBUG_BACKGROUND_BATTERY_TRACKER) {
Slog.i(TAG, "updateBatteryUsageStatsOnceInternal uid=" + uid
@@ -549,32 +565,19 @@
return stats;
}
- private static void copyUidBatteryUsage(SparseDoubleArray source, SparseDoubleArray dest) {
+ private static void copyUidBatteryUsage(SparseArray<? extends BatteryUsage> source,
+ SparseArray<ImmutableBatteryUsage> dest) {
dest.clear();
for (int i = source.size() - 1; i >= 0; i--) {
- dest.put(source.keyAt(i), source.valueAt(i));
+ dest.put(source.keyAt(i), new ImmutableBatteryUsage(source.valueAt(i)));
}
}
- private static void copyUidBatteryUsage(SparseDoubleArray source, SparseDoubleArray dest,
- double scale) {
+ private static void copyUidBatteryUsage(SparseArray<? extends BatteryUsage> source,
+ SparseArray<ImmutableBatteryUsage> dest, double scale) {
dest.clear();
for (int i = source.size() - 1; i >= 0; i--) {
- dest.put(source.keyAt(i), source.valueAt(i) * scale);
- }
- }
-
- private static double getBgUsage(final UidBatteryConsumer uidConsumer) {
- return getConsumedPowerNoThrow(uidConsumer, BATT_DIMEN_BG)
- + getConsumedPowerNoThrow(uidConsumer, BATT_DIMEN_FGS);
- }
-
- private static double getConsumedPowerNoThrow(final UidBatteryConsumer uidConsumer,
- final BatteryConsumer.Dimensions dimens) {
- try {
- return uidConsumer.getConsumedPower(dimens);
- } catch (IllegalArgumentException e) {
- return 0.0d;
+ dest.put(source.keyAt(i), new ImmutableBatteryUsage(source.valueAt(i), scale));
}
}
@@ -602,6 +605,19 @@
}
}
+ void setDebugUidPercentage(int[] uids, double[][] percentages) {
+ mDebugUidPercentages.clear();
+ for (int i = 0; i < uids.length; i++) {
+ mDebugUidPercentages.put(uids[i], new BatteryUsage().setPercentage(percentages[i]));
+ }
+ scheduleBgBatteryUsageStatsCheck();
+ }
+
+ void clearDebugUidPercentage() {
+ mDebugUidPercentages.clear();
+ scheduleBgBatteryUsageStatsCheck();
+ }
+
@VisibleForTesting
void reset() {
synchronized (mLock) {
@@ -620,7 +636,7 @@
pw.println("APP BATTERY STATE TRACKER:");
updateBatteryUsageStatsIfNecessary(mInjector.currentTimeMillis(), true);
synchronized (mLock) {
- final SparseDoubleArray uidConsumers = mUidBatteryUsageInWindow;
+ final SparseArray<ImmutableBatteryUsage> uidConsumers = mUidBatteryUsageInWindow;
pw.print(" " + prefix);
pw.print(" Last battery usage start=");
TimeUtils.dumpTime(pw, mLastUidBatteryUsageStartTs);
@@ -638,26 +654,286 @@
} else {
for (int i = 0, size = uidConsumers.size(); i < size; i++) {
final int uid = uidConsumers.keyAt(i);
- final double bgUsage = uidConsumers.valueAt(i);
- final double exemptedUsage = mAppRestrictionController
- .getUidBatteryExemptedUsageSince(uid, since, now);
- final double reportedUsage = Math.max(0.0d, bgUsage - exemptedUsage);
- pw.format("%s%s: [%s] %.3f mAh (%4.2f%%) | %.3f mAh (%4.2f%%) | "
- + "%.3f mAh (%4.2f%%) | %.3f mAh\n",
+ final BatteryUsage bgUsage = uidConsumers.valueAt(i)
+ .calcPercentage(uid, bgPolicy);
+ final BatteryUsage exemptedUsage = mAppRestrictionController
+ .getUidBatteryExemptedUsageSince(uid, since, now,
+ bgPolicy.mBgCurrentDrainExemptedTypes)
+ .calcPercentage(uid, bgPolicy);
+ final BatteryUsage reportedUsage = new BatteryUsage(bgUsage)
+ .subtract(exemptedUsage)
+ .calcPercentage(uid, bgPolicy);
+ pw.format("%s%s: [%s] %s (%s) | %s (%s) | %s (%s) | %s\n",
newPrefix, UserHandle.formatUid(uid),
PowerExemptionManager.reasonCodeToString(bgPolicy.shouldExemptUid(uid)),
- bgUsage , bgPolicy.getPercentage(uid, bgUsage),
- exemptedUsage, bgPolicy.getPercentage(-1, exemptedUsage),
- reportedUsage, bgPolicy.getPercentage(-1, reportedUsage),
- mUidBatteryUsage.get(uid, 0.0d));
+ bgUsage.toString(),
+ bgUsage.percentageToString(),
+ exemptedUsage.toString(),
+ exemptedUsage.percentageToString(),
+ reportedUsage.toString(),
+ reportedUsage.percentageToString(),
+ mUidBatteryUsage.get(uid, BATTERY_USAGE_NONE).toString());
}
}
}
super.dump(pw, prefix);
}
+ static class BatteryUsage {
+ static final int BATTERY_USAGE_INDEX_UNSPECIFIED = PROCESS_STATE_UNSPECIFIED;
+ static final int BATTERY_USAGE_INDEX_FOREGROUND = PROCESS_STATE_FOREGROUND;
+ static final int BATTERY_USAGE_INDEX_BACKGROUND = PROCESS_STATE_BACKGROUND;
+ static final int BATTERY_USAGE_INDEX_FOREGROUND_SERVICE = PROCESS_STATE_FOREGROUND_SERVICE;
+ static final int BATTERY_USAGE_COUNT = PROCESS_STATE_COUNT;
+
+ static final Dimensions[] BATT_DIMENS = new Dimensions[] {
+ new Dimensions(AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_POWER_COMPONENTS,
+ PROCESS_STATE_UNSPECIFIED),
+ new Dimensions(AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_POWER_COMPONENTS,
+ PROCESS_STATE_FOREGROUND),
+ new Dimensions(AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_POWER_COMPONENTS,
+ PROCESS_STATE_BACKGROUND),
+ new Dimensions(AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_POWER_COMPONENTS,
+ PROCESS_STATE_FOREGROUND_SERVICE),
+ };
+
+ @NonNull double[] mUsage;
+ @Nullable double[] mPercentage;
+
+ BatteryUsage() {
+ this(0.0d, 0.0d, 0.0d, 0.0d);
+ }
+
+ BatteryUsage(double unspecifiedUsage, double fgUsage, double bgUsage, double fgsUsage) {
+ mUsage = new double[] {unspecifiedUsage, fgUsage, bgUsage, fgsUsage};
+ }
+
+ BatteryUsage(@NonNull double[] usage) {
+ mUsage = usage;
+ }
+
+ BatteryUsage(@NonNull BatteryUsage other, double scale) {
+ this(other);
+ scaleInternal(scale);
+ }
+
+ BatteryUsage(@NonNull BatteryUsage other) {
+ mUsage = new double[other.mUsage.length];
+ setToInternal(other);
+ }
+
+ BatteryUsage(@NonNull UidBatteryConsumer consumer, @NonNull AppBatteryPolicy policy) {
+ final Dimensions[] dims = policy.mBatteryDimensions;
+ mUsage = new double[] {
+ getConsumedPowerNoThrow(consumer, dims[BATTERY_USAGE_INDEX_UNSPECIFIED]),
+ getConsumedPowerNoThrow(consumer, dims[BATTERY_USAGE_INDEX_FOREGROUND]),
+ getConsumedPowerNoThrow(consumer, dims[BATTERY_USAGE_INDEX_BACKGROUND]),
+ getConsumedPowerNoThrow(consumer, dims[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE])
+ };
+ }
+
+ BatteryUsage setTo(@NonNull BatteryUsage other) {
+ return setToInternal(other);
+ }
+
+ private BatteryUsage setToInternal(@NonNull BatteryUsage other) {
+ for (int i = 0; i < other.mUsage.length; i++) {
+ mUsage[i] = other.mUsage[i];
+ }
+ return this;
+ }
+
+ BatteryUsage add(@NonNull BatteryUsage other) {
+ for (int i = 0; i < other.mUsage.length; i++) {
+ mUsage[i] += other.mUsage[i];
+ }
+ return this;
+ }
+
+ BatteryUsage subtract(@NonNull BatteryUsage other) {
+ for (int i = 0; i < other.mUsage.length; i++) {
+ mUsage[i] = Math.max(0.0d, mUsage[i] - other.mUsage[i]);
+ }
+ return this;
+ }
+
+ BatteryUsage scale(double scale) {
+ return scaleInternal(scale);
+ }
+
+ private BatteryUsage scaleInternal(double scale) {
+ for (int i = 0; i < mUsage.length; i++) {
+ mUsage[i] *= scale;
+ }
+ return this;
+ }
+
+ ImmutableBatteryUsage unmutate() {
+ return new ImmutableBatteryUsage(this);
+ }
+
+ BatteryUsage calcPercentage(int uid, @NonNull AppBatteryPolicy policy) {
+ if (mPercentage == null || mPercentage.length != mUsage.length) {
+ mPercentage = new double[mUsage.length];
+ }
+ policy.calcPercentage(uid, mUsage, mPercentage);
+ return this;
+ }
+
+ BatteryUsage setPercentage(@NonNull double[] percentage) {
+ mPercentage = percentage;
+ return this;
+ }
+
+ double[] getPercentage() {
+ return mPercentage;
+ }
+
+ String percentageToString() {
+ return formatBatteryUsagePercentage(mPercentage);
+ }
+
+ @Override
+ public String toString() {
+ return formatBatteryUsage(mUsage);
+ }
+
+ boolean isValid() {
+ for (int i = 0; i < mUsage.length; i++) {
+ if (mUsage[i] < 0.0d) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ boolean isEmpty() {
+ for (int i = 0; i < mUsage.length; i++) {
+ if (mUsage[i] > 0.0d) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == null) {
+ return false;
+ }
+ final BatteryUsage otherUsage = (BatteryUsage) other;
+ for (int i = 0; i < mUsage.length; i++) {
+ if (Double.compare(mUsage[i], otherUsage.mUsage[i]) != 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int hashCode = 0;
+ for (int i = 0; i < mUsage.length; i++) {
+ hashCode = Double.hashCode(mUsage[i]) + hashCode * 31;
+ }
+ return hashCode;
+ }
+
+ private static String formatBatteryUsage(double[] usage) {
+ return String.format("%.3f %.3f %.3f %.3f mAh",
+ usage[BATTERY_USAGE_INDEX_UNSPECIFIED],
+ usage[BATTERY_USAGE_INDEX_FOREGROUND],
+ usage[BATTERY_USAGE_INDEX_BACKGROUND],
+ usage[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE]);
+ }
+
+ static String formatBatteryUsagePercentage(double[] percentage) {
+ return String.format("%4.2f%% %4.2f%% %4.2f%% %4.2f%%",
+ percentage[BATTERY_USAGE_INDEX_UNSPECIFIED],
+ percentage[BATTERY_USAGE_INDEX_FOREGROUND],
+ percentage[BATTERY_USAGE_INDEX_BACKGROUND],
+ percentage[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE]);
+ }
+
+ private static double getConsumedPowerNoThrow(final UidBatteryConsumer uidConsumer,
+ final Dimensions dimens) {
+ try {
+ return uidConsumer.getConsumedPower(dimens);
+ } catch (IllegalArgumentException e) {
+ return 0.0d;
+ }
+ }
+ }
+
+ static final class ImmutableBatteryUsage extends BatteryUsage {
+ ImmutableBatteryUsage() {
+ super();
+ }
+
+ ImmutableBatteryUsage(double unspecifiedUsage, double fgUsage, double bgUsage,
+ double fgsUsage) {
+ super(unspecifiedUsage, fgUsage, bgUsage, fgsUsage);
+ }
+
+ ImmutableBatteryUsage(@NonNull double[] usage) {
+ super(usage);
+ }
+
+ ImmutableBatteryUsage(@NonNull BatteryUsage other, double scale) {
+ super(other, scale);
+ }
+
+ ImmutableBatteryUsage(@NonNull BatteryUsage other) {
+ super(other);
+ }
+
+ ImmutableBatteryUsage(@NonNull UidBatteryConsumer consumer,
+ @NonNull AppBatteryPolicy policy) {
+ super(consumer, policy);
+ }
+
+ @Override
+ BatteryUsage setTo(@NonNull BatteryUsage other) {
+ throw new RuntimeException("Readonly");
+ }
+
+ @Override
+ BatteryUsage add(@NonNull BatteryUsage other) {
+ throw new RuntimeException("Readonly");
+ }
+
+ @Override
+ BatteryUsage subtract(@NonNull BatteryUsage other) {
+ throw new RuntimeException("Readonly");
+ }
+
+ @Override
+ BatteryUsage scale(double scale) {
+ throw new RuntimeException("Readonly");
+ }
+
+ @Override
+ BatteryUsage setPercentage(@NonNull double[] percentage) {
+ throw new RuntimeException("Readonly");
+ }
+
+ BatteryUsage mutate() {
+ return new BatteryUsage(this);
+ }
+ }
+
static final class AppBatteryPolicy extends BaseAppStatePolicy<AppBatteryTracker> {
/**
+ * The type of battery usage we could choose to apply the policy on.
+ *
+ * Must be in sync with android.os.BatteryConsumer.PROCESS_STATE_*.
+ */
+ static final int BATTERY_USAGE_TYPE_UNSPECIFIED = 1;
+ static final int BATTERY_USAGE_TYPE_FOREGROUND = 1 << 1;
+ static final int BATTERY_USAGE_TYPE_BACKGROUND = 1 << 2;
+ static final int BATTERY_USAGE_TYPE_FOREGROUND_SERVICE = 1 << 3;
+
+ /**
* Whether or not we should enable the monitoring on background current drains.
*/
static final String KEY_BG_CURRENT_DRAIN_MONITOR_ENABLED =
@@ -729,58 +1005,115 @@
+ "current_drain_event_duration_based_threshold_enabled";
/**
- * Default value to {@link #mTrackerEnabled}.
+ * The types of battery drain we're checking on each app; if the sum of the battery drain
+ * exceeds the threshold, it'll be moved to restricted standby bucket; the type here
+ * must be one of, or combination of {@link #BATTERY_USAGE_TYPE_BACKGROUND} and
+ * {@link #BATTERY_USAGE_TYPE_FOREGROUND_SERVICE}.
*/
- static final boolean DEFAULT_BG_CURRENT_DRAIN_MONITOR_ENABLED = true;
+ static final String KEY_BG_CURRENT_DRAIN_TYPES_TO_RESTRICTED_BUCKET =
+ DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_types_to_restricted_bucket";
+
+ /**
+ * The types of battery drain we're checking on each app; if the sum of the battery drain
+ * exceeds the threshold, it'll be moved to background restricted level; the type here
+ * must be one of, or combination of {@link #BATTERY_USAGE_TYPE_BACKGROUND} and
+ * {@link #BATTERY_USAGE_TYPE_FOREGROUND_SERVICE}.
+ */
+ static final String KEY_BG_CURRENT_DRAIN_TYPES_TO_BG_RESTRICTED =
+ DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_types_to_bg_restricted";
+
+ /**
+ * The power usage components we're monitoring.
+ */
+ static final String KEY_BG_CURRENT_DRAIN_POWER_COMPONENTS =
+ DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_power_components";
+
+ /**
+ * The types of state where we'll exempt its battery usage when it's in that state.
+ * The state here must be one or a combination of STATE_TYPE_* in BaseAppStateTracker.
+ */
+ static final String KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES =
+ DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_exempted_types";
+
+ /**
+ * The behavior when an app has the permission ACCESS_BACKGROUND_LOCATION granted,
+ * whether or not the system will use a higher threshold towards its background battery
+ * usage because of it.
+ */
+ static final String KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_BY_BG_LOCATION =
+ DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_high_threshold_by_bg_location";
/**
* Default value to the {@link #INDEX_REGULAR_CURRENT_DRAIN_THRESHOLD} of
* the {@link #mBgCurrentDrainRestrictedBucketThreshold}.
*/
- static final float DEFAULT_BG_CURRENT_DRAIN_RESTRICTED_BUCKET_THRESHOLD =
- isLowRamDeviceStatic() ? 4.0f : 2.0f;
+ final float mDefaultBgCurrentDrainRestrictedBucket;
/**
* Default value to the {@link #INDEX_REGULAR_CURRENT_DRAIN_THRESHOLD} of
* the {@link #mBgCurrentDrainBgRestrictedThreshold}.
*/
- static final float DEFAULT_BG_CURRENT_DRAIN_BG_RESTRICTED_THRESHOLD =
- isLowRamDeviceStatic() ? 8.0f : 4.0f;
+ final float mDefaultBgCurrentDrainBgRestrictedThreshold;
/**
* Default value to {@link #mBgCurrentDrainWindowMs}.
*/
- static final long DEFAULT_BG_CURRENT_DRAIN_WINDOW_MS = ONE_DAY;
+ final long mDefaultBgCurrentDrainWindowMs;
/**
* Default value to the {@link #INDEX_HIGH_CURRENT_DRAIN_THRESHOLD} of
* the {@link #mBgCurrentDrainRestrictedBucketThreshold}.
*/
- static final float DEFAULT_BG_CURRENT_DRAIN_RESTRICTED_BUCKET_HIGH_THRESHOLD =
- isLowRamDeviceStatic() ? 60.0f : 30.0f;
+ final float mDefaultBgCurrentDrainRestrictedBucketHighThreshold;
/**
* Default value to the {@link #INDEX_HIGH_CURRENT_DRAIN_THRESHOLD} of
* the {@link #mBgCurrentDrainBgRestrictedThreshold}.
*/
- static final float DEFAULT_BG_CURRENT_DRAIN_BG_RESTRICTED_HIGH_THRESHOLD =
- isLowRamDeviceStatic() ? 60.0f : 30.0f;
+ final float mDefaultBgCurrentDrainBgRestrictedHighThreshold;
/**
* Default value to {@link #mBgCurrentDrainMediaPlaybackMinDuration}.
*/
- static final long DEFAULT_BG_CURRENT_DRAIN_MEDIA_PLAYBACK_MIN_DURATION = 30 * ONE_MINUTE;
+ final long mDefaultBgCurrentDrainMediaPlaybackMinDuration;
/**
* Default value to {@link #mBgCurrentDrainLocationMinDuration}.
*/
- static final long DEFAULT_BG_CURRENT_DRAIN_LOCATION_MIN_DURATION = 30 * ONE_MINUTE;
+ final long mDefaultBgCurrentDrainLocationMinDuration;
/**
* Default value to {@link #mBgCurrentDrainEventDurationBasedThresholdEnabled}.
*/
- static final boolean DEFAULT_BG_CURRENT_DRAIN_EVENT_DURATION_BASED_THRESHOLD_ENABLED =
- false;
+ final boolean mDefaultBgCurrentDrainEventDurationBasedThresholdEnabled;
+
+ /**
+ * Default value to {@link #mBgCurrentDrainRestrictedBucketTypes}.
+ */
+ final int mDefaultCurrentDrainTypesToRestrictedBucket;
+
+ /**
+ * Default value to {@link #mBgCurrentDrainBgRestrictedTypes}.
+ */
+ final int mDefaultBgCurrentDrainTypesToBgRestricted;
+
+ /**
+ * Default value to {@link #mBgCurrentDrainPowerComponents}.
+ **/
+ @BatteryConsumer.PowerComponent
+ static final int DEFAULT_BG_CURRENT_DRAIN_POWER_COMPONENTS = POWER_COMPONENT_ANY;
+
+ final int mDefaultBgCurrentDrainPowerComponent;
+
+ /**
+ * Default value to {@link #mBgCurrentDrainExmptedTypes}.
+ **/
+ final int mDefaultBgCurrentDrainExemptedTypes;
+
+ /**
+ * Default value to {@link #mBgCurrentDrainHighThresholdByBgLocation}.
+ */
+ final boolean mDefaultBgCurrentDrainHighThresholdByBgLocation;
/**
* The index to {@link #mBgCurrentDrainRestrictedBucketThreshold}
@@ -793,36 +1126,28 @@
* @see #KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET.
* @see #KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_RESTRICTED_BUCKET.
*/
- volatile float[] mBgCurrentDrainRestrictedBucketThreshold = {
- DEFAULT_BG_CURRENT_DRAIN_RESTRICTED_BUCKET_THRESHOLD,
- DEFAULT_BG_CURRENT_DRAIN_BG_RESTRICTED_HIGH_THRESHOLD,
- };
+ volatile float[] mBgCurrentDrainRestrictedBucketThreshold = new float[2];
/**
* @see #KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_BG_RESTRICTED.
* @see #KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_BG_RESTRICTED.
*/
- volatile float[] mBgCurrentDrainBgRestrictedThreshold = {
- DEFAULT_BG_CURRENT_DRAIN_BG_RESTRICTED_THRESHOLD,
- DEFAULT_BG_CURRENT_DRAIN_BG_RESTRICTED_HIGH_THRESHOLD,
- };
+ volatile float[] mBgCurrentDrainBgRestrictedThreshold = new float[2];
/**
* @see #KEY_BG_CURRENT_DRAIN_WINDOW.
*/
- volatile long mBgCurrentDrainWindowMs = DEFAULT_BG_CURRENT_DRAIN_WINDOW_MS;
+ volatile long mBgCurrentDrainWindowMs;
/**
* @see #KEY_BG_CURRENT_DRAIN_MEDIA_PLAYBACK_MIN_DURATION.
*/
- volatile long mBgCurrentDrainMediaPlaybackMinDuration =
- DEFAULT_BG_CURRENT_DRAIN_MEDIA_PLAYBACK_MIN_DURATION;
+ volatile long mBgCurrentDrainMediaPlaybackMinDuration;
/**
* @see #KEY_BG_CURRENT_DRAIN_LOCATION_MIN_DURATION.
*/
- volatile long mBgCurrentDrainLocationMinDuration =
- DEFAULT_BG_CURRENT_DRAIN_LOCATION_MIN_DURATION;
+ volatile long mBgCurrentDrainLocationMinDuration;
/**
* @see #KEY_BG_CURRENT_DRAIN_EVENT_DURATION_BASED_THRESHOLD_ENABLED.
@@ -830,6 +1155,34 @@
volatile boolean mBgCurrentDrainEventDurationBasedThresholdEnabled;
/**
+ * @see #KEY_BG_CURRENT_DRAIN_TYPES_TO_RESTRICTED_BUCKET.
+ */
+ volatile int mBgCurrentDrainRestrictedBucketTypes;
+
+ /**
+ * @see #KEY_BG_CURRENT_DRAIN_TYPES_TO_BG_RESTRICTED.
+ */
+ volatile int mBgCurrentDrainBgRestrictedTypes;
+
+ /**
+ * @see #KEY_BG_CURRENT_DRAIN_POWER_COMPONENTS.
+ */
+ @BatteryConsumer.PowerComponent
+ volatile int mBgCurrentDrainPowerComponents;
+
+ volatile Dimensions[] mBatteryDimensions;
+
+ /**
+ * @see #KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES.
+ */
+ volatile int mBgCurrentDrainExemptedTypes;
+
+ /**
+ * @see #KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_BY_BG_LOCATION.
+ */
+ volatile boolean mBgCurrentDrainHighThresholdByBgLocation;
+
+ /**
* The capacity of the battery when fully charged in mAh.
*/
private int mBatteryFullChargeMah;
@@ -851,8 +1204,66 @@
AppBatteryPolicy(@NonNull Injector injector, @NonNull AppBatteryTracker tracker) {
super(injector, tracker, KEY_BG_CURRENT_DRAIN_MONITOR_ENABLED,
- DEFAULT_BG_CURRENT_DRAIN_MONITOR_ENABLED);
+ tracker.mContext.getResources()
+ .getBoolean(R.bool.config_bg_current_drain_monitor_enabled));
mLock = tracker.mLock;
+ final Resources resources = tracker.mContext.getResources();
+ float[] val = getFloatArray(resources.obtainTypedArray(
+ R.array.config_bg_current_drain_threshold_to_restricted_bucket));
+ mDefaultBgCurrentDrainRestrictedBucket =
+ isLowRamDeviceStatic() ? val[1] : val[0];
+ val = getFloatArray(resources.obtainTypedArray(
+ R.array.config_bg_current_drain_threshold_to_bg_restricted));
+ mDefaultBgCurrentDrainBgRestrictedThreshold =
+ isLowRamDeviceStatic() ? val[1] : val[0];
+ mDefaultBgCurrentDrainWindowMs = resources.getInteger(
+ R.integer.config_bg_current_drain_window);
+ val = getFloatArray(resources.obtainTypedArray(
+ R.array.config_bg_current_drain_high_threshold_to_restricted_bucket));
+ mDefaultBgCurrentDrainRestrictedBucketHighThreshold =
+ isLowRamDeviceStatic() ? val[1] : val[0];
+ val = getFloatArray(resources.obtainTypedArray(
+ R.array.config_bg_current_drain_high_threshold_to_bg_restricted));
+ mDefaultBgCurrentDrainBgRestrictedHighThreshold =
+ isLowRamDeviceStatic() ? val[1] : val[0];
+ mDefaultBgCurrentDrainMediaPlaybackMinDuration = resources.getInteger(
+ R.integer.config_bg_current_drain_media_playback_min_duration);
+ mDefaultBgCurrentDrainLocationMinDuration = resources.getInteger(
+ R.integer.config_bg_current_drain_location_min_duration);
+ mDefaultBgCurrentDrainEventDurationBasedThresholdEnabled = resources.getBoolean(
+ R.bool.config_bg_current_drain_event_duration_based_threshold_enabled);
+ mDefaultCurrentDrainTypesToRestrictedBucket = resources.getInteger(
+ R.integer.config_bg_current_drain_types_to_restricted_bucket);
+ mDefaultBgCurrentDrainTypesToBgRestricted = resources.getInteger(
+ R.integer.config_bg_current_drain_types_to_bg_restricted);
+ mDefaultBgCurrentDrainPowerComponent = resources.getInteger(
+ R.integer.config_bg_current_drain_power_components);
+ mDefaultBgCurrentDrainExemptedTypes = resources.getInteger(
+ R.integer.config_bg_current_drain_exempted_types);
+ mDefaultBgCurrentDrainHighThresholdByBgLocation = resources.getBoolean(
+ R.bool.config_bg_current_drain_high_threshold_by_bg_location);
+ mBgCurrentDrainRestrictedBucketThreshold[0] =
+ mDefaultBgCurrentDrainRestrictedBucket;
+ mBgCurrentDrainRestrictedBucketThreshold[1] =
+ mDefaultBgCurrentDrainRestrictedBucketHighThreshold;
+ mBgCurrentDrainBgRestrictedThreshold[0] =
+ mDefaultBgCurrentDrainBgRestrictedThreshold;
+ mBgCurrentDrainBgRestrictedThreshold[1] =
+ mDefaultBgCurrentDrainBgRestrictedHighThreshold;
+ mBgCurrentDrainWindowMs = mDefaultBgCurrentDrainWindowMs;
+ mBgCurrentDrainMediaPlaybackMinDuration =
+ mDefaultBgCurrentDrainMediaPlaybackMinDuration;
+ mBgCurrentDrainLocationMinDuration = mDefaultBgCurrentDrainLocationMinDuration;
+ }
+
+ static float[] getFloatArray(TypedArray array) {
+ int length = array.length();
+ float[] floatArray = new float[length];
+ for (int i = 0; i < length; i++) {
+ floatArray[i] = array.getFloat(i, Float.NaN);
+ }
+ array.recycle();
+ return floatArray;
}
@Override
@@ -860,8 +1271,12 @@
switch (name) {
case KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET:
case KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_BG_RESTRICTED:
+ case KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_BY_BG_LOCATION:
case KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_RESTRICTED_BUCKET:
case KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_BG_RESTRICTED:
+ case KEY_BG_CURRENT_DRAIN_TYPES_TO_RESTRICTED_BUCKET:
+ case KEY_BG_CURRENT_DRAIN_TYPES_TO_BG_RESTRICTED:
+ case KEY_BG_CURRENT_DRAIN_POWER_COMPONENTS:
updateCurrentDrainThreshold();
break;
case KEY_BG_CURRENT_DRAIN_WINDOW:
@@ -876,6 +1291,9 @@
case KEY_BG_CURRENT_DRAIN_EVENT_DURATION_BASED_THRESHOLD_ENABLED:
updateCurrentDrainEventDurationBasedThresholdEnabled();
break;
+ case KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES:
+ updateCurrentDrainExemptedTypes();
+ break;
default:
super.onPropertiesChanged(name);
break;
@@ -899,48 +1317,78 @@
mBgCurrentDrainRestrictedBucketThreshold[INDEX_REGULAR_CURRENT_DRAIN_THRESHOLD] =
DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET,
- DEFAULT_BG_CURRENT_DRAIN_RESTRICTED_BUCKET_THRESHOLD);
+ mDefaultBgCurrentDrainRestrictedBucket);
mBgCurrentDrainRestrictedBucketThreshold[INDEX_HIGH_CURRENT_DRAIN_THRESHOLD] =
DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_RESTRICTED_BUCKET,
- DEFAULT_BG_CURRENT_DRAIN_RESTRICTED_BUCKET_HIGH_THRESHOLD);
+ mDefaultBgCurrentDrainRestrictedBucketHighThreshold);
mBgCurrentDrainBgRestrictedThreshold[INDEX_REGULAR_CURRENT_DRAIN_THRESHOLD] =
DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_BG_RESTRICTED,
- DEFAULT_BG_CURRENT_DRAIN_BG_RESTRICTED_THRESHOLD);
+ mDefaultBgCurrentDrainBgRestrictedThreshold);
mBgCurrentDrainBgRestrictedThreshold[INDEX_HIGH_CURRENT_DRAIN_THRESHOLD] =
DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_BG_RESTRICTED,
- DEFAULT_BG_CURRENT_DRAIN_BG_RESTRICTED_HIGH_THRESHOLD);
+ mDefaultBgCurrentDrainBgRestrictedHighThreshold);
+ mBgCurrentDrainRestrictedBucketTypes =
+ DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_BG_CURRENT_DRAIN_TYPES_TO_RESTRICTED_BUCKET,
+ mDefaultCurrentDrainTypesToRestrictedBucket);
+ mBgCurrentDrainBgRestrictedTypes =
+ DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_BG_CURRENT_DRAIN_TYPES_TO_BG_RESTRICTED,
+ mDefaultBgCurrentDrainTypesToBgRestricted);
+ mBgCurrentDrainPowerComponents =
+ DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_BG_CURRENT_DRAIN_POWER_COMPONENTS,
+ mDefaultBgCurrentDrainPowerComponent);
+ if (mBgCurrentDrainPowerComponents == DEFAULT_BG_CURRENT_DRAIN_POWER_COMPONENTS) {
+ mBatteryDimensions = BatteryUsage.BATT_DIMENS;
+ } else {
+ mBatteryDimensions = new Dimensions[BatteryUsage.BATTERY_USAGE_COUNT];
+ for (int i = 0; i < BatteryUsage.BATTERY_USAGE_COUNT; i++) {
+ mBatteryDimensions[i] = new Dimensions(mBgCurrentDrainPowerComponents, i);
+ }
+ }
+ mBgCurrentDrainHighThresholdByBgLocation =
+ DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_BY_BG_LOCATION,
+ mDefaultBgCurrentDrainHighThresholdByBgLocation);
}
private void updateCurrentDrainWindow() {
mBgCurrentDrainWindowMs = DeviceConfig.getLong(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
KEY_BG_CURRENT_DRAIN_WINDOW,
- mBgCurrentDrainWindowMs != DEFAULT_BG_CURRENT_DRAIN_WINDOW_MS
- ? mBgCurrentDrainWindowMs : DEFAULT_BG_CURRENT_DRAIN_WINDOW_MS);
+ mDefaultBgCurrentDrainWindowMs);
}
private void updateCurrentDrainMediaPlaybackMinDuration() {
mBgCurrentDrainMediaPlaybackMinDuration = DeviceConfig.getLong(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
KEY_BG_CURRENT_DRAIN_MEDIA_PLAYBACK_MIN_DURATION,
- DEFAULT_BG_CURRENT_DRAIN_MEDIA_PLAYBACK_MIN_DURATION);
+ mDefaultBgCurrentDrainMediaPlaybackMinDuration);
}
private void updateCurrentDrainLocationMinDuration() {
mBgCurrentDrainLocationMinDuration = DeviceConfig.getLong(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
KEY_BG_CURRENT_DRAIN_LOCATION_MIN_DURATION,
- DEFAULT_BG_CURRENT_DRAIN_LOCATION_MIN_DURATION);
+ mDefaultBgCurrentDrainLocationMinDuration);
}
private void updateCurrentDrainEventDurationBasedThresholdEnabled() {
mBgCurrentDrainEventDurationBasedThresholdEnabled = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
KEY_BG_CURRENT_DRAIN_EVENT_DURATION_BASED_THRESHOLD_ENABLED,
- DEFAULT_BG_CURRENT_DRAIN_EVENT_DURATION_BASED_THRESHOLD_ENABLED);
+ mDefaultBgCurrentDrainEventDurationBasedThresholdEnabled);
+ }
+
+ private void updateCurrentDrainExemptedTypes() {
+ mBgCurrentDrainExemptedTypes = DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES,
+ mDefaultBgCurrentDrainExemptedTypes);
}
@Override
@@ -953,6 +1401,7 @@
updateCurrentDrainMediaPlaybackMinDuration();
updateCurrentDrainLocationMinDuration();
updateCurrentDrainEventDurationBasedThresholdEnabled();
+ updateCurrentDrainExemptedTypes();
}
@Override
@@ -970,18 +1419,58 @@
}
}
- double getBgUsage(final UidBatteryConsumer uidConsumer) {
- return getConsumedPowerNoThrow(uidConsumer, BATT_DIMEN_BG)
- + getConsumedPowerNoThrow(uidConsumer, BATT_DIMEN_FGS);
+ double[] calcPercentage(final int uid, final double[] usage, double[] percentage) {
+ final BatteryUsage debugUsage = uid > 0 ? mTracker.mDebugUidPercentages.get(uid) : null;
+ final double[] forced = debugUsage != null ? debugUsage.getPercentage() : null;
+ for (int i = 0; i < usage.length; i++) {
+ percentage[i] = forced != null ? forced[i] : usage[i] / mBatteryFullChargeMah * 100;
+ }
+ return percentage;
}
- double getPercentage(final int uid, final double usage) {
- final double actualPercentage = usage / mBatteryFullChargeMah * 100;
- return DEBUG_BACKGROUND_BATTERY_TRACKER
- ? mTracker.mDebugUidPercentages.get(uid, actualPercentage) : actualPercentage;
+ private double sumPercentageOfTypes(double[] percentage, int types) {
+ double result = 0.0d;
+ for (int type = Integer.highestOneBit(types); type != 0;
+ type = Integer.highestOneBit(types)) {
+ final int index = Integer.numberOfTrailingZeros(type);
+ result += percentage[index];
+ types &= ~type;
+ }
+ return result;
}
- void handleUidBatteryUsage(final int uid, final double percentage) {
+ private static String batteryUsageTypesToString(int types) {
+ final StringBuilder sb = new StringBuilder("[");
+ boolean needDelimiter = false;
+ for (int type = Integer.highestOneBit(types); type != 0;
+ type = Integer.highestOneBit(types)) {
+ if (needDelimiter) {
+ sb.append('|');
+ }
+ needDelimiter = true;
+ switch (type) {
+ case BATTERY_USAGE_TYPE_UNSPECIFIED:
+ sb.append("UNSPECIFIED");
+ break;
+ case BATTERY_USAGE_TYPE_FOREGROUND:
+ sb.append("FOREGROUND");
+ break;
+ case BATTERY_USAGE_TYPE_BACKGROUND:
+ sb.append("BACKGROUND");
+ break;
+ case BATTERY_USAGE_TYPE_FOREGROUND_SERVICE:
+ sb.append("FOREGROUND_SERVICE");
+ break;
+ default:
+ return "[UNKNOWN(" + Integer.toHexString(types) + ")]";
+ }
+ types &= ~type;
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
+ void handleUidBatteryUsage(final int uid, final BatteryUsage usage) {
final @ReasonCode int reason = shouldExemptUid(uid);
if (reason != REASON_DENIED) {
if (DEBUG_BACKGROUND_BATTERY_TRACKER) {
@@ -992,6 +1481,10 @@
}
boolean notifyController = false;
boolean excessive = false;
+ final double rbPercentage = sumPercentageOfTypes(usage.getPercentage(),
+ mBgCurrentDrainRestrictedBucketTypes);
+ final double brPercentage = sumPercentageOfTypes(usage.getPercentage(),
+ mBgCurrentDrainBgRestrictedTypes);
synchronized (mLock) {
final int curLevel = mTracker.mAppRestrictionController.getRestrictionLevel(uid);
if (curLevel >= RESTRICTION_LEVEL_BACKGROUND_RESTRICTED) {
@@ -1003,7 +1496,7 @@
mBgCurrentDrainWindowMs);
final int index = mHighBgBatteryPackages.indexOfKey(uid);
if (index < 0) {
- if (percentage >= mBgCurrentDrainRestrictedBucketThreshold[thresholdIndex]) {
+ if (rbPercentage >= mBgCurrentDrainRestrictedBucketThreshold[thresholdIndex]) {
// New findings to us, track it and let the controller know.
final long[] ts = new long[TIME_STAMP_INDEX_LAST];
ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = now;
@@ -1012,22 +1505,24 @@
}
} else {
final long[] ts = mHighBgBatteryPackages.valueAt(index);
- if (percentage < mBgCurrentDrainRestrictedBucketThreshold[thresholdIndex]) {
+ if (rbPercentage < mBgCurrentDrainRestrictedBucketThreshold[thresholdIndex]) {
// it's actually back to normal, but we don't untrack it until
// explicit user interactions.
notifyController = true;
} else {
excessive = true;
- if (percentage >= mBgCurrentDrainBgRestrictedThreshold[thresholdIndex]) {
+ if (brPercentage >= mBgCurrentDrainBgRestrictedThreshold[thresholdIndex]
+ && curLevel == RESTRICTION_LEVEL_RESTRICTED_BUCKET) {
// If we're in the restricted standby bucket but still seeing high
// current drains, tell the controller again.
- if (curLevel == RESTRICTION_LEVEL_RESTRICTED_BUCKET
- && ts[TIME_STAMP_INDEX_BG_RESTRICTED] == 0) {
- if (now > ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET]
- + mBgCurrentDrainWindowMs) {
- ts[TIME_STAMP_INDEX_BG_RESTRICTED] = now;
- notifyController = true;
- }
+ final long lastResbucket = ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET];
+ final long lastBgRes = ts[TIME_STAMP_INDEX_BG_RESTRICTED];
+ // If it has been a while since restricting the app and since the last
+ // time we notify the controller, notify it again.
+ if ((now >= lastResbucket + mBgCurrentDrainWindowMs) && (lastBgRes == 0
+ || (now >= lastBgRes + mBgCurrentDrainWindowMs))) {
+ ts[TIME_STAMP_INDEX_BG_RESTRICTED] = now;
+ notifyController = true;
}
}
}
@@ -1037,7 +1532,7 @@
if (excessive) {
if (DEBUG_BACKGROUND_BATTERY_TRACKER) {
Slog.i(TAG, "Excessive background current drain " + uid
- + String.format(" %.2f%%", percentage) + " over "
+ + usage + " (" + usage.percentageToString() + " ) over "
+ TimeUtils.formatDuration(mBgCurrentDrainWindowMs));
}
if (notifyController) {
@@ -1048,7 +1543,7 @@
} else {
if (DEBUG_BACKGROUND_BATTERY_TRACKER) {
Slog.i(TAG, "Background current drain backs to normal " + uid
- + String.format(" %.2f%%", percentage) + " over "
+ + usage + " (" + usage.percentageToString() + " ) over "
+ TimeUtils.formatDuration(mBgCurrentDrainWindowMs));
}
// For now, we're not lifting the restrictions if the bg current drain backs to
@@ -1069,6 +1564,9 @@
}
private boolean hasLocation(int uid, long now, long window) {
+ if (!mBgCurrentDrainHighThresholdByBgLocation) {
+ return false;
+ }
final AppRestrictionController controller = mTracker.mAppRestrictionController;
if (mInjector.getPermissionManagerServiceInternal().checkUidPermission(
uid, ACCESS_BACKGROUND_LOCATION) == PERMISSION_GRANTED) {
@@ -1120,15 +1618,6 @@
}
}
- private double getConsumedPowerNoThrow(final UidBatteryConsumer uidConsumer,
- final BatteryConsumer.Dimensions dimens) {
- try {
- return uidConsumer.getConsumedPower(dimens);
- } catch (IllegalArgumentException e) {
- return 0.0d;
- }
- }
-
@VisibleForTesting
void reset() {
mHighBgBatteryPackages.clear();
@@ -1179,6 +1668,26 @@
pw.print(KEY_BG_CURRENT_DRAIN_EVENT_DURATION_BASED_THRESHOLD_ENABLED);
pw.print('=');
pw.println(mBgCurrentDrainEventDurationBasedThresholdEnabled);
+ pw.print(prefix);
+ pw.print(KEY_BG_CURRENT_DRAIN_TYPES_TO_RESTRICTED_BUCKET);
+ pw.print('=');
+ pw.println(batteryUsageTypesToString(mBgCurrentDrainRestrictedBucketTypes));
+ pw.print(prefix);
+ pw.print(KEY_BG_CURRENT_DRAIN_TYPES_TO_BG_RESTRICTED);
+ pw.print('=');
+ pw.println(batteryUsageTypesToString(mBgCurrentDrainBgRestrictedTypes));
+ pw.print(prefix);
+ pw.print(KEY_BG_CURRENT_DRAIN_POWER_COMPONENTS);
+ pw.print('=');
+ pw.println(mBgCurrentDrainPowerComponents);
+ pw.print(prefix);
+ pw.print(KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES);
+ pw.print('=');
+ pw.println(BaseAppStateTracker.stateTypesToString(mBgCurrentDrainExemptedTypes));
+ pw.print(prefix);
+ pw.print(KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_BY_BG_LOCATION);
+ pw.print('=');
+ pw.println(mBgCurrentDrainHighThresholdByBgLocation);
pw.print(prefix);
pw.println("Excessive current drain detected:");
diff --git a/services/core/java/com/android/server/am/AppFGSTracker.java b/services/core/java/com/android/server/am/AppFGSTracker.java
index 9c775b3..5ac5a70 100644
--- a/services/core/java/com/android/server/am/AppFGSTracker.java
+++ b/services/core/java/com/android/server/am/AppFGSTracker.java
@@ -16,8 +16,6 @@
package com.android.server.am;
-import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE;
@@ -43,6 +41,7 @@
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -54,6 +53,7 @@
import com.android.server.am.BaseAppStateEventsTracker.BaseAppStateEventsPolicy;
import com.android.server.am.BaseAppStateTimeEvents.BaseTimeEvent;
import com.android.server.am.BaseAppStateTracker.Injector;
+import com.android.server.notification.NotificationManagerInternal;
import java.io.PrintWriter;
import java.lang.reflect.Constructor;
@@ -71,6 +71,9 @@
private final MyHandler mHandler;
+ @GuardedBy("mLock")
+ private final UidProcessMap<ArraySet<Integer>> mFGSNotificationIDs = new UidProcessMap<>();
+
// Unlocked since it's only accessed in single thread.
private final ArrayMap<PackageDurations, Long> mTmpPkgDurations = new ArrayMap<>();
@@ -100,11 +103,19 @@
: MyHandler.MSG_FOREGROUND_SERVICES_STOPPED, pid, uid, packageName).sendToTarget();
}
+ @Override
+ public void onForegroundServiceNotificationUpdated(String packageName, int uid,
+ int foregroundId) {
+ mHandler.obtainMessage(MyHandler.MSG_FOREGROUND_SERVICES_NOTIFICATION_UPDATED,
+ uid, foregroundId, packageName).sendToTarget();
+ }
+
private static class MyHandler extends Handler {
static final int MSG_FOREGROUND_SERVICES_STARTED = 0;
static final int MSG_FOREGROUND_SERVICES_STOPPED = 1;
static final int MSG_FOREGROUND_SERVICES_CHANGED = 2;
- static final int MSG_CHECK_LONG_RUNNING_FGS = 3;
+ static final int MSG_FOREGROUND_SERVICES_NOTIFICATION_UPDATED = 3;
+ static final int MSG_CHECK_LONG_RUNNING_FGS = 4;
private final AppFGSTracker mTracker;
@@ -128,6 +139,10 @@
mTracker.handleForegroundServicesChanged(
(String) msg.obj, msg.arg1, msg.arg2);
break;
+ case MSG_FOREGROUND_SERVICES_NOTIFICATION_UPDATED:
+ mTracker.handleForegroundServiceNotificationUpdated(
+ (String) msg.obj, msg.arg1, msg.arg2);
+ break;
case MSG_CHECK_LONG_RUNNING_FGS:
mTracker.checkLongRunningFgs();
break;
@@ -205,6 +220,44 @@
}
}
+ private void handleForegroundServiceNotificationUpdated(String packageName, int uid,
+ int notificationId) {
+ synchronized (mLock) {
+ if (notificationId > 0) {
+ ArraySet<Integer> notificationIDs = mFGSNotificationIDs.get(uid, packageName);
+ if (notificationIDs == null) {
+ notificationIDs = new ArraySet<>();
+ mFGSNotificationIDs.put(uid, packageName, notificationIDs);
+ }
+ notificationIDs.add(notificationId);
+ } else if (notificationId < 0) {
+ final ArraySet<Integer> notificationIDs = mFGSNotificationIDs.get(uid, packageName);
+ if (notificationIDs != null) {
+ notificationIDs.remove(-notificationId);
+ if (notificationIDs.isEmpty()) {
+ mFGSNotificationIDs.remove(uid, packageName);
+ }
+ }
+ }
+ }
+ }
+
+ @GuardedBy("mLock")
+ private boolean hasForegroundServiceNotificationsLocked(String packageName, int uid) {
+ final ArraySet<Integer> notificationIDs = mFGSNotificationIDs.get(uid, packageName);
+ if (notificationIDs == null || notificationIDs.isEmpty()) {
+ return false;
+ }
+ final NotificationManagerInternal nm = mInjector.getNotificationManagerInternal();
+ final int userId = UserHandle.getUserId(uid);
+ for (int i = notificationIDs.size() - 1; i >= 0; i--) {
+ if (nm.isNotificationShown(packageName, null, notificationIDs.valueAt(i), userId)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@GuardedBy("mLock")
private void scheduleDurationCheckLocked(long now) {
// Look for the active FGS with longest running time till now.
@@ -375,6 +428,28 @@
}
}
+ boolean hasForegroundServiceNotifications(String packageName, int uid) {
+ synchronized (mLock) {
+ return hasForegroundServiceNotificationsLocked(packageName, uid);
+ }
+ }
+
+ boolean hasForegroundServiceNotifications(int uid) {
+ synchronized (mLock) {
+ final SparseArray<ArrayMap<String, ArraySet<Integer>>> map =
+ mFGSNotificationIDs.getMap();
+ final ArrayMap<String, ArraySet<Integer>> pkgs = map.get(uid);
+ if (pkgs != null) {
+ for (int i = pkgs.size() - 1; i >= 0; i--) {
+ if (hasForegroundServiceNotificationsLocked(pkgs.keyAt(i), uid)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
@Override
void dump(PrintWriter pw, String prefix) {
pw.print(prefix);
@@ -382,6 +457,35 @@
super.dump(pw, " " + prefix);
}
+ @Override
+ void dumpOthers(PrintWriter pw, String prefix) {
+ pw.print(prefix);
+ pw.println("APPS WITH ACTIVE FOREGROUND SERVICES:");
+ prefix = " " + prefix;
+ synchronized (mLock) {
+ final SparseArray<ArrayMap<String, ArraySet<Integer>>> map =
+ mFGSNotificationIDs.getMap();
+ if (map.size() == 0) {
+ pw.print(prefix);
+ pw.println("(none)");
+ }
+ for (int i = 0, size = map.size(); i < size; i++) {
+ final int uid = map.keyAt(i);
+ final String uidString = UserHandle.formatUid(uid);
+ final ArrayMap<String, ArraySet<Integer>> pkgs = map.valueAt(i);
+ for (int j = 0, numOfPkgs = pkgs.size(); j < numOfPkgs; j++) {
+ final String pkgName = pkgs.keyAt(j);
+ pw.print(prefix);
+ pw.print(pkgName);
+ pw.print('/');
+ pw.print(uidString);
+ pw.print(" notification=");
+ pw.println(hasForegroundServiceNotificationsLocked(pkgName, uid));
+ }
+ }
+ }
+ }
+
/**
* Tracks the durations with active FGS for a given package.
*/
@@ -437,7 +541,7 @@
}
if (isActive(i)) {
mEvents[i].add(new BaseTimeEvent(now));
- notifyListenersOnEventIfNecessary(false, now,
+ notifyListenersOnStateChangeIfNecessary(false, now,
indexToForegroundServiceType(i));
}
}
@@ -463,13 +567,13 @@
}
if (!isActive(i)) {
mEvents[i].add(new BaseTimeEvent(now));
- notifyListenersOnEventIfNecessary(true, now, serviceType);
+ notifyListenersOnStateChangeIfNecessary(true, now, serviceType);
}
} else {
// Stop this type.
if (mEvents[i] != null && isActive(i)) {
mEvents[i].add(new BaseTimeEvent(now));
- notifyListenersOnEventIfNecessary(false, now, serviceType);
+ notifyListenersOnStateChangeIfNecessary(false, now, serviceType);
}
}
changes &= ~serviceType;
@@ -478,20 +582,20 @@
mForegroundServiceTypes = serviceTypes;
}
- private void notifyListenersOnEventIfNecessary(boolean start, long now,
+ private void notifyListenersOnStateChangeIfNecessary(boolean start, long now,
@ForegroundServiceType int serviceType) {
- int eventType;
+ int stateType;
switch (serviceType) {
case FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK:
- eventType = BaseAppStateDurationsTracker.EVENT_TYPE_FGS_MEDIA_PLAYBACK;
+ stateType = BaseAppStateDurationsTracker.STATE_TYPE_FGS_MEDIA_PLAYBACK;
break;
case FOREGROUND_SERVICE_TYPE_LOCATION:
- eventType = BaseAppStateDurationsTracker.EVENT_TYPE_FGS_LOCATION;
+ stateType = BaseAppStateDurationsTracker.STATE_TYPE_FGS_LOCATION;
break;
default:
return;
}
- mTracker.notifyListenersOnEvent(mUid, mPackageName, start, now, eventType);
+ mTracker.notifyListenersOnStateChange(mUid, mPackageName, start, now, stateType);
}
void setIsLongRunning(boolean isLongRunning) {
@@ -687,10 +791,6 @@
if (shouldExemptLocationFGS(packageName, uid, now, since)) {
return;
}
- if (hasBackgroundLocationPermission(packageName, uid)) {
- // This package has background location permission, ignore it.
- return;
- }
mTracker.mAppRestrictionController.postLongRunningFgsIfNecessary(packageName, uid);
}
@@ -723,19 +823,6 @@
return false;
}
- boolean hasBackgroundLocationPermission(String packageName, int uid) {
- if (mInjector.getPermissionManagerServiceInternal().checkPermission(
- packageName, ACCESS_BACKGROUND_LOCATION, UserHandle.getUserId(uid))
- == PERMISSION_GRANTED) {
- if (DEBUG_BACKGROUND_FGS_TRACKER) {
- Slog.i(TAG, "Ignoring bg-location FGS in " + packageName + "/"
- + UserHandle.formatUid(uid));
- }
- return true;
- }
- return false;
- }
-
@Override
String getExemptionReasonString(String packageName, int uid, @ReasonCode int reason) {
if (reason != REASON_DENIED) {
@@ -745,8 +832,7 @@
final long window = getFgsLongRunningWindowSize();
final long since = Math.max(0, now - getFgsLongRunningWindowSize());
return "{mediaPlayback=" + shouldExemptMediaPlaybackFGS(packageName, uid, now, window)
- + ", location=" + shouldExemptLocationFGS(packageName, uid, now, since)
- + ", bgLocationPerm=" + hasBackgroundLocationPermission(packageName, uid) + "}";
+ + ", location=" + shouldExemptLocationFGS(packageName, uid, now, since) + "}";
}
void onLongRunningFgsGone(String packageName, int uid) {
diff --git a/services/core/java/com/android/server/am/AppMediaSessionTracker.java b/services/core/java/com/android/server/am/AppMediaSessionTracker.java
index 3914f6f..4ce23f7 100644
--- a/services/core/java/com/android/server/am/AppMediaSessionTracker.java
+++ b/services/core/java/com/android/server/am/AppMediaSessionTracker.java
@@ -19,8 +19,8 @@
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.AppRestrictionController.DEVICE_CONFIG_SUBNAMESPACE_PREFIX;
-import static com.android.server.am.BaseAppStateDurationsTracker.EVENT_TYPE_MEDIA_SESSION;
import static com.android.server.am.BaseAppStateTracker.ONE_DAY;
+import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_MEDIA_SESSION;
import android.annotation.NonNull;
import android.content.Context;
@@ -104,8 +104,8 @@
}
if (!pkg.isActive()) {
pkg.addEvent(true, now);
- notifyListenersOnEvent(pkg.mUid, pkg.mPackageName, true, now,
- EVENT_TYPE_MEDIA_SESSION);
+ notifyListenersOnStateChange(pkg.mUid, pkg.mPackageName, true, now,
+ STATE_TYPE_MEDIA_SESSION);
}
// Mark it as active, so we could filter out inactive ones below.
mTmpMediaControllers.put(packageName, uid, Boolean.TRUE);
@@ -127,8 +127,8 @@
&& mTmpMediaControllers.get(pkg.mPackageName, pkg.mUid) == null) {
// This package has removed its controller, issue a stop event.
pkg.addEvent(false, now);
- notifyListenersOnEvent(pkg.mUid, pkg.mPackageName, false, now,
- EVENT_TYPE_MEDIA_SESSION);
+ notifyListenersOnStateChange(pkg.mUid, pkg.mPackageName, false, now,
+ STATE_TYPE_MEDIA_SESSION);
}
}
}
@@ -146,8 +146,8 @@
final SimplePackageDurations pkg = val.valueAt(j);
if (pkg.isActive()) {
pkg.addEvent(false, now);
- notifyListenersOnEvent(pkg.mUid, pkg.mPackageName, false, now,
- EVENT_TYPE_MEDIA_SESSION);
+ notifyListenersOnStateChange(pkg.mUid, pkg.mPackageName, false, now,
+ STATE_TYPE_MEDIA_SESSION);
}
}
}
diff --git a/services/core/java/com/android/server/am/AppPermissionTracker.java b/services/core/java/com/android/server/am/AppPermissionTracker.java
new file mode 100644
index 0000000..7f48d52
--- /dev/null
+++ b/services/core/java/com/android/server/am/AppPermissionTracker.java
@@ -0,0 +1,327 @@
+/*
+ * 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.am;
+
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.Process.SYSTEM_UID;
+
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.AppBatteryExemptionTracker.DEFAULT_NAME;
+import static com.android.server.am.AppRestrictionController.DEVICE_CONFIG_SUBNAMESPACE_PREFIX;
+import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_PERMISSION;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager.OnPermissionsChangedListener;
+import android.content.pm.PackageManagerInternal;
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.permission.PermissionManager;
+import android.provider.DeviceConfig;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.am.AppPermissionTracker.AppPermissionPolicy;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
+
+import java.io.PrintWriter;
+import java.lang.reflect.Constructor;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * The tracker for monitoring selected permission state of apps.
+ */
+final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy>
+ implements OnPermissionsChangedListener {
+ static final String TAG = TAG_WITH_CLASS_NAME ? "AppPermissionTracker" : TAG_AM;
+
+ static final boolean DEBUG_PERMISSION_TRACKER = false;
+
+ private final MyHandler mHandler;
+
+ @GuardedBy("mLock")
+ private SparseArray<ArraySet<String>> mUidGrantedPermissionsInMonitor = new SparseArray<>();
+
+ AppPermissionTracker(Context context, AppRestrictionController controller) {
+ this(context, controller, null, null);
+ }
+
+ AppPermissionTracker(Context context, AppRestrictionController controller,
+ Constructor<? extends Injector<AppPermissionPolicy>> injector, Object outerContext) {
+ super(context, controller, injector, outerContext);
+ mHandler = new MyHandler(this);
+ mInjector.setPolicy(new AppPermissionPolicy(mInjector, this));
+ }
+
+ @Override
+ public void onPermissionsChanged(int uid) {
+ mHandler.obtainMessage(MyHandler.MSG_PERMISSIONS_CHANGED, uid, 0).sendToTarget();
+ }
+
+ private void handlePermissionsInit() {
+ final int[] allUsers = mInjector.getUserManagerInternal().getUserIds();
+ final PackageManagerInternal pmi = mInjector.getPackageManagerInternal();
+ final PermissionManagerServiceInternal pm = mInjector.getPermissionManagerServiceInternal();
+ final String[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
+ for (int userId : allUsers) {
+ final List<ApplicationInfo> apps = pmi.getInstalledApplications(0, userId, SYSTEM_UID);
+ if (apps == null) {
+ continue;
+ }
+ synchronized (mLock) {
+ final SparseArray<ArraySet<String>> uidPerms = mUidGrantedPermissionsInMonitor;
+ final long now = SystemClock.elapsedRealtime();
+ for (int i = 0, size = apps.size(); i < size; i++) {
+ final ApplicationInfo ai = apps.get(i);
+ for (String permission : permissions) {
+ if (pm.checkUidPermission(ai.uid, permission) != PERMISSION_GRANTED) {
+ continue;
+ }
+ ArraySet<String> grantedPermissions = uidPerms.get(ai.uid);
+ if (grantedPermissions == null) {
+ grantedPermissions = new ArraySet<String>();
+ uidPerms.put(ai.uid, grantedPermissions);
+ }
+ grantedPermissions.add(permission);
+ notifyListenersOnStateChange(ai.uid, DEFAULT_NAME, true, now,
+ STATE_TYPE_PERMISSION);
+ }
+ }
+ }
+ }
+ }
+
+ private void handlePermissionsDestroy() {
+ synchronized (mLock) {
+ final SparseArray<ArraySet<String>> uidPerms = mUidGrantedPermissionsInMonitor;
+ final long now = SystemClock.elapsedRealtime();
+ for (int i = 0, size = uidPerms.size(); i < size; i++) {
+ final int uid = uidPerms.keyAt(i);
+ final ArraySet<String> grantedPermissions = uidPerms.valueAt(i);
+ for (int j = 0, numOfPerms = grantedPermissions.size(); j < numOfPerms; j++) {
+ notifyListenersOnStateChange(uid, DEFAULT_NAME, false, now,
+ STATE_TYPE_PERMISSION);
+ }
+ }
+ uidPerms.clear();
+ }
+ }
+
+ private void handlePermissionsChanged(int uid) {
+ final String[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
+ if (permissions != null && permissions.length > 0) {
+ synchronized (mLock) {
+ handlePermissionsChangedLocked(uid);
+ }
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void handlePermissionsChangedLocked(int uid) {
+ final PermissionManagerServiceInternal pm = mInjector.getPermissionManagerServiceInternal();
+ final int index = mUidGrantedPermissionsInMonitor.indexOfKey(uid);
+ ArraySet<String> grantedPermissions = index >= 0
+ ? mUidGrantedPermissionsInMonitor.valueAt(index) : null;
+ final String[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
+ final long now = SystemClock.elapsedRealtime();
+ for (String permission: permissions) {
+ boolean granted = pm.checkUidPermission(uid, permission) == PERMISSION_GRANTED;
+ if (DEBUG_PERMISSION_TRACKER) {
+ Slog.i(TAG, UserHandle.formatUid(uid) + " " + permission + "=" + granted);
+ }
+ boolean changed = false;
+ if (granted) {
+ if (grantedPermissions == null) {
+ grantedPermissions = new ArraySet<>();
+ mUidGrantedPermissionsInMonitor.put(uid, grantedPermissions);
+ }
+ changed = grantedPermissions.add(permission);
+ } else if (grantedPermissions != null) {
+ changed = grantedPermissions.remove(permission);
+ if (grantedPermissions.isEmpty()) {
+ mUidGrantedPermissionsInMonitor.removeAt(index);
+ }
+ }
+ if (changed) {
+ notifyListenersOnStateChange(uid, DEFAULT_NAME, granted, now,
+ STATE_TYPE_PERMISSION);
+ }
+ }
+ }
+
+ private static class MyHandler extends Handler {
+ static final int MSG_PERMISSIONS_INIT = 0;
+ static final int MSG_PERMISSIONS_DESTROY = 1;
+ static final int MSG_PERMISSIONS_CHANGED = 2;
+
+ private @NonNull AppPermissionTracker mTracker;
+
+ MyHandler(@NonNull AppPermissionTracker tracker) {
+ super(tracker.mBgHandler.getLooper());
+ mTracker = tracker;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_PERMISSIONS_INIT:
+ mTracker.handlePermissionsInit();
+ break;
+ case MSG_PERMISSIONS_DESTROY:
+ mTracker.handlePermissionsDestroy();
+ break;
+ case MSG_PERMISSIONS_CHANGED:
+ mTracker.handlePermissionsChanged(msg.arg1);
+ break;
+ }
+ }
+ }
+
+ private void onPermissionTrackerEnabled(boolean enabled) {
+ final PermissionManager pm = mInjector.getPermissionManager();
+ if (enabled) {
+ pm.addOnPermissionsChangeListener(this);
+ mHandler.obtainMessage(MyHandler.MSG_PERMISSIONS_INIT).sendToTarget();
+ } else {
+ pm.removeOnPermissionsChangeListener(this);
+ mHandler.obtainMessage(MyHandler.MSG_PERMISSIONS_DESTROY).sendToTarget();
+ }
+ }
+
+ @Override
+ void dump(PrintWriter pw, String prefix) {
+ pw.print(prefix);
+ pw.println("APP PERMISSIONS TRACKER:");
+ final String[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
+ final String prefixMore = " " + prefix;
+ final String prefixMoreMore = " " + prefixMore;
+ for (String permission : permissions) {
+ pw.print(prefixMore);
+ pw.print(permission);
+ pw.println(':');
+ synchronized (mLock) {
+ final SparseArray<ArraySet<String>> uidPerms = mUidGrantedPermissionsInMonitor;
+ pw.print(prefixMoreMore);
+ pw.print('[');
+ boolean needDelimiter = false;
+ for (int i = 0, size = uidPerms.size(); i < size; i++) {
+ if (uidPerms.valueAt(i).contains(permission)) {
+ if (needDelimiter) {
+ pw.print(',');
+ }
+ needDelimiter = true;
+ pw.print(UserHandle.formatUid(uidPerms.keyAt(i)));
+ }
+ }
+ pw.println(']');
+ }
+ }
+ super.dump(pw, prefix);
+ }
+
+ static final class AppPermissionPolicy extends BaseAppStatePolicy<AppPermissionTracker> {
+ /**
+ * Whether or not we should enable the monitoring on app permissions.
+ */
+ static final String KEY_BG_PERMISSION_MONITOR_ENABLED =
+ DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "permission_monitor_enabled";
+
+ /**
+ * The names of the permissions we're monitoring its changes.
+ */
+ static final String KEY_BG_PERMISSIONS_IN_MONITOR =
+ DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "permission_in_monitor";
+
+ /**
+ * Default value to {@link #mTrackerEnabled}.
+ */
+ static final boolean DEFAULT_BG_PERMISSION_MONITOR_ENABLED = true;
+
+ /**
+ * Default value to {@link #mBgPermissionsInMonitor}.
+ */
+ static final String[] DEFAULT_BG_PERMISSIONS_IN_MONITOR = new String[] {
+ ACCESS_FINE_LOCATION,
+ };
+
+ /**
+ * @see #KEY_BG_PERMISSIONS_IN_MONITOR.
+ */
+ volatile String[] mBgPermissionsInMonitor = DEFAULT_BG_PERMISSIONS_IN_MONITOR;
+
+ AppPermissionPolicy(@NonNull Injector injector, @NonNull AppPermissionTracker tracker) {
+ super(injector, tracker, KEY_BG_PERMISSION_MONITOR_ENABLED,
+ DEFAULT_BG_PERMISSION_MONITOR_ENABLED);
+ }
+
+ @Override
+ public void onSystemReady() {
+ super.onSystemReady();
+ updateBgPermissionsInMonitor();
+ }
+
+ @Override
+ public void onPropertiesChanged(String name) {
+ switch (name) {
+ case KEY_BG_PERMISSIONS_IN_MONITOR:
+ updateBgPermissionsInMonitor();
+ break;
+ default:
+ super.onPropertiesChanged(name);
+ break;
+ }
+ }
+
+ String[] getBgPermissionsInMonitor() {
+ return mBgPermissionsInMonitor;
+ }
+
+ private void updateBgPermissionsInMonitor() {
+ final String config = DeviceConfig.getString(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_BG_PERMISSIONS_IN_MONITOR,
+ null);
+ mBgPermissionsInMonitor = config != null
+ ? config.split(",") : DEFAULT_BG_PERMISSIONS_IN_MONITOR;
+ }
+
+ @Override
+ public void onTrackerEnabled(boolean enabled) {
+ mTracker.onPermissionTrackerEnabled(enabled);
+ }
+
+ @Override
+ void dump(PrintWriter pw, String prefix) {
+ pw.print(prefix);
+ pw.println("APP PERMISSION TRACKER POLICY SETTINGS:");
+ prefix = " " + prefix;
+ super.dump(pw, prefix);
+ pw.print(prefix);
+ pw.print(KEY_BG_PERMISSIONS_IN_MONITOR);
+ pw.print('=');
+ pw.println(Arrays.toString(mBgPermissionsInMonitor));
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/am/AppRestrictionController.java b/services/core/java/com/android/server/am/AppRestrictionController.java
index 8cff13e..1129c19 100644
--- a/services/core/java/com/android/server/am/AppRestrictionController.java
+++ b/services/core/java/com/android/server/am/AppRestrictionController.java
@@ -69,6 +69,7 @@
import static android.os.PowerExemptionManager.REASON_SYSTEM_ALLOW_LISTED;
import static android.os.PowerExemptionManager.REASON_SYSTEM_MODULE;
import static android.os.PowerExemptionManager.REASON_SYSTEM_UID;
+import static android.os.PowerExemptionManager.reasonCodeToString;
import static android.os.Process.SYSTEM_UID;
import static com.android.internal.notification.SystemNotificationChannels.ABUSIVE_BACKGROUND_APPS;
@@ -142,6 +143,7 @@
import com.android.server.AppStateTracker;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
+import com.android.server.am.AppBatteryTracker.ImmutableBatteryUsage;
import com.android.server.apphibernation.AppHibernationManagerInternal;
import com.android.server.pm.UserManagerInternal;
import com.android.server.usage.AppStandbyInternal;
@@ -156,6 +158,7 @@
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.function.Consumer;
@@ -328,6 +331,8 @@
}
}
}
+ pw.print(" effectiveExemption=");
+ pw.print(reasonCodeToString(getBackgroundRestrictionExemptionReason(mUid)));
}
String getPackageName() {
@@ -546,17 +551,50 @@
static final String KEY_BG_ABUSIVE_NOTIFICATION_MINIMAL_INTERVAL =
DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "abusive_notification_minimal_interval";
+ /**
+ * The behavior for an app with a FGS and its notification is still showing, when the system
+ * detects it's abusive and should be put into bg restricted level. {@code true} - we'll
+ * show the prompt to user, {@code false} - we'll not show it.
+ */
+ static final String KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_TO_BG_RESTRICTED =
+ DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "prompt_fgs_with_noti_to_bg_restricted";
+
+ /**
+ * The list of packages to be exempted from all these background restrictions.
+ */
+ static final String KEY_BG_RESTRICTION_EXEMPTED_PACKAGES =
+ DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "restriction_exempted_packages";
+
static final boolean DEFAULT_BG_AUTO_RESTRICTED_BUCKET_ON_BG_RESTRICTION = false;
static final long DEFAULT_BG_ABUSIVE_NOTIFICATION_MINIMAL_INTERVAL_MS = 24 * 60 * 60 * 1000;
+ /**
+ * Default value to {@link #mBgPromptFgsWithNotiToBgRestricted}.
+ */
+ final boolean mDefaultBgPromptFgsWithNotiToBgRestricted;
+
volatile boolean mBgAutoRestrictedBucket;
volatile boolean mRestrictedBucketEnabled;
volatile long mBgNotificationMinIntervalMs;
- ConstantsObserver(Handler handler) {
+ /**
+ * @see #KEY_BG_RESTRICTION_EXEMPTED_PACKAGES.
+ *
+ *<p> Mutations on them would result in copy-on-write.</p>
+ */
+ volatile Set<String> mBgRestrictionExemptedPackages = Collections.emptySet();
+
+ /**
+ * @see #KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_TO_BG_RESTRICTED.
+ */
+ volatile boolean mBgPromptFgsWithNotiToBgRestricted;
+
+ ConstantsObserver(Handler handler, Context context) {
super(handler);
+ mDefaultBgPromptFgsWithNotiToBgRestricted = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_bg_prompt_fgs_with_noti_to_bg_restricted);
}
@Override
@@ -572,6 +610,12 @@
case KEY_BG_ABUSIVE_NOTIFICATION_MINIMAL_INTERVAL:
updateBgAbusiveNotificationMinimalInterval();
break;
+ case KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_TO_BG_RESTRICTED:
+ updateBgPromptFgsWithNotiToBgRestricted();
+ break;
+ case KEY_BG_RESTRICTION_EXEMPTED_PACKAGES:
+ updateBgRestrictionExemptedPackages();
+ break;
}
AppRestrictionController.this.onPropertiesChanged(name);
}
@@ -603,6 +647,8 @@
void updateDeviceConfig() {
updateBgAutoRestrictedBucketChanged();
updateBgAbusiveNotificationMinimalInterval();
+ updateBgPromptFgsWithNotiToBgRestricted();
+ updateBgRestrictionExemptedPackages();
}
private void updateBgAutoRestrictedBucketChanged() {
@@ -622,6 +668,53 @@
KEY_BG_ABUSIVE_NOTIFICATION_MINIMAL_INTERVAL,
DEFAULT_BG_ABUSIVE_NOTIFICATION_MINIMAL_INTERVAL_MS);
}
+
+ private void updateBgPromptFgsWithNotiToBgRestricted() {
+ mBgPromptFgsWithNotiToBgRestricted = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_TO_BG_RESTRICTED,
+ mDefaultBgPromptFgsWithNotiToBgRestricted);
+ }
+
+ private void updateBgRestrictionExemptedPackages() {
+ final String settings = DeviceConfig.getString(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_BG_RESTRICTION_EXEMPTED_PACKAGES,
+ null);
+ if (settings == null) {
+ mBgRestrictionExemptedPackages = Collections.emptySet();
+ return;
+ }
+ final String[] settingsList = settings.split(",");
+ final ArraySet<String> packages = new ArraySet<>();
+ for (String pkg : settingsList) {
+ packages.add(pkg);
+ }
+ mBgRestrictionExemptedPackages = Collections.unmodifiableSet(packages);
+ }
+
+ void dump(PrintWriter pw, String prefix) {
+ pw.print(prefix);
+ pw.println("BACKGROUND RESTRICTION POLICY SETTINGS:");
+ final String indent = " ";
+ prefix = indent + prefix;
+ pw.print(prefix);
+ pw.print(KEY_BG_AUTO_RESTRICTED_BUCKET_ON_BG_RESTRICTION);
+ pw.print('=');
+ pw.println(mBgAutoRestrictedBucket);
+ pw.print(prefix);
+ pw.print(KEY_BG_ABUSIVE_NOTIFICATION_MINIMAL_INTERVAL);
+ pw.print('=');
+ pw.println(mBgNotificationMinIntervalMs);
+ pw.print(prefix);
+ pw.print(KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_TO_BG_RESTRICTED);
+ pw.print('=');
+ pw.println(mBgPromptFgsWithNotiToBgRestricted);
+ pw.print(prefix);
+ pw.print(KEY_BG_RESTRICTION_EXEMPTED_PACKAGES);
+ pw.print('=');
+ pw.println(mBgRestrictionExemptedPackages.toString());
+ }
}
private final ConstantsObserver mConstantsObserver;
@@ -703,7 +796,7 @@
mBgHandlerThread.start();
mBgHandler = new BgHandler(mBgHandlerThread.getLooper(), injector);
mBgExecutor = new HandlerExecutor(mBgHandler);
- mConstantsObserver = new ConstantsObserver(mBgHandler);
+ mConstantsObserver = new ConstantsObserver(mBgHandler, mContext);
mNotificationHelper = new NotificationHelper(this);
injector.initAppStateTrackers(this);
}
@@ -1073,18 +1166,33 @@
}
/**
+ * @return If the given package/uid has a foreground service notification or not.
+ */
+ boolean hasForegroundServiceNotifications(String packageName, int uid) {
+ return mInjector.getAppFGSTracker().hasForegroundServiceNotifications(packageName, uid);
+ }
+
+ /**
+ * @return If the given uid has a foreground service notification or not.
+ */
+ boolean hasForegroundServiceNotifications(int uid) {
+ return mInjector.getAppFGSTracker().hasForegroundServiceNotifications(uid);
+ }
+
+ /**
* @return The to-be-exempted battery usage of the given UID in the given duration; it could
* be considered as "exempted" due to various use cases, i.e. media playback.
*/
- double getUidBatteryExemptedUsageSince(int uid, long since, long now) {
+ ImmutableBatteryUsage getUidBatteryExemptedUsageSince(int uid, long since, long now,
+ int types) {
return mInjector.getAppBatteryExemptionTracker()
- .getUidBatteryExemptedUsageSince(uid, since, now);
+ .getUidBatteryExemptedUsageSince(uid, since, now, types);
}
/**
* @return The total battery usage of the given UID since the system boots.
*/
- double getUidBatteryUsage(int uid) {
+ @NonNull ImmutableBatteryUsage getUidBatteryUsage(int uid) {
return mInjector.getUidBatteryUsageProvider().getUidBatteryUsage(uid);
}
@@ -1092,16 +1200,19 @@
/**
* @return The total battery usage of the given UID since the system boots.
*/
- double getUidBatteryUsage(int uid);
+ @NonNull ImmutableBatteryUsage getUidBatteryUsage(int uid);
}
void dump(PrintWriter pw, String prefix) {
pw.print(prefix);
- pw.println("BACKGROUND RESTRICTION LEVEL SETTINGS");
+ pw.println("APP BACKGROUND RESTRICTIONS");
prefix = " " + prefix;
+ pw.print(prefix);
+ pw.println("BACKGROUND RESTRICTION LEVEL SETTINGS");
synchronized (mLock) {
- mRestrictionSettings.dumpLocked(pw, prefix);
+ mRestrictionSettings.dumpLocked(pw, " " + prefix);
}
+ mConstantsObserver.dump(pw, " " + prefix);
for (int i = 0, size = mAppStateTrackers.size(); i < size; i++) {
pw.println();
mAppStateTrackers.get(i).dump(pw, prefix);
@@ -1365,8 +1476,21 @@
intent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE, null,
UserHandle.of(UserHandle.getUserId(uid)));
Notification.Action[] actions = null;
- if (ENABLE_SHOW_FOREGROUND_SERVICE_MANAGER
- && mBgController.hasForegroundServices(packageName, uid)) {
+ final boolean hasForegroundServices =
+ mBgController.hasForegroundServices(packageName, uid);
+ final boolean hasForegroundServiceNotifications =
+ mBgController.hasForegroundServiceNotifications(packageName, uid);
+ if (!mBgController.mConstantsObserver.mBgPromptFgsWithNotiToBgRestricted) {
+ // We're not going to prompt the user if the FGS is active and its notification
+ // is still showing (not dismissed/silenced/denied).
+ if (hasForegroundServices && hasForegroundServiceNotifications) {
+ if (DEBUG_BG_RESTRICTION_CONTROLLER) {
+ Slog.i(TAG, "Not requesting bg-restriction due to FGS with notification");
+ }
+ return;
+ }
+ }
+ if (ENABLE_SHOW_FOREGROUND_SERVICE_MANAGER && hasForegroundServices) {
final Intent trampoline = new Intent(ACTION_FGS_MANAGER_TRAMPOLINE);
trampoline.setPackage("android");
trampoline.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
@@ -1645,6 +1769,8 @@
return REASON_CARRIER_PRIVILEGED_APP;
} else if (isExemptedFromSysConfig(pkg)) {
return REASON_SYSTEM_ALLOW_LISTED;
+ } else if (mConstantsObserver.mBgRestrictionExemptedPackages.contains(pkg)) {
+ return REASON_ALLOWLISTED_PACKAGE;
}
}
}
@@ -1863,6 +1989,7 @@
private AppBatteryExemptionTracker mAppBatteryExemptionTracker;
private AppFGSTracker mAppFGSTracker;
private AppMediaSessionTracker mAppMediaSessionTracker;
+ private AppPermissionTracker mAppPermissionTracker;
private TelephonyManager mTelephonyManager;
Injector(Context context) {
@@ -1879,10 +2006,12 @@
mAppBatteryExemptionTracker = new AppBatteryExemptionTracker(mContext, controller);
mAppFGSTracker = new AppFGSTracker(mContext, controller);
mAppMediaSessionTracker = new AppMediaSessionTracker(mContext, controller);
+ mAppPermissionTracker = new AppPermissionTracker(mContext, controller);
controller.mAppStateTrackers.add(mAppBatteryTracker);
controller.mAppStateTrackers.add(mAppBatteryExemptionTracker);
controller.mAppStateTrackers.add(mAppFGSTracker);
controller.mAppStateTrackers.add(mAppMediaSessionTracker);
+ controller.mAppStateTrackers.add(mAppPermissionTracker);
controller.mAppStateTrackers.add(new AppBroadcastEventsTracker(mContext, controller));
controller.mAppStateTrackers.add(new AppBindServiceEventsTracker(mContext, controller));
}
@@ -1990,6 +2119,10 @@
return mAppBatteryExemptionTracker;
}
+ AppPermissionTracker getAppPermissionTracker() {
+ return mAppPermissionTracker;
+ }
+
String getPackageName(int pid) {
final ActivityManagerService am = getActivityManagerService();
final ProcessRecord app;
diff --git a/services/core/java/com/android/server/am/BaseAppStateDurationsTracker.java b/services/core/java/com/android/server/am/BaseAppStateDurationsTracker.java
index cc89e84..80a219d4 100644
--- a/services/core/java/com/android/server/am/BaseAppStateDurationsTracker.java
+++ b/services/core/java/com/android/server/am/BaseAppStateDurationsTracker.java
@@ -19,7 +19,6 @@
import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
-import android.annotation.NonNull;
import android.content.Context;
import android.os.SystemClock;
import android.util.SparseArray;
@@ -32,7 +31,6 @@
import java.io.PrintWriter;
import java.lang.reflect.Constructor;
-import java.util.ArrayList;
import java.util.LinkedList;
/**
@@ -43,20 +41,9 @@
extends BaseAppStateEventsTracker<T, U> {
static final boolean DEBUG_BASE_APP_STATE_DURATION_TRACKER = false;
- static final int EVENT_TYPE_MEDIA_SESSION = 0;
- static final int EVENT_TYPE_FGS_MEDIA_PLAYBACK = 1;
- static final int EVENT_TYPE_FGS_LOCATION = 2;
- static final int EVENT_NUM = 3;
-
- final ArrayList<EventListener> mEventListeners = new ArrayList<>();
-
@GuardedBy("mLock")
final SparseArray<UidStateDurations> mUidStateDurations = new SparseArray<>();
- interface EventListener {
- void onNewEvent(int uid, String packageName, boolean start, long now, int eventType);
- }
-
BaseAppStateDurationsTracker(Context context, AppRestrictionController controller,
Constructor<? extends Injector<T>> injector, Object outerContext) {
super(context, controller, injector, outerContext);
@@ -104,21 +91,6 @@
mUidStateDurations.remove(uid);
}
- void registerEventListener(@NonNull EventListener listener) {
- synchronized (mLock) {
- mEventListeners.add(listener);
- }
- }
-
- void notifyListenersOnEvent(int uid, String packageName,
- boolean start, long now, int eventType) {
- synchronized (mLock) {
- for (int i = 0, size = mEventListeners.size(); i < size; i++) {
- mEventListeners.get(i).onNewEvent(uid, packageName, start, now, eventType);
- }
- }
- }
-
long getTotalDurations(String packageName, int uid, long now, int index, boolean bgOnly) {
synchronized (mLock) {
final U durations = mPkgEvents.get(uid, packageName);
diff --git a/services/core/java/com/android/server/am/BaseAppStateEventsTracker.java b/services/core/java/com/android/server/am/BaseAppStateEventsTracker.java
index 3e1bcae..c6900b2 100644
--- a/services/core/java/com/android/server/am/BaseAppStateEventsTracker.java
+++ b/services/core/java/com/android/server/am/BaseAppStateEventsTracker.java
@@ -184,9 +184,13 @@
}
}
}
+ dumpOthers(pw, prefix);
policy.dump(pw, prefix);
}
+ void dumpOthers(PrintWriter pw, String prefix) {
+ }
+
@GuardedBy("mLock")
void dumpEventHeaderLocked(PrintWriter pw, String prefix, String packageName, int uid, U events,
T policy) {
diff --git a/services/core/java/com/android/server/am/BaseAppStateTracker.java b/services/core/java/com/android/server/am/BaseAppStateTracker.java
index 2846f6c..482d697 100644
--- a/services/core/java/com/android/server/am/BaseAppStateTracker.java
+++ b/services/core/java/com/android/server/am/BaseAppStateTracker.java
@@ -28,19 +28,23 @@
import android.app.role.RoleManager;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.media.session.MediaSessionManager;
import android.os.BatteryManagerInternal;
import android.os.BatteryStatsInternal;
import android.os.Handler;
+import android.permission.PermissionManager;
import android.util.Slog;
import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
+import com.android.server.notification.NotificationManagerInternal;
import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import java.io.PrintWriter;
import java.lang.reflect.Constructor;
+import java.util.ArrayList;
/**
* Base class to track certain state of the app, could be used to determine the restriction level.
@@ -54,11 +58,27 @@
static final long ONE_HOUR = 60 * ONE_MINUTE;
static final long ONE_DAY = 24 * ONE_HOUR;
+ static final int STATE_TYPE_MEDIA_SESSION = 1;
+ static final int STATE_TYPE_FGS_MEDIA_PLAYBACK = 1 << 1;
+ static final int STATE_TYPE_FGS_LOCATION = 1 << 2;
+ static final int STATE_TYPE_PERMISSION = 1 << 3;
+ static final int STATE_TYPE_NUM = 4;
+
+ static final int STATE_TYPE_INDEX_MEDIA_SESSION = 0;
+ static final int STATE_TYPE_INDEX_FGS_MEDIA_PLAYBACK = 1;
+ static final int STATE_TYPE_INDEX_FGS_LOCATION = 2;
+ static final int STATE_TYPE_INDEX_PERMISSION = 3;
+
protected final AppRestrictionController mAppRestrictionController;
protected final Injector<T> mInjector;
protected final Context mContext;
protected final Handler mBgHandler;
protected final Object mLock;
+ protected final ArrayList<StateListener> mStateListeners = new ArrayList<>();
+
+ interface StateListener {
+ void onStateChange(int uid, String packageName, boolean start, long now, int stateType);
+ }
BaseAppStateTracker(Context context, AppRestrictionController controller,
@Nullable Constructor<? extends Injector<T>> injector, Object outerContext) {
@@ -79,6 +99,60 @@
}
}
+ static int stateTypeToIndex(int stateType) {
+ return Integer.numberOfTrailingZeros(stateType);
+ }
+
+ static int stateIndexToType(int stateTypeIndex) {
+ return 1 << stateTypeIndex;
+ }
+
+ static String stateTypesToString(int stateTypes) {
+ final StringBuilder sb = new StringBuilder("[");
+ boolean needDelimiter = false;
+ for (int stateType = Integer.highestOneBit(stateTypes); stateType != 0;
+ stateType = Integer.highestOneBit(stateTypes)) {
+ if (needDelimiter) {
+ sb.append('|');
+ }
+ needDelimiter = true;
+ switch (stateType) {
+ case STATE_TYPE_MEDIA_SESSION:
+ sb.append("MEDIA_SESSION");
+ break;
+ case STATE_TYPE_FGS_MEDIA_PLAYBACK:
+ sb.append("FGS_MEDIA_PLAYBACK");
+ break;
+ case STATE_TYPE_FGS_LOCATION:
+ sb.append("FGS_LOCATION");
+ break;
+ case STATE_TYPE_PERMISSION:
+ sb.append("PERMISSION");
+ break;
+ default:
+ return "[UNKNOWN(" + Integer.toHexString(stateTypes) + ")]";
+ }
+ stateTypes &= ~stateType;
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
+ void registerStateListener(@NonNull StateListener listener) {
+ synchronized (mLock) {
+ mStateListeners.add(listener);
+ }
+ }
+
+ void notifyListenersOnStateChange(int uid, String packageName,
+ boolean start, long now, int stateType) {
+ synchronized (mLock) {
+ for (int i = 0, size = mStateListeners.size(); i < size; i++) {
+ mStateListeners.get(i).onStateChange(uid, packageName, start, now, stateType);
+ }
+ }
+ }
+
/**
* Return the policy holder of this tracker.
*/
@@ -179,10 +253,13 @@
DeviceIdleInternal mDeviceIdleInternal;
UserManagerInternal mUserManagerInternal;
PackageManager mPackageManager;
+ PackageManagerInternal mPackageManagerInternal;
+ PermissionManager mPermissionManager;
PermissionManagerServiceInternal mPermissionManagerServiceInternal;
AppOpsManager mAppOpsManager;
MediaSessionManager mMediaSessionManager;
RoleManager mRoleManager;
+ NotificationManagerInternal mNotificationManagerInternal;
void setPolicy(T policy) {
mAppStatePolicy = policy;
@@ -194,13 +271,17 @@
mBatteryStatsInternal = LocalServices.getService(BatteryStatsInternal.class);
mDeviceIdleInternal = LocalServices.getService(DeviceIdleInternal.class);
mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
+ mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
mPermissionManagerServiceInternal = LocalServices.getService(
PermissionManagerServiceInternal.class);
final Context context = mAppStatePolicy.mTracker.mContext;
mPackageManager = context.getPackageManager();
mAppOpsManager = context.getSystemService(AppOpsManager.class);
mMediaSessionManager = context.getSystemService(MediaSessionManager.class);
+ mPermissionManager = context.getSystemService(PermissionManager.class);
mRoleManager = context.getSystemService(RoleManager.class);
+ mNotificationManagerInternal = LocalServices.getService(
+ NotificationManagerInternal.class);
getPolicy().onSystemReady();
}
@@ -240,6 +321,14 @@
return mPackageManager;
}
+ PackageManagerInternal getPackageManagerInternal() {
+ return mPackageManagerInternal;
+ }
+
+ PermissionManager getPermissionManager() {
+ return mPermissionManager;
+ }
+
PermissionManagerServiceInternal getPermissionManagerServiceInternal() {
return mPermissionManagerServiceInternal;
}
@@ -259,5 +348,9 @@
RoleManager getRoleManager() {
return mRoleManager;
}
+
+ NotificationManagerInternal getNotificationManagerInternal() {
+ return mNotificationManagerInternal;
+ }
}
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 2f7249e..91822ac 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -79,7 +79,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.BackgroundThread;
-import com.android.internal.os.BatteryStatsHelper;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.BatteryUsageStatsProvider;
import com.android.internal.os.BatteryUsageStatsStore;
@@ -2488,7 +2487,7 @@
final long ident = Binder.clearCallingIdentity();
try {
- if (BatteryStatsHelper.checkWifiOnly(mContext)) {
+ if (BatteryStats.checkWifiOnly(mContext)) {
flags |= BatteryStats.DUMP_DEVICE_WIFI_ONLY;
}
awaitCompletion();
diff --git a/services/core/java/com/android/server/am/BroadcastConstants.java b/services/core/java/com/android/server/am/BroadcastConstants.java
index e580327..2ebe0b4 100644
--- a/services/core/java/com/android/server/am/BroadcastConstants.java
+++ b/services/core/java/com/android/server/am/BroadcastConstants.java
@@ -16,6 +16,10 @@
package com.android.server.am;
+import android.annotation.IntDef;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
+import android.compat.annotation.Overridable;
import android.content.ContentResolver;
import android.database.ContentObserver;
import android.os.Build;
@@ -26,6 +30,8 @@
import android.util.TimeUtils;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
* Tunable parameters for broadcast dispatch policy
@@ -51,6 +57,47 @@
private static final long DEFAULT_ALLOW_BG_ACTIVITY_START_TIMEOUT =
10_000 * Build.HW_TIMEOUT_MULTIPLIER;
+ /**
+ * Defer LOCKED_BOOT_COMPLETED and BOOT_COMPLETED broadcasts until the first time any process in
+ * the UID is started.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.S_V2)
+ @Overridable
+ static final long DEFER_BOOT_COMPLETED_BROADCAST_CHANGE_ID = 203704822L;
+
+ /**
+ * Do not defer LOCKED_BOOT_COMPLETED and BOOT_COMPLETED broadcasts.
+ */
+ public static final int DEFER_BOOT_COMPLETED_BROADCAST_NONE = 0;
+ /**
+ * Defer all LOCKED_BOOT_COMPLETED and BOOT_COMPLETED broadcasts.
+ */
+ public static final int DEFER_BOOT_COMPLETED_BROADCAST_ALL = 1 << 0;
+ /**
+ * Defer LOCKED_BOOT_COMPLETED and BOOT_COMPLETED broadcasts if app is background restricted.
+ */
+ public static final int DEFER_BOOT_COMPLETED_BROADCAST_BACKGROUND_RESTRICTED_ONLY = 1 << 1;
+ /**
+ * Defer LOCKED_BOOT_COMPLETED and BOOT_COMPLETED broadcasts if app's targetSdkVersion is T
+ * and above.
+ */
+ public static final int DEFER_BOOT_COMPLETED_BROADCAST_TARGET_T_ONLY = 1 << 2;
+
+ /**
+ * The list of DEFER_BOOT_COMPLETED_BROADCAST types.
+ * If multiple flags are selected, all conditions must be met to defer the broadcast.
+ * @hide
+ */
+ @IntDef(flag = true, prefix = { "DEFER_BOOT_COMPLETED_BROADCAST_" }, value = {
+ DEFER_BOOT_COMPLETED_BROADCAST_NONE,
+ DEFER_BOOT_COMPLETED_BROADCAST_ALL,
+ DEFER_BOOT_COMPLETED_BROADCAST_BACKGROUND_RESTRICTED_ONLY,
+ DEFER_BOOT_COMPLETED_BROADCAST_TARGET_T_ONLY,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DeferBootCompletedBroadcastType {}
+
// All time constants are in milliseconds
// Timeout period for this broadcast queue
diff --git a/services/core/java/com/android/server/am/BroadcastDispatcher.java b/services/core/java/com/android/server/am/BroadcastDispatcher.java
index 8afd52e..01d8109 100644
--- a/services/core/java/com/android/server/am/BroadcastDispatcher.java
+++ b/services/core/java/com/android/server/am/BroadcastDispatcher.java
@@ -18,14 +18,21 @@
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_DEFERRAL;
+import static com.android.server.am.BroadcastConstants.DEFER_BOOT_COMPLETED_BROADCAST_NONE;
+import android.annotation.Nullable;
import android.content.Intent;
+import android.content.pm.ResolveInfo;
import android.os.Handler;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.util.Slog;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.AlarmManagerInternal;
import com.android.server.LocalServices;
@@ -232,6 +239,253 @@
// Next outbound broadcast, established by getNextBroadcastLocked()
private BroadcastRecord mCurrentBroadcast;
+ // Map userId to its deferred boot completed broadcasts.
+ private SparseArray<DeferredBootCompletedBroadcastPerUser> mUser2Deferred = new SparseArray<>();
+
+ /**
+ * Deferred LOCKED_BOOT_COMPLETED and BOOT_COMPLETED broadcasts that is sent to a user.
+ */
+ static class DeferredBootCompletedBroadcastPerUser {
+ private int mUserId;
+ // UID that has process started at least once, ready to execute LOCKED_BOOT_COMPLETED
+ // receivers.
+ @VisibleForTesting
+ SparseBooleanArray mUidReadyForLockedBootCompletedBroadcast = new SparseBooleanArray();
+ // UID that has process started at least once, ready to execute BOOT_COMPLETED receivers.
+ @VisibleForTesting
+ SparseBooleanArray mUidReadyForBootCompletedBroadcast = new SparseBooleanArray();
+ // Map UID to deferred LOCKED_BOOT_COMPLETED broadcasts.
+ // LOCKED_BOOT_COMPLETED broadcast receivers are deferred until the first time the uid has
+ // any process started.
+ @VisibleForTesting
+ SparseArray<BroadcastRecord> mDeferredLockedBootCompletedBroadcasts = new SparseArray<>();
+ // is the LOCKED_BOOT_COMPLETED broadcast received by the user.
+ @VisibleForTesting
+ boolean mLockedBootCompletedBroadcastReceived;
+ // Map UID to deferred BOOT_COMPLETED broadcasts.
+ // BOOT_COMPLETED broadcast receivers are deferred until the first time the uid has any
+ // process started.
+ @VisibleForTesting
+ SparseArray<BroadcastRecord> mDeferredBootCompletedBroadcasts = new SparseArray<>();
+ // is the BOOT_COMPLETED broadcast received by the user.
+ @VisibleForTesting
+ boolean mBootCompletedBroadcastReceived;
+
+ DeferredBootCompletedBroadcastPerUser(int userId) {
+ this.mUserId = userId;
+ }
+
+ public void updateUidReady(int uid) {
+ if (!mLockedBootCompletedBroadcastReceived
+ || mDeferredLockedBootCompletedBroadcasts.size() != 0) {
+ mUidReadyForLockedBootCompletedBroadcast.put(uid, true);
+ }
+ if (!mBootCompletedBroadcastReceived
+ || mDeferredBootCompletedBroadcasts.size() != 0) {
+ mUidReadyForBootCompletedBroadcast.put(uid, true);
+ }
+ }
+
+ public void enqueueBootCompletedBroadcasts(String action,
+ SparseArray<BroadcastRecord> deferred) {
+ if (Intent.ACTION_LOCKED_BOOT_COMPLETED.equals(action)) {
+ enqueueBootCompletedBroadcasts(deferred, mDeferredLockedBootCompletedBroadcasts,
+ mUidReadyForLockedBootCompletedBroadcast);
+ mLockedBootCompletedBroadcastReceived = true;
+ if (DEBUG_BROADCAST_DEFERRAL) {
+ dumpBootCompletedBroadcastRecord(mDeferredLockedBootCompletedBroadcasts);
+ }
+ } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
+ enqueueBootCompletedBroadcasts(deferred, mDeferredBootCompletedBroadcasts,
+ mUidReadyForBootCompletedBroadcast);
+ mBootCompletedBroadcastReceived = true;
+ if (DEBUG_BROADCAST_DEFERRAL) {
+ dumpBootCompletedBroadcastRecord(mDeferredBootCompletedBroadcasts);
+ }
+ }
+ }
+
+ /**
+ * Merge UID to BroadcastRecord map into {@link #mDeferredBootCompletedBroadcasts} or
+ * {@link #mDeferredLockedBootCompletedBroadcasts}
+ * @param from the UID to BroadcastRecord map.
+ * @param into The UID to list of BroadcastRecord map.
+ */
+ private void enqueueBootCompletedBroadcasts(SparseArray<BroadcastRecord> from,
+ SparseArray<BroadcastRecord> into, SparseBooleanArray uidReadyForReceiver) {
+ // remove unwanted uids from uidReadyForReceiver.
+ for (int i = uidReadyForReceiver.size() - 1; i >= 0; i--) {
+ if (from.indexOfKey(uidReadyForReceiver.keyAt(i)) < 0) {
+ uidReadyForReceiver.removeAt(i);
+ }
+ }
+ for (int i = 0, size = from.size(); i < size; i++) {
+ final int uid = from.keyAt(i);
+ into.put(uid, from.valueAt(i));
+ if (uidReadyForReceiver.indexOfKey(uid) < 0) {
+ // uid is wanted but not ready.
+ uidReadyForReceiver.put(uid, false);
+ }
+ }
+ }
+
+ public @Nullable BroadcastRecord dequeueDeferredBootCompletedBroadcast(
+ boolean isAllUidReady) {
+ BroadcastRecord next = dequeueDeferredBootCompletedBroadcast(
+ mDeferredLockedBootCompletedBroadcasts,
+ mUidReadyForLockedBootCompletedBroadcast, isAllUidReady);
+ if (next == null) {
+ next = dequeueDeferredBootCompletedBroadcast(mDeferredBootCompletedBroadcasts,
+ mUidReadyForBootCompletedBroadcast, isAllUidReady);
+ }
+ return next;
+ }
+
+ private @Nullable BroadcastRecord dequeueDeferredBootCompletedBroadcast(
+ SparseArray<BroadcastRecord> uid2br, SparseBooleanArray uidReadyForReceiver,
+ boolean isAllUidReady) {
+ for (int i = 0, size = uid2br.size(); i < size; i++) {
+ final int uid = uid2br.keyAt(i);
+ if (isAllUidReady || uidReadyForReceiver.get(uid)) {
+ final BroadcastRecord br = uid2br.valueAt(i);
+ if (DEBUG_BROADCAST_DEFERRAL) {
+ final Object receiver = br.receivers.get(0);
+ if (receiver instanceof BroadcastFilter) {
+ if (DEBUG_BROADCAST_DEFERRAL) {
+ Slog.i(TAG, "getDeferredBootCompletedBroadcast uid:" + uid
+ + " BroadcastFilter:" + (BroadcastFilter) receiver
+ + " broadcast:" + br.intent.getAction());
+ }
+ } else /* if (receiver instanceof ResolveInfo) */ {
+ ResolveInfo info = (ResolveInfo) receiver;
+ String packageName = info.activityInfo.applicationInfo.packageName;
+ if (DEBUG_BROADCAST_DEFERRAL) {
+ Slog.i(TAG, "getDeferredBootCompletedBroadcast uid:" + uid
+ + " packageName:" + packageName
+ + " broadcast:" + br.intent.getAction());
+ }
+ }
+ }
+ // remove the BroadcastRecord.
+ uid2br.removeAt(i);
+ if (uid2br.size() == 0) {
+ // All deferred receivers are executed, do not need uidReadyForReceiver
+ // any more.
+ uidReadyForReceiver.clear();
+ }
+ return br;
+ }
+ }
+ return null;
+ }
+
+ private @Nullable SparseArray<BroadcastRecord> getDeferredList(String action) {
+ SparseArray<BroadcastRecord> brs = null;
+ if (action.equals(Intent.ACTION_LOCKED_BOOT_COMPLETED)) {
+ brs = mDeferredLockedBootCompletedBroadcasts;
+ } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
+ brs = mDeferredBootCompletedBroadcasts;
+ }
+ return brs;
+ }
+
+ /**
+ * Return the total number of UIDs in all BroadcastRecord in
+ * {@link #mDeferredBootCompletedBroadcasts} or
+ * {@link #mDeferredLockedBootCompletedBroadcasts}
+ */
+ private int getBootCompletedBroadcastsUidsSize(String action) {
+ SparseArray<BroadcastRecord> brs = getDeferredList(action);
+ return brs != null ? brs.size() : 0;
+ }
+
+ /**
+ * Return the total number of receivers in all BroadcastRecord in
+ * {@link #mDeferredBootCompletedBroadcasts} or
+ * {@link #mDeferredLockedBootCompletedBroadcasts}
+ */
+ private int getBootCompletedBroadcastsReceiversSize(String action) {
+ SparseArray<BroadcastRecord> brs = getDeferredList(action);
+ if (brs == null) {
+ return 0;
+ }
+ int size = 0;
+ for (int i = 0, s = brs.size(); i < s; i++) {
+ size += brs.valueAt(i).receivers.size();
+ }
+ return size;
+ }
+
+ public void dump(Dumper dumper, String action) {
+ SparseArray<BroadcastRecord> brs = getDeferredList(action);
+ if (brs == null) {
+ return;
+ }
+ for (int i = 0, size = brs.size(); i < size; i++) {
+ dumper.dump(brs.valueAt(i));
+ }
+ }
+
+ public void dumpDebug(ProtoOutputStream proto, long fieldId) {
+ for (int i = 0, size = mDeferredLockedBootCompletedBroadcasts.size(); i < size; i++) {
+ mDeferredLockedBootCompletedBroadcasts.valueAt(i).dumpDebug(proto, fieldId);
+ }
+ for (int i = 0, size = mDeferredBootCompletedBroadcasts.size(); i < size; i++) {
+ mDeferredBootCompletedBroadcasts.valueAt(i).dumpDebug(proto, fieldId);
+ }
+ }
+
+ private void dumpBootCompletedBroadcastRecord(SparseArray<BroadcastRecord> brs) {
+ for (int i = 0, size = brs.size(); i < size; i++) {
+ final Object receiver = brs.valueAt(i).receivers.get(0);
+ String packageName = null;
+ if (receiver instanceof BroadcastFilter) {
+ BroadcastFilter recv = (BroadcastFilter) receiver;
+ packageName = recv.receiverList.app.processName;
+ } else /* if (receiver instanceof ResolveInfo) */ {
+ ResolveInfo info = (ResolveInfo) receiver;
+ packageName = info.activityInfo.applicationInfo.packageName;
+ }
+ Slog.i(TAG, "uid:" + brs.keyAt(i)
+ + " packageName:" + packageName
+ + " receivers:" + brs.valueAt(i).receivers.size());
+ }
+ }
+ }
+
+ private DeferredBootCompletedBroadcastPerUser getDeferredPerUser(int userId) {
+ if (mUser2Deferred.contains(userId)) {
+ return mUser2Deferred.get(userId);
+ } else {
+ final DeferredBootCompletedBroadcastPerUser temp =
+ new DeferredBootCompletedBroadcastPerUser(userId);
+ mUser2Deferred.put(userId, temp);
+ return temp;
+ }
+ }
+
+ /**
+ * ActivityManagerService.attachApplication() call this method to notify that the UID is ready
+ * to accept deferred LOCKED_BOOT_COMPLETED and BOOT_COMPLETED broadcasts.
+ * @param uid
+ */
+ public void updateUidReadyForBootCompletedBroadcastLocked(int uid) {
+ getDeferredPerUser(UserHandle.getUserId(uid)).updateUidReady(uid);
+ }
+
+ private @Nullable BroadcastRecord dequeueDeferredBootCompletedBroadcast() {
+ final boolean isAllUidReady = (mQueue.mService.mConstants.mDeferBootCompletedBroadcast
+ == DEFER_BOOT_COMPLETED_BROADCAST_NONE);
+ BroadcastRecord next = null;
+ for (int i = 0, size = mUser2Deferred.size(); i < size; i++) {
+ next = mUser2Deferred.valueAt(i).dequeueDeferredBootCompletedBroadcast(isAllUidReady);
+ if (next != null) {
+ break;
+ }
+ }
+ return next;
+ }
+
/**
* Constructed & sharing a lock with its associated BroadcastQueue instance
*/
@@ -261,7 +515,9 @@
return mCurrentBroadcast == null
&& mOrderedBroadcasts.isEmpty()
&& isDeferralsListEmpty(mDeferredBroadcasts)
- && isDeferralsListEmpty(mAlarmBroadcasts);
+ && isDeferralsListEmpty(mAlarmBroadcasts)
+ && getBootCompletedBroadcastsUidsSize(Intent.ACTION_LOCKED_BOOT_COMPLETED) == 0
+ && getBootCompletedBroadcastsUidsSize(Intent.ACTION_BOOT_COMPLETED) == 0;
}
}
@@ -301,14 +557,78 @@
sb.append(n);
sb.append(" deferred");
}
+ n = getBootCompletedBroadcastsUidsSize(Intent.ACTION_LOCKED_BOOT_COMPLETED);
+ if (n > 0) {
+ sb.append(", ");
+ sb.append(n);
+ sb.append(" deferred LOCKED_BOOT_COMPLETED/");
+ sb.append(getBootCompletedBroadcastsReceiversSize(Intent.ACTION_LOCKED_BOOT_COMPLETED));
+ sb.append(" receivers");
+ }
+
+ n = getBootCompletedBroadcastsUidsSize(Intent.ACTION_BOOT_COMPLETED);
+ if (n > 0) {
+ sb.append(", ");
+ sb.append(n);
+ sb.append(" deferred BOOT_COMPLETED/");
+ sb.append(getBootCompletedBroadcastsReceiversSize(Intent.ACTION_BOOT_COMPLETED));
+ sb.append(" receivers");
+ }
return sb.toString();
}
// ----------------------------------
// BroadcastQueue operation support
-
void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
- mOrderedBroadcasts.add(r);
+ if (Intent.ACTION_LOCKED_BOOT_COMPLETED.equals(r.intent.getAction())) {
+ // Create one BroadcastRecord for each UID that can be deferred.
+ final SparseArray<BroadcastRecord> deferred =
+ r.splitDeferredBootCompletedBroadcastLocked(mQueue.mService.mInternal,
+ mQueue.mService.mConstants.mDeferBootCompletedBroadcast);
+ getDeferredPerUser(r.userId).enqueueBootCompletedBroadcasts(
+ Intent.ACTION_LOCKED_BOOT_COMPLETED, deferred);
+ if (!r.receivers.isEmpty()) {
+ // The non-deferred receivers.
+ mOrderedBroadcasts.add(r);
+ return;
+ }
+ } else if (Intent.ACTION_BOOT_COMPLETED.equals(r.intent.getAction())) {
+ // Create one BroadcastRecord for each UID that can be deferred.
+ final SparseArray<BroadcastRecord> deferred =
+ r.splitDeferredBootCompletedBroadcastLocked(mQueue.mService.mInternal,
+ mQueue.mService.mConstants.mDeferBootCompletedBroadcast);
+ getDeferredPerUser(r.userId).enqueueBootCompletedBroadcasts(
+ Intent.ACTION_BOOT_COMPLETED, deferred);
+ if (!r.receivers.isEmpty()) {
+ // The non-deferred receivers.
+ mOrderedBroadcasts.add(r);
+ return;
+ }
+ } else {
+ mOrderedBroadcasts.add(r);
+ }
+ }
+
+ /**
+ * Return the total number of UIDs in all deferred boot completed BroadcastRecord.
+ */
+ private int getBootCompletedBroadcastsUidsSize(String action) {
+ int size = 0;
+ for (int i = 0, s = mUser2Deferred.size(); i < s; i++) {
+ size += mUser2Deferred.valueAt(i).getBootCompletedBroadcastsUidsSize(action);
+ }
+ return size;
+ }
+
+ /**
+ * Return the total number of receivers in all deferred boot completed BroadcastRecord.
+ */
+ private int getBootCompletedBroadcastsReceiversSize(String action) {
+ int size = 0;
+ for (int i = 0, s = mUser2Deferred.size(); i < s; i++) {
+ size += mUser2Deferred.valueAt(i).getBootCompletedBroadcastsReceiversSize(action);
+ }
+ return size;
}
// Returns the now-replaced broadcast record, or null if none
@@ -369,6 +689,31 @@
boolean didSomething = cleanupBroadcastListDisabledReceiversLocked(mOrderedBroadcasts,
packageName, filterByClasses, userId, doit);
if (doit || !didSomething) {
+ ArrayList<BroadcastRecord> lockedBootCompletedBroadcasts = new ArrayList<>();
+ for (int u = 0, usize = mUser2Deferred.size(); u < usize; u++) {
+ SparseArray<BroadcastRecord> brs =
+ mUser2Deferred.valueAt(u).mDeferredLockedBootCompletedBroadcasts;
+ for (int i = 0, size = brs.size(); i < size; i++) {
+ lockedBootCompletedBroadcasts.add(brs.valueAt(i));
+ }
+ }
+ didSomething = cleanupBroadcastListDisabledReceiversLocked(
+ lockedBootCompletedBroadcasts,
+ packageName, filterByClasses, userId, doit);
+ }
+ if (doit || !didSomething) {
+ ArrayList<BroadcastRecord> bootCompletedBroadcasts = new ArrayList<>();
+ for (int u = 0, usize = mUser2Deferred.size(); u < usize; u++) {
+ SparseArray<BroadcastRecord> brs =
+ mUser2Deferred.valueAt(u).mDeferredBootCompletedBroadcasts;
+ for (int i = 0, size = brs.size(); i < size; i++) {
+ bootCompletedBroadcasts.add(brs.valueAt(i));
+ }
+ }
+ didSomething = cleanupBroadcastListDisabledReceiversLocked(bootCompletedBroadcasts,
+ packageName, filterByClasses, userId, doit);
+ }
+ if (doit || !didSomething) {
didSomething |= cleanupDeferralsListDisabledReceiversLocked(mAlarmBroadcasts,
packageName, filterByClasses, userId, doit);
}
@@ -428,6 +773,10 @@
for (Deferrals d : mDeferredBroadcasts) {
d.dumpDebug(proto, fieldId);
}
+
+ for (int i = 0, size = mUser2Deferred.size(); i < size; i++) {
+ mUser2Deferred.valueAt(i).dumpDebug(proto, fieldId);
+ }
}
// ----------------------------------
@@ -453,7 +802,12 @@
final boolean someQueued = !mOrderedBroadcasts.isEmpty();
BroadcastRecord next = null;
- if (!mAlarmBroadcasts.isEmpty()) {
+
+ if (next == null) {
+ next = dequeueDeferredBootCompletedBroadcast();
+ }
+
+ if (next == null && !mAlarmBroadcasts.isEmpty()) {
next = popLocked(mAlarmBroadcasts);
if (DEBUG_BROADCAST_DEFERRAL && next != null) {
Slog.i(TAG, "Next broadcast from alarm targets: " + next);
@@ -752,6 +1106,20 @@
}
printed |= dumper.didPrint();
+ dumper.setHeading("Deferred LOCKED_BOOT_COMPLETED broadcasts");
+ dumper.setLabel("Deferred LOCKED_BOOT_COMPLETED Broadcast");
+ for (int i = 0, size = mUser2Deferred.size(); i < size; i++) {
+ mUser2Deferred.valueAt(i).dump(dumper, Intent.ACTION_LOCKED_BOOT_COMPLETED);
+ }
+ printed |= dumper.didPrint();
+
+ dumper.setHeading("Deferred BOOT_COMPLETED broadcasts");
+ dumper.setLabel("Deferred BOOT_COMPLETED Broadcast");
+ for (int i = 0, size = mUser2Deferred.size(); i < size; i++) {
+ mUser2Deferred.valueAt(i).dump(dumper, Intent.ACTION_BOOT_COMPLETED);
+ }
+ printed |= dumper.didPrint();
+
return printed;
}
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index a83fdd0..ea63c08 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -249,11 +249,13 @@
}
public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
+ r.enqueueClockTime = System.currentTimeMillis();
mParallelBroadcasts.add(r);
enqueueBroadcastHelper(r);
}
public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
+ r.enqueueClockTime = System.currentTimeMillis();
mDispatcher.enqueueOrderedBroadcastLocked(r);
enqueueBroadcastHelper(r);
}
@@ -263,8 +265,6 @@
* enqueueOrderedBroadcastLocked.
*/
private void enqueueBroadcastHelper(BroadcastRecord r) {
- r.enqueueClockTime = System.currentTimeMillis();
-
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING),
@@ -368,6 +368,15 @@
}
}
+ /**
+ * Called by ActivityManagerService to notify that the uid has process started, if there is any
+ * deferred BOOT_COMPLETED broadcast, the BroadcastDispatcher can dispatch the broadcast now.
+ * @param uid
+ */
+ public void updateUidReadyForBootCompletedBroadcastLocked(int uid) {
+ mDispatcher.updateUidReadyForBootCompletedBroadcastLocked(uid);
+ }
+
public boolean sendPendingBroadcastsLocked(ProcessRecord app) {
boolean didSomething = false;
final BroadcastRecord br = mPendingBroadcast;
@@ -1858,9 +1867,7 @@
}
private void maybeReportBroadcastDispatchedEventLocked(BroadcastRecord r, int targetUid) {
- // TODO (206518114): Only allow apps with ACCESS_PACKAGE_USAGE_STATS to set
- // getIdForResponseEvent.
- // TODO (217251579): Temporarily use temp-allowlist reason to identify
+ // STOPSHIP (217251579): Temporarily use temp-allowlist reason to identify
// push messages and record response events.
useTemporaryAllowlistReasonAsSignal(r);
if (r.options == null || r.options.getIdForResponseEvent() <= 0) {
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 8015596..8b1e829 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -16,9 +16,20 @@
package com.android.server.am;
+import static android.app.ActivityManager.RESTRICTION_LEVEL_BACKGROUND_RESTRICTED;
+
+import static com.android.server.am.BroadcastConstants.DEFER_BOOT_COMPLETED_BROADCAST_ALL;
+import static com.android.server.am.BroadcastConstants.DEFER_BOOT_COMPLETED_BROADCAST_BACKGROUND_RESTRICTED_ONLY;
+import static com.android.server.am.BroadcastConstants.DEFER_BOOT_COMPLETED_BROADCAST_CHANGE_ID;
+import static com.android.server.am.BroadcastConstants.DEFER_BOOT_COMPLETED_BROADCAST_NONE;
+import static com.android.server.am.BroadcastConstants.DEFER_BOOT_COMPLETED_BROADCAST_TARGET_T_ONLY;
+
+import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
import android.app.BroadcastOptions;
+import android.app.compat.CompatChanges;
import android.content.ComponentName;
import android.content.IIntentReceiver;
import android.content.Intent;
@@ -30,6 +41,7 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.PrintWriterPrinter;
+import android.util.SparseArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
@@ -371,6 +383,80 @@
return split;
}
+ /**
+ * Split a BroadcastRecord to a map of deferred receiver UID to deferred BroadcastRecord.
+ *
+ * The receivers that are deferred are removed from original BroadcastRecord's receivers list.
+ * The receivers that are not deferred are kept in original BroadcastRecord's receivers list.
+ *
+ * Only used to split LOCKED_BOOT_COMPLETED or BOOT_COMPLETED BroadcastRecord.
+ * LOCKED_BOOT_COMPLETED or BOOT_COMPLETED broadcast can be deferred until the first time
+ * the receiver's UID has a process started.
+ *
+ * @param ams The ActivityManagerService object.
+ * @param deferType Defer what UID?
+ * @return the deferred UID to BroadcastRecord map, the BroadcastRecord has the list of
+ * receivers in that UID.
+ */
+ @NonNull SparseArray<BroadcastRecord> splitDeferredBootCompletedBroadcastLocked(
+ ActivityManagerInternal activityManagerInternal,
+ @BroadcastConstants.DeferBootCompletedBroadcastType int deferType) {
+ final SparseArray<BroadcastRecord> ret = new SparseArray<>();
+ if (deferType == DEFER_BOOT_COMPLETED_BROADCAST_NONE) {
+ return ret;
+ }
+
+ final String action = intent.getAction();
+ if (!Intent.ACTION_LOCKED_BOOT_COMPLETED.equals(action)
+ && !Intent.ACTION_BOOT_COMPLETED.equals(action)) {
+ return ret;
+ }
+
+ final SparseArray<List<Object>> uid2receiverList = new SparseArray<>();
+ for (int i = receivers.size() - 1; i >= 0; i--) {
+ final Object receiver = receivers.get(i);
+ final int uid = getReceiverUid(receiver);
+ if (deferType != DEFER_BOOT_COMPLETED_BROADCAST_ALL) {
+ if ((deferType & DEFER_BOOT_COMPLETED_BROADCAST_BACKGROUND_RESTRICTED_ONLY) != 0) {
+ if (activityManagerInternal.getRestrictionLevel(uid)
+ < RESTRICTION_LEVEL_BACKGROUND_RESTRICTED) {
+ // skip if the UID is not background restricted.
+ continue;
+ }
+ }
+ if ((deferType & DEFER_BOOT_COMPLETED_BROADCAST_TARGET_T_ONLY) != 0) {
+ if (!CompatChanges.isChangeEnabled(DEFER_BOOT_COMPLETED_BROADCAST_CHANGE_ID,
+ uid)) {
+ // skip if the UID is not targetSdkVersion T+.
+ continue;
+ }
+ }
+ }
+ // Remove receiver from original BroadcastRecord's receivers list.
+ receivers.remove(i);
+ final List<Object> receiverList = uid2receiverList.get(uid);
+ if (receiverList != null) {
+ receiverList.add(0, receiver);
+ } else {
+ ArrayList<Object> splitReceivers = new ArrayList<>();
+ splitReceivers.add(0, receiver);
+ uid2receiverList.put(uid, splitReceivers);
+ }
+ }
+ final int uidSize = uid2receiverList.size();
+ for (int i = 0; i < uidSize; i++) {
+ final BroadcastRecord br = new BroadcastRecord(queue, intent, callerApp, callerPackage,
+ callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
+ requiredPermissions, excludedPermissions, appOp, options,
+ uid2receiverList.valueAt(i), resultTo,
+ resultCode, resultData, resultExtras, ordered, sticky, initialSticky, userId,
+ allowBackgroundActivityStarts, mBackgroundActivityStartsToken, timeoutExempt);
+ br.enqueueClockTime = this.enqueueClockTime;
+ ret.put(uid2receiverList.keyAt(i), br);
+ }
+ return ret;
+ }
+
int getReceiverUid(Object receiver) {
if (receiver instanceof BroadcastFilter) {
return ((BroadcastFilter) receiver).owningUid;
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index bdfd02e..6c9187a 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -2491,6 +2491,7 @@
mCachedAppOptimizer.onOomAdjustChanged(state.getSetAdj(), state.getCurAdj(), app);
} else if (mService.mWakefulness.get() != PowerManagerInternal.WAKEFULNESS_AWAKE
&& state.getSetAdj() < ProcessList.FOREGROUND_APP_ADJ
+ && !state.isRunningRemoteAnimation()
// Because these can fire independent of oom_adj/procstate changes, we need
// to throttle the actual dispatch of these requests in addition to the
// processing of the requests. As a result, there is throttling both here
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 1ad0bce..c4163e6 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1723,6 +1723,12 @@
return Zygote.MEMORY_TAG_LEVEL_TBI;
}
+ String defaultLevel = SystemProperties.get("persist.arm64.memtag.app_default");
+ if ("sync".equals(defaultLevel)) {
+ return Zygote.MEMORY_TAG_LEVEL_SYNC;
+ } else if ("async".equals(defaultLevel)) {
+ return Zygote.MEMORY_TAG_LEVEL_ASYNC;
+ }
return Zygote.MEMORY_TAG_LEVEL_NONE;
}
@@ -1918,7 +1924,7 @@
if ((app.info.privateFlags & ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL) != 0) {
runtimeFlags |= Zygote.PROFILE_FROM_SHELL;
}
- if ((app.info.privateFlagsExt & ApplicationInfo.PRIVATE_FLAG_EXT_PROFILEABLE) != 0) {
+ if (app.info.isProfileable()) {
runtimeFlags |= Zygote.PROFILEABLE;
}
if ("1".equals(SystemProperties.get("debug.checkjni"))) {
@@ -2525,6 +2531,7 @@
ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord,
int zygotePolicyFlags, boolean allowWhileBooting, boolean isolated, int isolatedUid,
+ boolean supplemental, int supplementalUid,
String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
long startTime = SystemClock.uptimeMillis();
ProcessRecord app;
@@ -2618,7 +2625,8 @@
if (app == null) {
checkSlow(startTime, "startProcess: creating new process record");
- app = newProcessRecordLocked(info, processName, isolated, isolatedUid, hostingRecord);
+ app = newProcessRecordLocked(info, processName, isolated, isolatedUid, supplemental,
+ supplementalUid, hostingRecord);
if (app == null) {
Slog.w(TAG, "Failed making new process record for "
+ processName + "/" + info.uid + " isolated=" + isolated);
@@ -3113,10 +3121,14 @@
@GuardedBy("mService")
ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
- boolean isolated, int isolatedUid, HostingRecord hostingRecord) {
+ boolean isolated, int isolatedUid, boolean supplemental, int supplementalUid,
+ HostingRecord hostingRecord) {
String proc = customProcess != null ? customProcess : info.processName;
final int userId = UserHandle.getUserId(info.uid);
int uid = info.uid;
+ if (supplemental) {
+ uid = supplementalUid;
+ }
if (isolated) {
if (isolatedUid == 0) {
IsolatedUidRange uidRange = getOrCreateIsolatedUidRangeLocked(info, hostingRecord);
diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java
index 256cffd..84d2b1f 100644
--- a/services/core/java/com/android/server/am/ProcessStatsService.java
+++ b/services/core/java/com/android/server/am/ProcessStatsService.java
@@ -787,7 +787,6 @@
}
private SparseArray<long[]> getUidProcStateStatsOverTime(long minTime) {
- final Parcel current = Parcel.obtain();
final ProcessStats stats = new ProcessStats();
long curTime;
synchronized (mLock) {
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index da78e2d..bf2876f 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -94,6 +94,8 @@
final boolean exported; // from ServiceInfo.exported
final Runnable restarter; // used to schedule retries of starting the service
final long createRealTime; // when this service was created
+ final boolean supplemental; // whether this is a supplemental service
+ final int supplementedAppUid; // the app uid for which this supplemental service is running
final ArrayMap<Intent.FilterComparison, IntentBindRecord> bindings
= new ArrayMap<Intent.FilterComparison, IntentBindRecord>();
// All active bindings to the service.
@@ -571,13 +573,13 @@
Intent.FilterComparison intent, ServiceInfo sInfo, boolean callerIsFg,
Runnable restarter) {
this(ams, name, instanceName, definingPackageName, definingUid, intent, sInfo, callerIsFg,
- restarter, false);
+ restarter, null, 0);
}
ServiceRecord(ActivityManagerService ams, ComponentName name,
ComponentName instanceName, String definingPackageName, int definingUid,
Intent.FilterComparison intent, ServiceInfo sInfo, boolean callerIsFg,
- Runnable restarter, boolean isSupplementalProcessService) {
+ Runnable restarter, String supplementalProcessName, int supplementedAppUid) {
this.ams = ams;
this.name = name;
this.instanceName = instanceName;
@@ -588,9 +590,12 @@
serviceInfo = sInfo;
appInfo = sInfo.applicationInfo;
packageName = sInfo.applicationInfo.packageName;
- if ((sInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0
- || isSupplementalProcessService) {
+ supplemental = supplementalProcessName != null;
+ this.supplementedAppUid = supplementedAppUid;
+ if ((sInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0) {
processName = sInfo.processName + ":" + instanceName.getClassName();
+ } else if (supplementalProcessName != null) {
+ processName = supplementalProcessName;
} else {
processName = sInfo.processName;
}
@@ -1093,6 +1098,10 @@
userId);
foregroundNoti = localForegroundNoti; // save it for amending next time
+
+ signalForegroundServiceNotification(packageName, appInfo.uid,
+ localForegroundId);
+
} catch (RuntimeException e) {
Slog.w(TAG, "Error showing notification for service", e);
// If it gave us a garbage notification, it doesn't
@@ -1126,10 +1135,21 @@
} catch (RuntimeException e) {
Slog.w(TAG, "Error canceling notification for service", e);
}
+ signalForegroundServiceNotification(packageName, appInfo.uid, -localForegroundId);
}
});
}
+ private void signalForegroundServiceNotification(String packageName, int uid,
+ int foregroundId) {
+ synchronized (ams) {
+ for (int i = ams.mForegroundServiceStateListeners.size() - 1; i >= 0; i--) {
+ ams.mForegroundServiceStateListeners.get(i).onForegroundServiceNotificationUpdated(
+ packageName, appInfo.uid, foregroundId);
+ }
+ }
+ }
+
public void stripForegroundServiceFlagFromNotification() {
final int localForegroundId = foregroundId;
final int localUserId = userId;
diff --git a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java
index 6982513..b73cf5b 100644
--- a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java
+++ b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java
@@ -20,22 +20,30 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.ActivityTaskManager;
import android.app.AppGlobals;
import android.app.BroadcastOptions;
import android.app.PendingIntent;
import android.app.ambientcontext.AmbientContextEvent;
import android.app.ambientcontext.AmbientContextEventRequest;
-import android.app.ambientcontext.AmbientContextEventResponse;
import android.app.ambientcontext.AmbientContextManager;
+import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
import android.content.pm.ServiceInfo;
import android.os.Binder;
+import android.os.Bundle;
import android.os.RemoteCallback;
import android.os.RemoteException;
-import android.service.ambientcontext.AmbientContextDetectionService;
+import android.service.ambientcontext.AmbientContextDetectionResult;
+import android.service.ambientcontext.AmbientContextDetectionServiceStatus;
+import android.text.TextUtils;
+import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.Slog;
@@ -44,7 +52,8 @@
import com.android.server.infra.AbstractPerUserSystemService;
import java.io.PrintWriter;
-import java.util.HashSet;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Set;
/**
@@ -60,14 +69,12 @@
RemoteAmbientContextDetectionService mRemoteService;
private ComponentName mComponentName;
- private Context mContext;
private Set<PendingIntent> mExistingPendingIntents;
AmbientContextManagerPerUserService(
@NonNull AmbientContextManagerService master, Object lock, @UserIdInt int userId) {
super(master, lock, userId);
- mContext = master.getContext();
- mExistingPendingIntents = new HashSet<>();
+ mExistingPendingIntents = new ArraySet<>();
}
void destroyLocked() {
@@ -154,12 +161,13 @@
* package. A new registration from the same package will overwrite the previous registration.
*/
public void onRegisterObserver(AmbientContextEventRequest request,
- PendingIntent pendingIntent) {
+ PendingIntent pendingIntent, RemoteCallback clientStatusCallback) {
synchronized (mLock) {
if (!setUpServiceIfNeeded()) {
- Slog.w(TAG, "Service is not available at this moment.");
- sendStatusUpdateIntent(
- pendingIntent, AmbientContextEventResponse.STATUS_SERVICE_UNAVAILABLE);
+ Slog.w(TAG, "Detection service is not available at this moment.");
+ sendStatusCallback(
+ clientStatusCallback,
+ AmbientContextManager.STATUS_SERVICE_UNAVAILABLE);
return;
}
@@ -173,29 +181,58 @@
}
// Register new package and add request to mExistingRequests
- startDetection(request, callingPackage, createRemoteCallback());
+ startDetection(request, callingPackage, createDetectionResultRemoteCallback(),
+ getServerStatusCallback(clientStatusCallback));
mExistingPendingIntents.add(pendingIntent);
}
}
+ /**
+ * Returns a RemoteCallback that handles the status from the detection service, and
+ * sends results to the client callback.
+ */
+ private RemoteCallback getServerStatusCallback(RemoteCallback clientStatusCallback) {
+ return new RemoteCallback(result -> {
+ AmbientContextDetectionServiceStatus serviceStatus =
+ (AmbientContextDetectionServiceStatus) result.get(
+ AmbientContextDetectionServiceStatus.STATUS_RESPONSE_BUNDLE_KEY);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ String packageName = serviceStatus.getPackageName();
+ Bundle bundle = new Bundle();
+ bundle.putInt(
+ AmbientContextManager.STATUS_RESPONSE_BUNDLE_KEY,
+ serviceStatus.getStatusCode());
+ clientStatusCallback.sendResult(bundle);
+ int statusCode = serviceStatus.getStatusCode();
+ Slog.i(TAG, "Got detection status of " + statusCode
+ + " for " + packageName);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ });
+ }
+
@VisibleForTesting
void startDetection(AmbientContextEventRequest request, String callingPackage,
- RemoteCallback callback) {
+ RemoteCallback detectionResultCallback, RemoteCallback statusCallback) {
Slog.d(TAG, "Requested detection of " + request.getEventTypes());
synchronized (mLock) {
ensureRemoteServiceInitiated();
- mRemoteService.startDetection(request, callingPackage, callback);
+ mRemoteService.startDetection(request, callingPackage, detectionResultCallback,
+ statusCallback);
}
}
/**
* Sends an intent with a status code and empty events.
*/
- void sendStatusUpdateIntent(PendingIntent pendingIntent, int statusCode) {
- AmbientContextEventResponse response = new AmbientContextEventResponse.Builder()
- .setStatusCode(statusCode)
- .build();
- sendResponseIntent(pendingIntent, response);
+ void sendStatusCallback(RemoteCallback statusCallback, int statusCode) {
+ Bundle bundle = new Bundle();
+ bundle.putInt(
+ AmbientContextManager.STATUS_RESPONSE_BUNDLE_KEY,
+ statusCode);
+ statusCallback.sendResult(bundle);
}
/**
@@ -217,6 +254,120 @@
}
}
+ public void onQueryServiceStatus(int[] eventTypes, String callingPackage,
+ RemoteCallback statusCallback) {
+ Slog.d(TAG, "Query event status of " + Arrays.toString(eventTypes)
+ + " for " + callingPackage);
+ synchronized (mLock) {
+ if (!setUpServiceIfNeeded()) {
+ Slog.w(TAG, "Detection service is not available at this moment.");
+ sendStatusToCallback(statusCallback,
+ AmbientContextManager.STATUS_SERVICE_UNAVAILABLE);
+ return;
+ }
+ ensureRemoteServiceInitiated();
+ mRemoteService.queryServiceStatus(
+ eventTypes,
+ callingPackage,
+ getServerStatusCallback(statusCallback));
+ }
+ }
+
+ public void onStartConsentActivity(int[] eventTypes, String callingPackage) {
+ Slog.d(TAG, "Opening consent activity of " + Arrays.toString(eventTypes)
+ + " for " + callingPackage);
+
+ // Look up the recent task from the callingPackage
+ ActivityManager.RecentTaskInfo task;
+ ParceledListSlice<ActivityManager.RecentTaskInfo> recentTasks;
+ int userId = getUserId();
+ try {
+ recentTasks = ActivityTaskManager.getService().getRecentTasks(/*maxNum*/1,
+ /*flags*/ 0, userId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to query recent tasks!");
+ return;
+ }
+
+ if ((recentTasks == null) || recentTasks.getList().isEmpty()) {
+ Slog.e(TAG, "Recent task list is empty!");
+ return;
+ }
+
+ task = recentTasks.getList().get(0);
+ if (!callingPackage.equals(task.topActivityInfo.packageName)) {
+ Slog.e(TAG, "Recent task package name: " + task.topActivityInfo.packageName
+ + " doesn't match with client package name: " + callingPackage);
+ return;
+ }
+
+ // Start activity as the same task from the callingPackage
+ ComponentName consentComponent = getConsentComponent();
+ if (consentComponent == null) {
+ Slog.e(TAG, "Consent component not found!");
+ return;
+ }
+
+ Slog.d(TAG, "Starting consent activity for " + callingPackage);
+ Intent intent = new Intent();
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ Context context = getContext();
+ String packageNameExtraKey = context.getResources().getString(
+ com.android.internal.R.string.config_ambientContextPackageNameExtraKey);
+ String eventArrayExtraKey = context.getResources().getString(
+ com.android.internal.R.string.config_ambientContextEventArrayExtraKey);
+
+ // Create consent activity intent with the calling package name and requested events
+ intent.setComponent(consentComponent);
+ if (packageNameExtraKey != null) {
+ intent.putExtra(packageNameExtraKey, callingPackage);
+ } else {
+ Slog.d(TAG, "Missing packageNameExtraKey for consent activity");
+ }
+ if (eventArrayExtraKey != null) {
+ intent.putExtra(eventArrayExtraKey, eventTypes);
+ } else {
+ Slog.d(TAG, "Missing eventArrayExtraKey for consent activity");
+ }
+
+ // Set parent to the calling app's task
+ ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchTaskId(task.taskId);
+ context.startActivityAsUser(intent, options.toBundle(), context.getUser());
+ } catch (ActivityNotFoundException e) {
+ Slog.e(TAG, "unable to start consent activity");
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Returns the consent activity component from config lookup.
+ */
+ private ComponentName getConsentComponent() {
+ Context context = getContext();
+ String consentComponent = context.getResources().getString(
+ com.android.internal.R.string.config_defaultAmbientContextConsentComponent);
+ if (TextUtils.isEmpty(consentComponent)) {
+ return null;
+ }
+ Slog.i(TAG, "Consent component name: " + consentComponent);
+ return ComponentName.unflattenFromString(consentComponent);
+ }
+
+ /**
+ * Sends the result response with the specified status to the callback.
+ */
+ void sendStatusToCallback(RemoteCallback callback,
+ @AmbientContextManager.StatusCode int status) {
+ Bundle bundle = new Bundle();
+ bundle.putInt(
+ AmbientContextManager.STATUS_RESPONSE_BUNDLE_KEY,
+ status);
+ callback.sendResult(bundle);
+ }
+
@VisibleForTesting
void stopDetection(String packageName) {
Slog.d(TAG, "Stop detection for " + packageName);
@@ -240,12 +391,13 @@
* Sends out the Intent to the client after the event is detected.
*
* @param pendingIntent Client's PendingIntent for callback
- * @param response Response with status code and detection result
+ * @param result result from the detection service
*/
- private void sendResponseIntent(PendingIntent pendingIntent,
- AmbientContextEventResponse response) {
+ private void sendDetectionResultIntent(PendingIntent pendingIntent,
+ AmbientContextDetectionResult result) {
Intent intent = new Intent();
- intent.putExtra(AmbientContextManager.EXTRA_AMBIENT_CONTEXT_EVENT_RESPONSE, response);
+ intent.putExtra(AmbientContextManager.EXTRA_AMBIENT_CONTEXT_EVENTS,
+ new ArrayList(result.getEvents()));
// Explicitly disallow the receiver from starting activities, to prevent apps from utilizing
// the PendingIntent as a backdoor to do this.
BroadcastOptions options = BroadcastOptions.makeBasic();
@@ -254,38 +406,29 @@
pendingIntent.send(getContext(), 0, intent, null, null, null,
options.toBundle());
Slog.i(TAG, "Sending PendingIntent to " + pendingIntent.getCreatorPackage() + ": "
- + response);
+ + result);
} catch (PendingIntent.CanceledException e) {
Slog.w(TAG, "Couldn't deliver pendingIntent:" + pendingIntent);
}
}
@NonNull
- private RemoteCallback createRemoteCallback() {
+ private RemoteCallback createDetectionResultRemoteCallback() {
return new RemoteCallback(result -> {
- AmbientContextEventResponse response = (AmbientContextEventResponse) result.get(
- AmbientContextDetectionService.RESPONSE_BUNDLE_KEY);
+ AmbientContextDetectionResult detectionResult =
+ (AmbientContextDetectionResult) result.get(
+ AmbientContextDetectionResult.RESULT_RESPONSE_BUNDLE_KEY);
final long token = Binder.clearCallingIdentity();
try {
- Set<PendingIntent> pendingIntentForFailedRequests = new HashSet<>();
for (PendingIntent pendingIntent : mExistingPendingIntents) {
- // Send PendingIntent if a requesting package matches the response packages.
- if (response.getPackageName().equals(pendingIntent.getCreatorPackage())) {
- sendResponseIntent(pendingIntent, response);
-
- int statusCode = response.getStatusCode();
- if (statusCode != AmbientContextEventResponse.STATUS_SUCCESS) {
- pendingIntentForFailedRequests.add(pendingIntent);
- }
- Slog.i(TAG, "Got response of " + response.getEvents() + " for "
- + pendingIntent.getCreatorPackage() + ". Status: " + statusCode);
+ // Send PendingIntent to requesting packages
+ String creatorPackage = pendingIntent.getCreatorPackage();
+ if (detectionResult.getPackageName().equals(creatorPackage)) {
+ sendDetectionResultIntent(pendingIntent, detectionResult);
+ Slog.i(TAG, "Got detection result of " + detectionResult.getEvents()
+ + " for " + creatorPackage);
}
}
-
- // Removes the failed requests from the existing requests.
- for (PendingIntent pendingIntent : pendingIntentForFailedRequests) {
- mExistingPendingIntents.remove(pendingIntent);
- }
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java
index 33905f2..2cdf7e7 100644
--- a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java
+++ b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java
@@ -24,8 +24,8 @@
import android.app.PendingIntent;
import android.app.ambientcontext.AmbientContextEvent;
import android.app.ambientcontext.AmbientContextEventRequest;
-import android.app.ambientcontext.AmbientContextEventResponse;
-import android.app.ambientcontext.IAmbientContextEventObserver;
+import android.app.ambientcontext.AmbientContextManager;
+import android.app.ambientcontext.IAmbientContextManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManagerInternal;
@@ -76,7 +76,7 @@
@Override
public void onStart() {
- publishBinderService(Context.AMBIENT_CONTEXT_SERVICE, new AmbientContextEventObserver());
+ publishBinderService(Context.AMBIENT_CONTEXT_SERVICE, new AmbientContextManagerInternal());
}
@Override
@@ -128,14 +128,16 @@
* specified events. Intended for use by shell command for testing.
* Requires ACCESS_AMBIENT_CONTEXT_EVENT permission.
*/
- void startAmbientContextEvent(@UserIdInt int userId, AmbientContextEventRequest request,
- String packageName, RemoteCallback callback) {
+ void startDetection(@UserIdInt int userId, AmbientContextEventRequest request,
+ String packageName, RemoteCallback detectionResultCallback,
+ RemoteCallback statusCallback) {
mContext.enforceCallingOrSelfPermission(
Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT, TAG);
synchronized (mLock) {
final AmbientContextManagerPerUserService service = getServiceForUserLocked(userId);
if (service != null) {
- service.startDetection(request, packageName, callback);
+ service.startDetection(request, packageName, detectionResultCallback,
+ statusCallback);
} else {
Slog.i(TAG, "service not available for user_id: " + userId);
}
@@ -161,6 +163,25 @@
}
/**
+ * Send request to the remote AmbientContextDetectionService impl to query the status of the
+ * specified events. Intended for use by shell command for testing.
+ * Requires ACCESS_AMBIENT_CONTEXT_EVENT permission.
+ */
+ void queryServiceStatus(@UserIdInt int userId, String packageName,
+ int[] eventTypes, RemoteCallback callback) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT, TAG);
+ synchronized (mLock) {
+ final AmbientContextManagerPerUserService service = getServiceForUserLocked(userId);
+ if (service != null) {
+ service.onQueryServiceStatus(eventTypes, packageName, callback);
+ } else {
+ Slog.i(TAG, "query service not available for user_id: " + userId);
+ }
+ }
+ }
+
+ /**
* Returns the AmbientContextManagerPerUserService component for this user.
*/
public ComponentName getComponentName(@UserIdInt int userId) {
@@ -173,34 +194,65 @@
return null;
}
- private final class AmbientContextEventObserver extends IAmbientContextEventObserver.Stub {
+ private final class AmbientContextManagerInternal extends IAmbientContextManager.Stub {
final AmbientContextManagerPerUserService mService = getServiceForUserLocked(
UserHandle.getCallingUserId());
@Override
public void registerObserver(
- AmbientContextEventRequest request, PendingIntent pendingIntent) {
+ AmbientContextEventRequest request, PendingIntent resultPendingIntent,
+ RemoteCallback statusCallback) {
Objects.requireNonNull(request);
- Objects.requireNonNull(pendingIntent);
+ Objects.requireNonNull(resultPendingIntent);
+ Objects.requireNonNull(statusCallback);
mContext.enforceCallingOrSelfPermission(
Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT, TAG);
+ assertCalledByPackageOwner(resultPendingIntent.getCreatorPackage());
if (!mIsServiceEnabled) {
Slog.w(TAG, "Service not available.");
- mService.sendStatusUpdateIntent(pendingIntent,
- AmbientContextEventResponse.STATUS_SERVICE_UNAVAILABLE);
+ mService.sendStatusCallback(statusCallback,
+ AmbientContextManager.STATUS_SERVICE_UNAVAILABLE);
return;
}
- mService.onRegisterObserver(request, pendingIntent);
+ mService.onRegisterObserver(request, resultPendingIntent, statusCallback);
}
@Override
public void unregisterObserver(String callingPackage) {
mContext.enforceCallingOrSelfPermission(
Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT, TAG);
+ assertCalledByPackageOwner(callingPackage);
mService.onUnregisterObserver(callingPackage);
}
@Override
+ public void queryServiceStatus(int[] eventTypes, String callingPackage,
+ RemoteCallback statusCallback) {
+ Objects.requireNonNull(eventTypes);
+ Objects.requireNonNull(callingPackage);
+ Objects.requireNonNull(statusCallback);
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT, TAG);
+ assertCalledByPackageOwner(callingPackage);
+ if (!mIsServiceEnabled) {
+ Slog.w(TAG, "Detection service not available.");
+ mService.sendStatusToCallback(statusCallback,
+ AmbientContextManager.STATUS_SERVICE_UNAVAILABLE);
+ return;
+ }
+ mService.onQueryServiceStatus(eventTypes, callingPackage,
+ statusCallback);
+ }
+
+ @Override
+ public void startConsentActivity(int[] eventTypes, String callingPackage) {
+ Objects.requireNonNull(eventTypes);
+ Objects.requireNonNull(callingPackage);
+ assertCalledByPackageOwner(callingPackage);
+ mService.onStartConsentActivity(eventTypes, callingPackage);
+ }
+
+ @Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) {
return;
diff --git a/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java b/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java
index b5cd985..010bf1b 100644
--- a/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java
+++ b/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java
@@ -21,12 +21,12 @@
import android.annotation.NonNull;
import android.app.ambientcontext.AmbientContextEvent;
import android.app.ambientcontext.AmbientContextEventRequest;
-import android.app.ambientcontext.AmbientContextEventResponse;
import android.content.ComponentName;
import android.os.Binder;
import android.os.RemoteCallback;
import android.os.ShellCommand;
-import android.service.ambientcontext.AmbientContextDetectionService;
+import android.service.ambientcontext.AmbientContextDetectionResult;
+import android.service.ambientcontext.AmbientContextDetectionServiceStatus;
import java.io.PrintWriter;
@@ -35,6 +35,12 @@
*/
final class AmbientContextShellCommand extends ShellCommand {
+ private static final AmbientContextEventRequest REQUEST =
+ new AmbientContextEventRequest.Builder()
+ .addEventType(AmbientContextEvent.EVENT_COUGH)
+ .addEventType(AmbientContextEvent.EVENT_SNORE)
+ .build();
+
@NonNull
private final AmbientContextManagerService mService;
@@ -44,22 +50,43 @@
/** Callbacks for AmbientContextEventService results used internally for testing. */
static class TestableCallbackInternal {
- private AmbientContextEventResponse mLastResponse;
+ private AmbientContextDetectionResult mLastResult;
+ private AmbientContextDetectionServiceStatus mLastStatus;
- public AmbientContextEventResponse getLastResponse() {
- return mLastResponse;
+ public AmbientContextDetectionResult getLastResult() {
+ return mLastResult;
+ }
+
+ public AmbientContextDetectionServiceStatus getLastStatus() {
+ return mLastStatus;
}
@NonNull
- private RemoteCallback createRemoteCallback() {
+ private RemoteCallback createRemoteDetectionResultCallback() {
return new RemoteCallback(result -> {
- AmbientContextEventResponse response =
- (AmbientContextEventResponse) result.get(
- AmbientContextDetectionService.RESPONSE_BUNDLE_KEY);
+ AmbientContextDetectionResult detectionResult =
+ (AmbientContextDetectionResult) result.get(
+ AmbientContextDetectionResult.RESULT_RESPONSE_BUNDLE_KEY);
final long token = Binder.clearCallingIdentity();
try {
- mLastResponse = response;
- out.println("Response available: " + response);
+ mLastResult = detectionResult;
+ out.println("Detection result available: " + detectionResult);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ });
+ }
+
+ @NonNull
+ private RemoteCallback createRemoteStatusCallback() {
+ return new RemoteCallback(result -> {
+ AmbientContextDetectionServiceStatus status =
+ (AmbientContextDetectionServiceStatus) result.get(
+ AmbientContextDetectionServiceStatus.STATUS_RESPONSE_BUNDLE_KEY);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mLastStatus = status;
+ out.println("Status available: " + status);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -83,6 +110,8 @@
return runStopDetection();
case "get-last-status-code":
return getLastStatusCode();
+ case "query-service-status":
+ return runQueryServiceStatus();
case "get-bound-package":
return getBoundPackageName();
case "set-temporary-service":
@@ -95,13 +124,9 @@
private int runStartDetection() {
final int userId = Integer.parseInt(getNextArgRequired());
final String packageName = getNextArgRequired();
- AmbientContextEventRequest request = new AmbientContextEventRequest.Builder()
- .addEventType(AmbientContextEvent.EVENT_COUGH)
- .addEventType(AmbientContextEvent.EVENT_SNORE)
- .build();
-
- mService.startAmbientContextEvent(userId, request, packageName,
- sTestableCallbackInternal.createRemoteCallback());
+ mService.startDetection(userId, REQUEST, packageName,
+ sTestableCallbackInternal.createRemoteDetectionResultCallback(),
+ sTestableCallbackInternal.createRemoteStatusCallback());
return 0;
}
@@ -112,8 +137,20 @@
return 0;
}
+ private int runQueryServiceStatus() {
+ final int userId = Integer.parseInt(getNextArgRequired());
+ final String packageName = getNextArgRequired();
+ int[] types = new int[] {
+ AmbientContextEvent.EVENT_COUGH,
+ AmbientContextEvent.EVENT_SNORE};
+ mService.queryServiceStatus(userId, packageName, types,
+ sTestableCallbackInternal.createRemoteStatusCallback());
+ return 0;
+ }
+
private int getLastStatusCode() {
- AmbientContextEventResponse lastResponse = sTestableCallbackInternal.getLastResponse();
+ AmbientContextDetectionServiceStatus lastResponse =
+ sTestableCallbackInternal.getLastStatus();
if (lastResponse == null) {
return -1;
}
@@ -130,6 +167,7 @@
pw.println(" start-detection USER_ID PACKAGE_NAME: Starts AmbientContextEvent detection.");
pw.println(" stop-detection USER_ID: Stops AmbientContextEvent detection.");
pw.println(" get-last-status-code: Prints the latest request status code.");
+ pw.println(" query-event-status USER_ID PACKAGE_NAME: Prints the event status code.");
pw.println(" get-bound-package USER_ID:"
+ " Print the bound package that implements the service.");
pw.println(" set-temporary-service USER_ID [COMPONENT_NAME DURATION]");
diff --git a/services/core/java/com/android/server/ambientcontext/RemoteAmbientContextDetectionService.java b/services/core/java/com/android/server/ambientcontext/RemoteAmbientContextDetectionService.java
index 5cc29b3..f42080d 100644
--- a/services/core/java/com/android/server/ambientcontext/RemoteAmbientContextDetectionService.java
+++ b/services/core/java/com/android/server/ambientcontext/RemoteAmbientContextDetectionService.java
@@ -20,6 +20,7 @@
import static android.content.Context.BIND_INCLUDE_CAPABILITIES;
import android.annotation.NonNull;
+import android.app.ambientcontext.AmbientContextEvent;
import android.app.ambientcontext.AmbientContextEventRequest;
import android.content.ComponentName;
import android.content.Context;
@@ -53,13 +54,15 @@
*
* @param request The request with events to detect, and optional detection options.
* @param packageName The app package that requested the detection
- * @param callback callback for detection results
+ * @param detectionResultCallback callback for detection results
+ * @param statusCallback callback for service status
*/
public void startDetection(
@NonNull AmbientContextEventRequest request, String packageName,
- RemoteCallback callback) {
+ RemoteCallback detectionResultCallback, RemoteCallback statusCallback) {
Slog.i(TAG, "Start detection for " + request.getEventTypes());
- post(service -> service.startDetection(request, packageName, callback));
+ post(service -> service.startDetection(request, packageName, detectionResultCallback,
+ statusCallback));
}
/**
@@ -71,4 +74,15 @@
Slog.i(TAG, "Stop detection for " + packageName);
post(service -> service.stopDetection(packageName));
}
+
+ /**
+ * Asks the implementation to return the event status for the package.
+ */
+ public void queryServiceStatus(
+ @AmbientContextEvent.EventCode int[] eventTypes,
+ String packageName,
+ RemoteCallback callback) {
+ Slog.i(TAG, "Query status for " + packageName);
+ post(service -> service.queryServiceStatus(eventTypes, packageName, callback));
+ }
}
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index 551773e..9ba9d78 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -17,8 +17,8 @@
package com.android.server.app;
import static android.content.Intent.ACTION_PACKAGE_ADDED;
-import static android.content.Intent.ACTION_PACKAGE_CHANGED;
import static android.content.Intent.ACTION_PACKAGE_REMOVED;
+import static android.content.Intent.EXTRA_REPLACING;
import static com.android.internal.R.styleable.GameModeConfig_allowGameAngleDriver;
import static com.android.internal.R.styleable.GameModeConfig_allowGameDownscaling;
@@ -1467,7 +1467,6 @@
private void registerPackageReceiver() {
final IntentFilter packageFilter = new IntentFilter();
packageFilter.addAction(ACTION_PACKAGE_ADDED);
- packageFilter.addAction(ACTION_PACKAGE_CHANGED);
packageFilter.addAction(ACTION_PACKAGE_REMOVED);
packageFilter.addDataScheme("package");
final BroadcastReceiver packageReceiver = new BroadcastReceiver() {
@@ -1492,16 +1491,29 @@
}
switch (intent.getAction()) {
case ACTION_PACKAGE_ADDED:
- case ACTION_PACKAGE_CHANGED:
updateConfigsForUser(userId, packageName);
break;
case ACTION_PACKAGE_REMOVED:
disableCompatScale(packageName);
- synchronized (mOverrideConfigLock) {
- mOverrideConfigs.remove(packageName);
- }
- synchronized (mDeviceConfigLock) {
- mConfigs.remove(packageName);
+ // If EXTRA_REPLACING is true, it means there will be an
+ // ACTION_PACKAGE_ADDED triggered after this because this
+ // is an updated package that gets installed. Hence, disable
+ // resolution downscaling effort but avoid removing the server
+ // or commandline overriding configurations because those will
+ // not change but the package game mode configurations may change
+ // which may opt in and/or opt out some game mode configurations.
+ if (!intent.getBooleanExtra(EXTRA_REPLACING, false)) {
+ synchronized (mOverrideConfigLock) {
+ mOverrideConfigs.remove(packageName);
+ }
+ synchronized (mDeviceConfigLock) {
+ mConfigs.remove(packageName);
+ }
+ synchronized (mLock) {
+ if (mSettings.containsKey(userId)) {
+ mSettings.get(userId).removeGame(packageName);
+ }
+ }
}
break;
default:
diff --git a/services/core/java/com/android/server/app/GameManagerSettings.java b/services/core/java/com/android/server/app/GameManagerSettings.java
index 2982545..1455a61 100644
--- a/services/core/java/com/android/server/app/GameManagerSettings.java
+++ b/services/core/java/com/android/server/app/GameManagerSettings.java
@@ -93,6 +93,14 @@
}
/**
+ * Remove the game mode of a given package.
+ * This operation must be synced with an external lock.
+ */
+ void removeGame(String packageName) {
+ mGameModes.remove(packageName);
+ }
+
+ /**
* Write all current game service settings into disk.
* This operation must be synced with an external lock.
*/
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 40fda4c..cebcc64f 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -4549,6 +4549,26 @@
return new PackageVerificationResult(null,
/* isAttributionTagValid */ true);
}
+ if (Process.isSupplemental(uid)) {
+ // Supplemental processes run in their own UID range, but their associated
+ // UID for checks should always be the UID of the supplemental package.
+ // TODO: We will need to modify the callers of this function instead, so
+ // modifications and checks against the app ops state are done with the
+ // correct UID.
+ try {
+ final PackageManager pm = mContext.getPackageManager();
+ final String supplementalPackageName = pm.getSupplementalProcessPackageName();
+ if (Objects.equals(packageName, supplementalPackageName)) {
+ int supplementalAppId = pm.getPackageUid(supplementalPackageName,
+ PackageManager.PackageInfoFlags.of(0));
+ uid = UserHandle.getUid(UserHandle.getUserId(uid), supplementalAppId);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ // Shouldn't happen for the supplemental package
+ e.printStackTrace();
+ }
+ }
+
// Do not check if uid/packageName/attributionTag is already known.
synchronized (this) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 05955c3..3e5e435 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -22,6 +22,7 @@
import static android.media.AudioManager.RINGER_MODE_VIBRATE;
import static android.media.AudioManager.STREAM_SYSTEM;
import static android.os.Process.FIRST_APPLICATION_UID;
+import static android.os.Process.INVALID_UID;
import static android.provider.Settings.Secure.VOLUME_HUSH_MUTE;
import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
import static android.provider.Settings.Secure.VOLUME_HUSH_VIBRATE;
@@ -147,6 +148,7 @@
import android.telecom.TelecomManager;
import android.text.TextUtils;
import android.util.AndroidRuntimeException;
+import android.util.ArraySet;
import android.util.IntArray;
import android.util.Log;
import android.util.MathUtils;
@@ -329,6 +331,9 @@
private static final int MSG_ROUTING_UPDATED = 41;
private static final int MSG_INIT_HEADTRACKING_SENSORS = 42;
private static final int MSG_PERSIST_SPATIAL_AUDIO_ENABLED = 43;
+ private static final int MSG_ADD_ASSISTANT_SERVICE_UID = 44;
+ private static final int MSG_REMOVE_ASSISTANT_SERVICE_UID = 45;
+ private static final int MSG_UPDATE_ACTIVE_ASSISTANT_SERVICE_UID = 46;
// start of messages handled under wakelock
// these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
@@ -341,6 +346,9 @@
// retry delay in case of failure to indicate system ready to AudioFlinger
private static final int INDICATE_SYSTEM_READY_RETRY_DELAY_MS = 1000;
+ // List of empty UIDs used to reset the active assistant list
+ private static final int[] NO_ACTIVE_ASSISTANT_SERVICE_UIDS = new int[0];
+
/** @see AudioSystemThread */
private AudioSystemThread mAudioSystemThread;
/** @see AudioHandler */
@@ -756,10 +764,15 @@
private VolumePolicy mVolumePolicy = VolumePolicy.DEFAULT;
private long mLoweredFromNormalToVibrateTime;
- // Uid of the active hotword detection service to check if caller is the one or not.
- @GuardedBy("mHotwordDetectionServiceUidLock")
- private int mHotwordDetectionServiceUid = android.os.Process.INVALID_UID;
- private final Object mHotwordDetectionServiceUidLock = new Object();
+ // Array of Uids of valid assistant services to check if caller is one of them
+ @GuardedBy("mSettingsLock")
+ private final ArraySet<Integer> mAssistantUids = new ArraySet<>();
+ @GuardedBy("mSettingsLock")
+ private int mPrimaryAssistantUid = INVALID_UID;
+
+ // Array of Uids of valid active assistant service to check if caller is one of them
+ @GuardedBy("mSettingsLock")
+ private int[] mActiveAssistantServiceUids = NO_ACTIVE_ASSISTANT_SERVICE_UIDS;
// Array of Uids of valid accessibility services to check if caller is one of them
private final Object mAccessibilityServiceUidsLock = new Object();
@@ -787,9 +800,6 @@
private boolean mHomeSoundEffectEnabled;
@GuardedBy("mSettingsLock")
- private int mAssistantUid;
-
- @GuardedBy("mSettingsLock")
private int mCurrentImeUid;
private final Object mSupportedSystemUsagesLock = new Object();
@@ -1395,12 +1405,10 @@
mDeviceBroker.setForceUse_Async(AudioSystem.FOR_DOCK, forDock, "onAudioServerDied");
sendEncodedSurroundMode(mContentResolver, "onAudioServerDied");
sendEnabledSurroundFormats(mContentResolver, true);
- updateAssistantUId(true);
AudioSystem.setRttEnabled(mRttEnabled);
+ updateAssistantServicesUidsLocked();
}
- synchronized (mHotwordDetectionServiceUidLock) {
- AudioSystem.setHotwordDetectionServiceUid(mHotwordDetectionServiceUid);
- }
+
synchronized (mAccessibilityServiceUidsLock) {
AudioSystem.setA11yServicesUids(mAccessibilityServiceUids);
}
@@ -1478,6 +1486,68 @@
updateVibratorInfos();
}
+ private void onRemoveAssistantServiceUids(int[] uids) {
+ synchronized (mSettingsLock) {
+ removeAssistantServiceUidsLocked(uids);
+ }
+ }
+
+ @GuardedBy("mSettingsLock")
+ private void removeAssistantServiceUidsLocked(int[] uids) {
+ boolean changed = false;
+ for (int index = 0; index < uids.length; index++) {
+ if (!mAssistantUids.remove(uids[index])) {
+ Slog.e(TAG, TextUtils.formatSimple(
+ "Cannot remove assistant service, uid(%d) not present", uids[index]));
+ continue;
+ }
+ changed = true;
+ }
+ if (changed) {
+ updateAssistantServicesUidsLocked();
+ }
+ }
+
+ private void onAddAssistantServiceUids(int[] uids) {
+ synchronized (mSettingsLock) {
+ addAssistantServiceUidsLocked(uids);
+ }
+ }
+
+ @GuardedBy("mSettingsLock")
+ private void addAssistantServiceUidsLocked(int[] uids) {
+ boolean changed = false;
+ for (int index = 0; index < uids.length; index++) {
+ if (uids[index] == INVALID_UID) {
+ continue;
+ }
+ if (!mAssistantUids.add(uids[index])) {
+ Slog.e(TAG, TextUtils.formatSimple(
+ "Cannot add assistant service, uid(%d) already present",
+ uids[index]));
+ continue;
+ }
+ changed = true;
+ }
+ if (changed) {
+ updateAssistantServicesUidsLocked();
+ }
+ }
+
+ @GuardedBy("mSettingsLock")
+ private void updateAssistantServicesUidsLocked() {
+ int[] assistantUids = mAssistantUids.stream().mapToInt(Integer::intValue).toArray();
+ AudioSystem.setAssistantServicesUids(assistantUids);
+ }
+
+ private void updateActiveAssistantServiceUids() {
+ int [] activeAssistantServiceUids;
+ synchronized (mSettingsLock) {
+ activeAssistantServiceUids = mActiveAssistantServiceUids;
+ }
+ AudioSystem.setActiveAssistantServicesUids(activeAssistantServiceUids);
+ }
+
private void onReinitVolumes(@NonNull String caller) {
final int numStreamTypes = AudioSystem.getNumStreamTypes();
// keep track of any error during stream volume initialization
@@ -2243,8 +2313,7 @@
@GuardedBy("mSettingsLock")
private void updateAssistantUId(boolean forceUpdate) {
- int assistantUid = 0;
-
+ int assistantUid = INVALID_UID;
// Consider assistants in the following order of priority:
// 1) apk in assistant role
// 2) voice interaction service
@@ -2288,10 +2357,10 @@
}
}
}
-
- if (assistantUid != mAssistantUid || forceUpdate) {
- AudioSystem.setAssistantUid(assistantUid);
- mAssistantUid = assistantUid;
+ if ((mPrimaryAssistantUid != assistantUid) || forceUpdate) {
+ mAssistantUids.remove(mPrimaryAssistantUid);
+ mPrimaryAssistantUid = assistantUid;
+ addAssistantServiceUidsLocked(new int[]{mPrimaryAssistantUid});
}
}
@@ -2342,6 +2411,7 @@
sendEncodedSurroundMode(cr, "readPersistedSettings");
sendEnabledSurroundFormats(cr, true);
updateAssistantUId(true);
+ resetActiveAssistantUidsLocked();
AudioSystem.setRttEnabled(mRttEnabled);
}
@@ -2367,6 +2437,12 @@
mVolumeController.loadSettings(cr);
}
+ @GuardedBy("mSettingsLock")
+ private void resetActiveAssistantUidsLocked() {
+ mActiveAssistantServiceUids = NO_ACTIVE_ASSISTANT_SERVICE_UIDS;
+ updateActiveAssistantServiceUids();
+ }
+
private void readUserRestrictions() {
if (!mSystemServer.isPrivileged()) {
return;
@@ -2892,8 +2968,9 @@
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;
}
@@ -3031,7 +3108,8 @@
}
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);
@@ -3631,8 +3709,9 @@
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;
}
@@ -3675,7 +3754,8 @@
}
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);
@@ -7843,6 +7923,17 @@
case MSG_PERSIST_SPATIAL_AUDIO_ENABLED:
onPersistSpatialAudioEnabled(msg.arg1 == 1);
break;
+
+ case MSG_ADD_ASSISTANT_SERVICE_UID:
+ onAddAssistantServiceUids(new int[]{msg.arg1});
+ break;
+
+ case MSG_REMOVE_ASSISTANT_SERVICE_UID:
+ onRemoveAssistantServiceUids(new int[]{msg.arg1});
+ break;
+ case MSG_UPDATE_ACTIVE_ASSISTANT_SERVICE_UID:
+ updateActiveAssistantServiceUids();
+ break;
}
}
}
@@ -8483,6 +8574,30 @@
return mSpatializerHelper.isAvailable();
}
+ /** @see Spatializer#isAvailableForDevice(AudioDeviceAttributes) */
+ public boolean isSpatializerAvailableForDevice(@NonNull AudioDeviceAttributes device) {
+ enforceModifyDefaultAudioEffectsPermission();
+ return mSpatializerHelper.isAvailableForDevice(Objects.requireNonNull(device));
+ }
+
+ /** @see Spatializer#hasHeadTracker(AudioDeviceAttributes) */
+ public boolean hasHeadTracker(@NonNull AudioDeviceAttributes device) {
+ enforceModifyDefaultAudioEffectsPermission();
+ return mSpatializerHelper.hasHeadTracker(Objects.requireNonNull(device));
+ }
+
+ /** @see Spatializer#setHeadTrackerEnabled(boolean, AudioDeviceAttributes) */
+ public void setHeadTrackerEnabled(boolean enabled, @NonNull AudioDeviceAttributes device) {
+ enforceModifyDefaultAudioEffectsPermission();
+ mSpatializerHelper.setHeadTrackerEnabled(enabled, Objects.requireNonNull(device));
+ }
+
+ /** @see Spatializer#isHeadTrackerEnabled(AudioDeviceAttributes) */
+ public boolean isHeadTrackerEnabled(@NonNull AudioDeviceAttributes device) {
+ enforceModifyDefaultAudioEffectsPermission();
+ return mSpatializerHelper.isHeadTrackerEnabled(Objects.requireNonNull(device));
+ }
+
/** @see Spatializer#setSpatializerEnabled(boolean) */
public void setSpatializerEnabled(boolean enabled) {
enforceModifyDefaultAudioEffectsPermission();
@@ -9351,7 +9466,7 @@
pw.print(" mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
pw.print(" mMusicActiveMs="); pw.println(mMusicActiveMs);
pw.print(" mMcc="); pw.println(mMcc);
- pw.print(" mCameraSoundForced="); pw.println(mCameraSoundForced);
+ pw.print(" mCameraSoundForced="); pw.println(isCameraSoundForced());
pw.print(" mHasVibrator="); pw.println(mHasVibrator);
pw.print(" mVolumePolicy="); pw.println(mVolumePolicy);
pw.print(" mAvrcpAbsVolSupported="); pw.println(mAvrcpAbsVolSupported);
@@ -9371,9 +9486,9 @@
+ " FromRestrictions=" + mMicMuteFromRestrictions
+ " FromApi=" + mMicMuteFromApi
+ " from system=" + mMicMuteFromSystemCached);
- pw.print("\n mAssistantUid="); pw.println(mAssistantUid);
pw.print(" mCurrentImeUid="); pw.println(mCurrentImeUid);
dumpAccessibilityServiceUids(pw);
+ dumpAssistantServicesUids(pw);
dumpAudioPolicies(pw);
mDynPolicyLogger.dump(pw);
@@ -9416,6 +9531,19 @@
}
}
+ private void dumpAssistantServicesUids(PrintWriter pw) {
+ synchronized (mSettingsLock) {
+ if (mAssistantUids.size() > 0) {
+ pw.println(" Assistant service UIDs:");
+ for (int uid : mAssistantUids) {
+ pw.println(" - " + uid);
+ }
+ } else {
+ pw.println(" No Assistant service Uids.");
+ }
+ }
+ }
+
private void dumpAccessibilityServiceUids(PrintWriter pw) {
synchronized (mSupportedSystemUsagesLock) {
if (mAccessibilityServiceUids != null && mAccessibilityServiceUids.length > 0) {
@@ -9714,13 +9842,40 @@
}
@Override
- public void setHotwordDetectionServiceUid(int uid) {
- synchronized (mHotwordDetectionServiceUidLock) {
- if (mHotwordDetectionServiceUid != uid) {
- mHotwordDetectionServiceUid = uid;
- AudioSystem.setHotwordDetectionServiceUid(mHotwordDetectionServiceUid);
+ public void addAssistantServiceUid(int uid) {
+ sendMsg(mAudioHandler, MSG_ADD_ASSISTANT_SERVICE_UID, SENDMSG_QUEUE,
+ uid, 0, null, 0);
+ }
+
+ @Override
+ public void removeAssistantServiceUid(int uid) {
+ sendMsg(mAudioHandler, MSG_REMOVE_ASSISTANT_SERVICE_UID, SENDMSG_QUEUE,
+ uid, 0, null, 0);
+ }
+
+ @Override
+ public void setActiveAssistantServicesUids(IntArray activeUids) {
+ synchronized (mSettingsLock) {
+ if (activeUids.size() == 0) {
+ mActiveAssistantServiceUids = NO_ACTIVE_ASSISTANT_SERVICE_UIDS;
+ } else {
+ boolean changed = (mActiveAssistantServiceUids == null)
+ || (mActiveAssistantServiceUids.length != activeUids.size());
+ if (!changed) {
+ for (int i = 0; i < mActiveAssistantServiceUids.length; i++) {
+ if (activeUids.get(i) != mActiveAssistantServiceUids[i]) {
+ changed = true;
+ break;
+ }
+ }
+ }
+ if (changed) {
+ mActiveAssistantServiceUids = activeUids.toArray();
+ }
}
}
+ sendMsg(mAudioHandler, MSG_UPDATE_ACTIVE_ASSISTANT_SERVICE_UID, SENDMSG_REPLACE,
+ 0, 0, null, 0);
}
@Override
@@ -11017,6 +11172,59 @@
return delayMillis;
}
+ /** @see AudioManager#addAssistantServicesUids(int []) */
+ @Override
+ public void addAssistantServicesUids(int [] assistantUids) {
+ enforceModifyAudioRoutingPermission();
+ Objects.requireNonNull(assistantUids);
+
+ synchronized (mSettingsLock) {
+ addAssistantServiceUidsLocked(assistantUids);
+ }
+ }
+
+ /** @see AudioManager#removeAssistantServicesUids(int []) */
+ @Override
+ public void removeAssistantServicesUids(int [] assistantUids) {
+ enforceModifyAudioRoutingPermission();
+ Objects.requireNonNull(assistantUids);
+ synchronized (mSettingsLock) {
+ removeAssistantServiceUidsLocked(assistantUids);
+ }
+ }
+
+ /** @see AudioManager#getAssistantServicesUids() */
+ @Override
+ public int[] getAssistantServicesUids() {
+ enforceModifyAudioRoutingPermission();
+ int [] assistantUids;
+ synchronized (mSettingsLock) {
+ assistantUids = mAssistantUids.stream().mapToInt(Integer::intValue).toArray();
+ }
+ return assistantUids;
+ }
+
+ /** @see AudioManager#setActiveAssistantServiceUids(int []) */
+ @Override
+ public void setActiveAssistantServiceUids(int [] activeAssistantUids) {
+ enforceModifyAudioRoutingPermission();
+ synchronized (mSettingsLock) {
+ mActiveAssistantServiceUids = activeAssistantUids;
+ }
+ updateActiveAssistantServiceUids();
+ }
+
+ /** @see AudioManager#getActiveAssistantServiceUids() */
+ @Override
+ public int[] getActiveAssistantServiceUids() {
+ enforceModifyAudioRoutingPermission();
+ int [] activeAssistantUids;
+ synchronized (mSettingsLock) {
+ activeAssistantUids = mActiveAssistantServiceUids.clone();
+ }
+ return activeAssistantUids;
+ }
+
UUID getDeviceSensorUuid(AudioDeviceAttributes device) {
return mDeviceBroker.getDeviceSensorUuid(device);
}
diff --git a/services/core/java/com/android/server/audio/AudioSystemAdapter.java b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
index f572261..a70b470 100644
--- a/services/core/java/com/android/server/audio/AudioSystemAdapter.java
+++ b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
@@ -387,14 +387,6 @@
}
/**
- * Same as {@link AudioSystem#setHotwordDetectionServiceUid(int)}
- * Communicate UID of current HotwordDetectionService to audio policy service.
- */
- public int setHotwordDetectionServiceUid(int uid) {
- return AudioSystem.setHotwordDetectionServiceUid(uid);
- }
-
- /**
* Same as {@link AudioSystem#setCurrentImeUid(int)}
* Communicate UID of current InputMethodService to audio policy service.
*/
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index 106cbba..63b27d8 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -23,6 +23,7 @@
import android.hardware.SensorManager;
import android.media.AudioAttributes;
import android.media.AudioDeviceAttributes;
+import android.media.AudioDeviceInfo;
import android.media.AudioFormat;
import android.media.AudioSystem;
import android.media.INativeSpatializerCallback;
@@ -33,11 +34,14 @@
import android.media.ISpatializerHeadTrackingModeCallback;
import android.media.ISpatializerOutputCallback;
import android.media.SpatializationLevel;
+import android.media.SpatializationMode;
import android.media.Spatializer;
import android.media.SpatializerHeadTrackingMode;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;
+import android.util.Pair;
+import android.util.SparseIntArray;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -69,10 +73,42 @@
// TODO: replace with generic head tracker sensor name.
// the current implementation refers to the "google" namespace but will be replaced
// by an android name at the next API level revision, it is not Google-specific.
- // Also see "TODO-HT" in onInitSensors() method
private static final String HEADTRACKER_SENSOR =
"com.google.hardware.sensor.hid_dynamic.headtracker";
+ private static final SparseIntArray SPAT_MODE_FOR_DEVICE_TYPE = new SparseIntArray(15) {
+ {
+ append(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, SpatializationMode.SPATIALIZER_TRANSAURAL);
+ append(AudioDeviceInfo.TYPE_WIRED_HEADSET, SpatializationMode.SPATIALIZER_BINAURAL);
+ append(AudioDeviceInfo.TYPE_WIRED_HEADPHONES, SpatializationMode.SPATIALIZER_BINAURAL);
+ // assumption for A2DP: mostly headsets
+ append(AudioDeviceInfo.TYPE_BLUETOOTH_A2DP, SpatializationMode.SPATIALIZER_BINAURAL);
+ append(AudioDeviceInfo.TYPE_DOCK, SpatializationMode.SPATIALIZER_TRANSAURAL);
+ append(AudioDeviceInfo.TYPE_USB_ACCESSORY, SpatializationMode.SPATIALIZER_TRANSAURAL);
+ append(AudioDeviceInfo.TYPE_USB_DEVICE, SpatializationMode.SPATIALIZER_TRANSAURAL);
+ append(AudioDeviceInfo.TYPE_USB_HEADSET, SpatializationMode.SPATIALIZER_BINAURAL);
+ append(AudioDeviceInfo.TYPE_LINE_ANALOG, SpatializationMode.SPATIALIZER_TRANSAURAL);
+ append(AudioDeviceInfo.TYPE_LINE_DIGITAL, SpatializationMode.SPATIALIZER_TRANSAURAL);
+ append(AudioDeviceInfo.TYPE_AUX_LINE, SpatializationMode.SPATIALIZER_TRANSAURAL);
+ append(AudioDeviceInfo.TYPE_HEARING_AID, SpatializationMode.SPATIALIZER_BINAURAL);
+ append(AudioDeviceInfo.TYPE_BLE_HEADSET, SpatializationMode.SPATIALIZER_BINAURAL);
+ append(AudioDeviceInfo.TYPE_BLE_SPEAKER, SpatializationMode.SPATIALIZER_TRANSAURAL);
+ // assumption that BLE broadcast would be mostly consumed on headsets
+ append(AudioDeviceInfo.TYPE_BLE_BROADCAST, SpatializationMode.SPATIALIZER_BINAURAL);
+ }
+ };
+
+ private static final int[] WIRELESS_TYPES = { AudioDeviceInfo.TYPE_BLUETOOTH_SCO,
+ AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
+ AudioDeviceInfo.TYPE_BLE_HEADSET,
+ AudioDeviceInfo.TYPE_BLE_SPEAKER,
+ AudioDeviceInfo.TYPE_BLE_BROADCAST
+ };
+
+ private static final int[] WIRELESS_SPEAKER_TYPES = {
+ AudioDeviceInfo.TYPE_BLE_SPEAKER,
+ };
+
// Spatializer state machine
private static final int STATE_UNINITIALIZED = 0;
private static final int STATE_NOT_SUPPORTED = 1;
@@ -82,11 +118,20 @@
private static final int STATE_DISABLED_AVAILABLE = 6;
private int mState = STATE_UNINITIALIZED;
+ private boolean mFeatureEnabled = false;
/** current level as reported by native Spatializer in callback */
private int mSpatLevel = Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
private int mCapableSpatLevel = Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
+ private boolean mTransauralSupported = false;
+ private boolean mBinauralSupported = false;
private int mActualHeadTrackingMode = Spatializer.HEAD_TRACKING_MODE_UNSUPPORTED;
private int mDesiredHeadTrackingMode = Spatializer.HEAD_TRACKING_MODE_RELATIVE_WORLD;
+ /**
+ * The desired head tracking mode when enabling head tracking, tracks mDesiredHeadTrackingMode,
+ * except when head tracking gets disabled through setting the desired mode to
+ * {@link Spatializer#HEAD_TRACKING_MODE_DISABLED}.
+ */
+ private int mDesiredHeadTrackingModeWhenEnabled = Spatializer.HEAD_TRACKING_MODE_RELATIVE_WORLD;
private int mSpatOutput = 0;
private @Nullable ISpatializer mSpat;
private @Nullable SpatializerCallback mSpatCallback;
@@ -108,8 +153,18 @@
//---------------------------------------------------------------
// audio device compatibility / enabled
+ /**
+ * List of device types that can be used on this device with Spatial Audio.
+ * It is initialized based on the transaural/binaural capabilities
+ * of the effect.
+ */
+ private final ArrayList<Integer> mSACapableDeviceTypes = new ArrayList<>(0);
- private final ArrayList<AudioDeviceAttributes> mCompatibleAudioDevices = new ArrayList<>(0);
+ /**
+ * List of devices where Spatial Audio is possible. Each device can be enabled or disabled
+ * (== user choice to use or not)
+ */
+ private final ArrayList<SADeviceState> mSADevices = new ArrayList<>(0);
//------------------------------------------------------
// initialization
@@ -155,6 +210,46 @@
break;
}
}
+ byte[] spatModes = spat.getSupportedModes();
+ for (byte mode : spatModes) {
+ switch (mode) {
+ case SpatializationMode.SPATIALIZER_BINAURAL:
+ mBinauralSupported = true;
+ break;
+ case SpatializationMode.SPATIALIZER_TRANSAURAL:
+ mTransauralSupported = true;
+ break;
+ default:
+ Log.e(TAG, "Spatializer reports unknown supported mode:" + mode);
+ break;
+ }
+ }
+ // if neither transaural nor binaural is supported, bail
+ if (!mBinauralSupported && !mTransauralSupported) {
+ mState = STATE_NOT_SUPPORTED;
+ return;
+ }
+
+ // initialize list of compatible devices
+ for (int i = 0; i < SPAT_MODE_FOR_DEVICE_TYPE.size(); i++) {
+ int mode = SPAT_MODE_FOR_DEVICE_TYPE.valueAt(i);
+ if ((mode == (int) SpatializationMode.SPATIALIZER_BINAURAL && mBinauralSupported)
+ || (mode == (int) SpatializationMode.SPATIALIZER_TRANSAURAL
+ && mTransauralSupported)) {
+ mSACapableDeviceTypes.add(SPAT_MODE_FOR_DEVICE_TYPE.keyAt(i));
+ }
+ }
+ if (mTransauralSupported) {
+ // TODO deal with persisted values
+ mSADevices.add(
+ new SADeviceState(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, null));
+ }
+ if (mBinauralSupported) {
+ // TODO deal with persisted values
+ mSADevices.add(
+ new SADeviceState(AudioDeviceInfo.TYPE_WIRED_HEADPHONES, null));
+ }
+ // TODO read persisted states
} catch (RemoteException e) {
/* capable level remains at NONE*/
} finally {
@@ -184,12 +279,15 @@
mCapableSpatLevel = Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
mActualHeadTrackingMode = Spatializer.HEAD_TRACKING_MODE_UNSUPPORTED;
init(true);
- setFeatureEnabled(featureEnabled);
+ setSpatializerEnabledInt(featureEnabled);
}
//------------------------------------------------------
// routing monitoring
- void onRoutingUpdated() {
+ synchronized void onRoutingUpdated() {
+ if (!mFeatureEnabled) {
+ return;
+ }
switch (mState) {
case STATE_UNINITIALIZED:
case STATE_NOT_SUPPORTED:
@@ -201,11 +299,36 @@
break;
}
mASA.getDevicesForAttributes(DEFAULT_ATTRIBUTES).toArray(ROUTING_DEVICES);
- final boolean able =
- AudioSystem.canBeSpatialized(DEFAULT_ATTRIBUTES, DEFAULT_FORMAT, ROUTING_DEVICES);
- logd("onRoutingUpdated: can spatialize media 5.1:" + able
- + " on device:" + ROUTING_DEVICES[0]);
- setDispatchAvailableState(able);
+
+ // is media routed to a new device?
+ if (isWireless(ROUTING_DEVICES[0].getType())) {
+ addWirelessDeviceIfNew(ROUTING_DEVICES[0]);
+ }
+
+ // find if media device enabled / available
+ final Pair<Boolean, Boolean> enabledAvailable = evaluateState(ROUTING_DEVICES[0]);
+
+ boolean able = false;
+ if (enabledAvailable.second) {
+ // available for Spatial audio, check w/ effect
+ able = canBeSpatializedOnDevice(DEFAULT_ATTRIBUTES, DEFAULT_FORMAT, ROUTING_DEVICES);
+ Log.i(TAG, "onRoutingUpdated: can spatialize media 5.1:" + able
+ + " on device:" + ROUTING_DEVICES[0]);
+ setDispatchAvailableState(able);
+ } else {
+ Log.i(TAG, "onRoutingUpdated: device:" + ROUTING_DEVICES[0]
+ + " not available for Spatial Audio");
+ setDispatchAvailableState(false);
+ }
+
+ if (able && enabledAvailable.first) {
+ Log.i(TAG, "Enabling Spatial Audio since enabled for media device:"
+ + ROUTING_DEVICES[0]);
+ } else {
+ Log.i(TAG, "Disabling Spatial Audio since disabled for media device:"
+ + ROUTING_DEVICES[0]);
+ }
+ setDispatchFeatureEnabledState(able && enabledAvailable.first);
if (mDesiredHeadTrackingMode != Spatializer.HEAD_TRACKING_MODE_UNSUPPORTED
&& mDesiredHeadTrackingMode != Spatializer.HEAD_TRACKING_MODE_DISABLED) {
@@ -298,20 +421,145 @@
//------------------------------------------------------
// compatible devices
/**
- * @return a shallow copy of the list of compatible audio devices
+ * Return the list of compatible devices, which reflects the device compatible with the
+ * spatializer effect, and those that have been explicitly enabled or disabled
+ * @return the list of compatible audio devices
*/
synchronized @NonNull List<AudioDeviceAttributes> getCompatibleAudioDevices() {
- return (List<AudioDeviceAttributes>) mCompatibleAudioDevices.clone();
+ // build unionOf(mCompatibleAudioDevices, mEnabledDevice) - mDisabledAudioDevices
+ ArrayList<AudioDeviceAttributes> compatList = new ArrayList<>();
+ for (SADeviceState dev : mSADevices) {
+ if (dev.mEnabled) {
+ compatList.add(new AudioDeviceAttributes(AudioDeviceAttributes.ROLE_OUTPUT,
+ dev.mDeviceType, dev.mDeviceAddress == null ? "" : dev.mDeviceAddress));
+ }
+ }
+ return compatList;
}
synchronized void addCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada) {
- if (!mCompatibleAudioDevices.contains(ada)) {
- mCompatibleAudioDevices.add(ada);
+ // TODO add log
+ final int deviceType = ada.getType();
+ final boolean wireless = isWireless(deviceType);
+ boolean updateRouting = false;
+ boolean isInList = false;
+
+ for (SADeviceState deviceState : mSADevices) {
+ if (deviceType == deviceState.mDeviceType
+ && (wireless && ada.getAddress().equals(deviceState.mDeviceAddress))
+ || !wireless) {
+ isInList = true;
+ // state change?
+ updateRouting = !deviceState.mEnabled;
+ deviceState.mEnabled = true;
+ break;
+ }
+ }
+ if (!isInList) {
+ final SADeviceState dev = new SADeviceState(deviceType,
+ wireless ? ada.getAddress() : null);
+ dev.mEnabled = true;
+ mSADevices.add(dev);
+ updateRouting = true;
+ }
+ if (updateRouting) {
+ onRoutingUpdated();
}
}
synchronized void removeCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada) {
- mCompatibleAudioDevices.remove(ada);
+ // TODO add log
+ final int deviceType = ada.getType();
+ final boolean wireless = isWireless(deviceType);
+ boolean updateRouting = false;
+
+ for (SADeviceState deviceState : mSADevices) {
+ if (deviceType == deviceState.mDeviceType
+ && (wireless && ada.getAddress().equals(deviceState.mDeviceAddress))
+ || !wireless) {
+ // state change?
+ updateRouting = deviceState.mEnabled;
+ deviceState.mEnabled = false;
+ break;
+ }
+ }
+ if (updateRouting) {
+ onRoutingUpdated();
+ }
+ }
+
+ /**
+ * Return if Spatial Audio is enabled and available for the given device
+ * @param ada
+ * @return a pair of boolean, 1/ enabled? 2/ available?
+ */
+ private synchronized Pair<Boolean, Boolean> evaluateState(AudioDeviceAttributes ada) {
+ // if not a wireless device, this value will be overwritten to map the type
+ // to TYPE_BUILTIN_SPEAKER or TYPE_WIRED_HEADPHONES
+ int deviceType = ada.getType();
+ final boolean wireless = isWireless(deviceType);
+
+ // if not a wireless device: find if media device is in the speaker, wired headphones
+ if (!wireless) {
+ // is the device type capable of doing SA?
+ if (!mSACapableDeviceTypes.contains(deviceType)) {
+ Log.i(TAG, "Device incompatible with Spatial Audio dev:" + ada);
+ return new Pair<>(false, false);
+ }
+ // what spatialization mode to use for this device?
+ final int spatMode = SPAT_MODE_FOR_DEVICE_TYPE.get(deviceType, Integer.MIN_VALUE);
+ if (spatMode == Integer.MIN_VALUE) {
+ // error case, device not found
+ Log.e(TAG, "no spatialization mode found for device type:" + deviceType);
+ return new Pair<>(false, false);
+ }
+ // map the spatialization mode to the SPEAKER or HEADPHONES device
+ if (spatMode == SpatializationMode.SPATIALIZER_TRANSAURAL) {
+ deviceType = AudioDeviceInfo.TYPE_BUILTIN_SPEAKER;
+ } else {
+ deviceType = AudioDeviceInfo.TYPE_WIRED_HEADPHONES;
+ }
+ } else { // wireless device
+ if (isWirelessSpeaker(deviceType) && !mTransauralSupported) {
+ Log.i(TAG, "Device incompatible with Spatial Audio (no transaural) dev:"
+ + ada);
+ return new Pair<>(false, false);
+ }
+ if (!mBinauralSupported) {
+ Log.i(TAG, "Device incompatible with Spatial Audio (no binaural) dev:"
+ + ada);
+ return new Pair<>(false, false);
+ }
+ }
+
+ boolean enabled = false;
+ boolean available = false;
+ for (SADeviceState deviceState : mSADevices) {
+ if (deviceType == deviceState.mDeviceType
+ && (wireless && ada.getAddress().equals(deviceState.mDeviceAddress))
+ || !wireless) {
+ available = true;
+ enabled = deviceState.mEnabled;
+ break;
+ }
+ }
+ return new Pair<>(enabled, available);
+ }
+
+ private synchronized void addWirelessDeviceIfNew(@NonNull AudioDeviceAttributes ada) {
+ boolean knownDevice = false;
+ for (SADeviceState deviceState : mSADevices) {
+ // wireless device so always check address
+ if (ada.getType() == deviceState.mDeviceType
+ && ada.getAddress().equals(deviceState.mDeviceAddress)) {
+ knownDevice = true;
+ break;
+ }
+ }
+ if (!knownDevice) {
+ mSADevices.add(new SADeviceState(ada.getType(), ada.getAddress()));
+ //### TODO persist list
+ }
}
//------------------------------------------------------
@@ -345,7 +593,56 @@
}
}
+ synchronized boolean isAvailableForDevice(@NonNull AudioDeviceAttributes ada) {
+ if (ada.getRole() != AudioDeviceAttributes.ROLE_OUTPUT) {
+ return false;
+ }
+
+ final int deviceType = ada.getType();
+ final boolean wireless = isWireless(deviceType);
+ for (SADeviceState deviceState : mSADevices) {
+ if (deviceType == deviceState.mDeviceType
+ && (wireless && ada.getAddress().equals(deviceState.mDeviceAddress))
+ || !wireless) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private synchronized boolean canBeSpatializedOnDevice(@NonNull AudioAttributes attributes,
+ @NonNull AudioFormat format, @NonNull AudioDeviceAttributes[] devices) {
+ final byte modeForDevice = (byte) SPAT_MODE_FOR_DEVICE_TYPE.get(devices[0].getType(),
+ /*default when type not found*/ SpatializationMode.SPATIALIZER_BINAURAL);
+ if ((modeForDevice == SpatializationMode.SPATIALIZER_BINAURAL && mBinauralSupported)
+ || (modeForDevice == SpatializationMode.SPATIALIZER_TRANSAURAL
+ && mTransauralSupported)) {
+ return AudioSystem.canBeSpatialized(attributes, format, devices);
+ }
+ return false;
+ }
+
synchronized void setFeatureEnabled(boolean enabled) {
+ if (mFeatureEnabled == enabled) {
+ return;
+ }
+ mFeatureEnabled = enabled;
+ if (mFeatureEnabled) {
+ if (mState == STATE_NOT_SUPPORTED) {
+ Log.e(TAG, "Can't enabled Spatial Audio, unsupported");
+ return;
+ }
+ if (mState == STATE_UNINITIALIZED) {
+ init(true);
+ }
+ setSpatializerEnabledInt(true);
+ onRoutingUpdated();
+ } else {
+ setSpatializerEnabledInt(false);
+ }
+ }
+
+ synchronized void setSpatializerEnabledInt(boolean enabled) {
switch (mState) {
case STATE_UNINITIALIZED:
if (enabled) {
@@ -397,8 +694,7 @@
}
/**
- * precondition: mState = STATE_*
- * isFeatureEnabled() != featureEnabled
+ * Update the feature state, no-op if no change
* @param featureEnabled
*/
private synchronized void setDispatchFeatureEnabledState(boolean featureEnabled) {
@@ -410,6 +706,10 @@
case STATE_DISABLED_AVAILABLE:
mState = STATE_ENABLED_AVAILABLE;
break;
+ case STATE_ENABLED_AVAILABLE:
+ case STATE_ENABLED_UNAVAILABLE:
+ // already enabled: no-op
+ return;
default:
throw(new IllegalStateException("Invalid mState:" + mState
+ " for enabled true"));
@@ -422,6 +722,10 @@
case STATE_ENABLED_AVAILABLE:
mState = STATE_DISABLED_AVAILABLE;
break;
+ case STATE_DISABLED_AVAILABLE:
+ case STATE_DISABLED_UNAVAILABLE:
+ // already disabled: no-op
+ return;
default:
throw (new IllegalStateException("Invalid mState:" + mState
+ " for enabled false"));
@@ -562,7 +866,7 @@
AudioDeviceAttributes[] devices = new AudioDeviceAttributes[1];
// going through adapter to take advantage of routing cache
mASA.getDevicesForAttributes(attributes).toArray(devices);
- final boolean able = AudioSystem.canBeSpatialized(attributes, format, devices);
+ final boolean able = canBeSpatializedOnDevice(attributes, format, devices);
logd("canBeSpatialized returning " + able);
return able;
}
@@ -688,6 +992,9 @@
if (!checkSpatForHeadTracking("setDesiredHeadTrackingMode")) {
return;
}
+ if (mode != Spatializer.HEAD_TRACKING_MODE_DISABLED) {
+ mDesiredHeadTrackingModeWhenEnabled = mode;
+ }
try {
if (mDesiredHeadTrackingMode != mode) {
mDesiredHeadTrackingMode = mode;
@@ -701,6 +1008,84 @@
}
}
+ synchronized void setHeadTrackerEnabled(boolean enabled, @NonNull AudioDeviceAttributes ada) {
+ final int deviceType = ada.getType();
+ final boolean wireless = isWireless(deviceType);
+
+ for (SADeviceState deviceState : mSADevices) {
+ if (deviceType == deviceState.mDeviceType
+ && (wireless && ada.getAddress().equals(deviceState.mDeviceAddress))
+ || !wireless) {
+ if (!deviceState.mHasHeadTracker) {
+ Log.e(TAG, "Called setHeadTrackerEnabled enabled:" + enabled
+ + " device:" + ada + " on a device without headtracker");
+ return;
+ }
+ Log.i(TAG, "setHeadTrackerEnabled enabled:" + enabled + " device:" + ada);
+ deviceState.mHeadTrackerEnabled = enabled;
+ break;
+ }
+ }
+ // check current routing to see if it affects the headtracking mode
+ if (ROUTING_DEVICES[0].getType() == deviceType
+ && ROUTING_DEVICES[0].getAddress().equals(ada.getAddress())) {
+ setDesiredHeadTrackingMode(enabled ? mDesiredHeadTrackingModeWhenEnabled
+ : Spatializer.HEAD_TRACKING_MODE_DISABLED);
+ }
+ }
+
+ synchronized boolean hasHeadTracker(@NonNull AudioDeviceAttributes ada) {
+ final int deviceType = ada.getType();
+ final boolean wireless = isWireless(deviceType);
+
+ for (SADeviceState deviceState : mSADevices) {
+ if (deviceType == deviceState.mDeviceType
+ && (wireless && ada.getAddress().equals(deviceState.mDeviceAddress))
+ || !wireless) {
+ return deviceState.mHasHeadTracker;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Configures device in list as having a head tracker
+ * @param ada
+ * @return true if the head tracker is enabled, false otherwise or if device not found
+ */
+ synchronized boolean setHasHeadTracker(@NonNull AudioDeviceAttributes ada) {
+ final int deviceType = ada.getType();
+ final boolean wireless = isWireless(deviceType);
+
+ for (SADeviceState deviceState : mSADevices) {
+ if (deviceType == deviceState.mDeviceType
+ && (wireless && ada.getAddress().equals(deviceState.mDeviceAddress))
+ || !wireless) {
+ deviceState.mHasHeadTracker = true;
+ return deviceState.mHeadTrackerEnabled;
+ }
+ }
+ Log.e(TAG, "setHasHeadTracker: device not found for:" + ada);
+ return false;
+ }
+
+ synchronized boolean isHeadTrackerEnabled(@NonNull AudioDeviceAttributes ada) {
+ final int deviceType = ada.getType();
+ final boolean wireless = isWireless(deviceType);
+
+ for (SADeviceState deviceState : mSADevices) {
+ if (deviceType == deviceState.mDeviceType
+ && (wireless && ada.getAddress().equals(deviceState.mDeviceAddress))
+ || !wireless) {
+ if (!deviceState.mHasHeadTracker) {
+ return false;
+ }
+ return deviceState.mHeadTrackerEnabled;
+ }
+ }
+ return false;
+ }
+
private boolean checkSpatForHeadTracking(String funcName) {
switch (mState) {
case STATE_UNINITIALIZED:
@@ -884,7 +1269,7 @@
}
synchronized void onInitSensors() {
- final boolean init = (mSpatLevel != SpatializationLevel.NONE);
+ final boolean init = mFeatureEnabled && (mSpatLevel != SpatializationLevel.NONE);
final String action = init ? "initializing" : "releasing";
if (mSpat == null) {
Log.e(TAG, "not " + action + " sensors, null spatializer");
@@ -926,6 +1311,12 @@
UUID uuid = sensor.getUuid();
if (uuid.equals(routingDeviceUuid)) {
headHandle = sensor.getHandle();
+ // TODO check risk of race condition:
+ // does this happen before routing is updated?
+ // avoid by supporting adding device here AND in onRoutingUpdated()
+ if (!setHasHeadTracker(ROUTING_DEVICES[0])) {
+ headHandle = -1;
+ }
break;
}
if (uuid.equals(UuidUtils.STANDALONE_UUID)) {
@@ -933,6 +1324,7 @@
}
}
}
+
Sensor screenSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
screenHandle = screenSensor.getHandle();
} else {
@@ -1017,7 +1409,50 @@
for (int mode : modes) {
modesString += Spatializer.headtrackingModeToString(mode) + " ";
}
+ pw.println("\tsupports binaural:" + mBinauralSupported + " / transaural"
+ + mTransauralSupported);
pw.println("\tsupported head tracking modes:" + modesString);
pw.println("\tmSpatOutput:" + mSpatOutput);
+ pw.println("\tdevices:\n");
+ for (SADeviceState device : mSADevices) {
+ pw.println("\t\t" + device + "\n");
+ }
+ }
+
+ private static final class SADeviceState {
+ final int mDeviceType;
+ final @Nullable String mDeviceAddress; // non-null for wireless devices
+ boolean mEnabled = true; // by default, SA is enabled on any device
+ boolean mHasHeadTracker = false;
+ boolean mHeadTrackerEnabled = true; // by default, if head tracker is present, use it
+
+ SADeviceState(int deviceType, @Nullable String address) {
+ mDeviceType = deviceType;
+ mDeviceAddress = address;
+ }
+
+ @Override
+ public String toString() {
+ return "type:" + mDeviceType + " addr:" + mDeviceAddress + " enabled:" + mEnabled
+ + " HT:" + mHasHeadTracker + " HTenabled:" + mHeadTrackerEnabled;
+ }
+ }
+
+ private static boolean isWireless(int deviceType) {
+ for (int type : WIRELESS_TYPES) {
+ if (type == deviceType) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean isWirelessSpeaker(int deviceType) {
+ for (int type: WIRELESS_SPEAKER_TYPES) {
+ if (type == deviceType) {
+ return true;
+ }
+ }
+ return false;
}
}
diff --git a/services/core/java/com/android/server/biometrics/PreAuthInfo.java b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
index 05c3f68..aec98f0 100644
--- a/services/core/java/com/android/server/biometrics/PreAuthInfo.java
+++ b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
@@ -104,7 +104,8 @@
final int requestedStrength = Utils.getPublicBiometricStrength(promptInfo);
final boolean credentialRequested = Utils.isCredentialRequested(promptInfo);
- final boolean credentialAvailable = trustManager.isDeviceSecure(userId);
+ final boolean credentialAvailable = trustManager.isDeviceSecure(userId,
+ context.getAssociatedDisplayId());
// Assuming that biometric authenticators are listed in priority-order, the rest of this
// function will attempt to find the first authenticator that's as strong or stronger than
diff --git a/services/core/java/com/android/server/biometrics/log/BiometricContext.java b/services/core/java/com/android/server/biometrics/log/BiometricContext.java
index c5e266f..c86a8cb 100644
--- a/services/core/java/com/android/server/biometrics/log/BiometricContext.java
+++ b/services/core/java/com/android/server/biometrics/log/BiometricContext.java
@@ -44,7 +44,7 @@
@Nullable Integer getBiometricPromptSessionId();
/** If the display is in AOD. */
- boolean isAoD();
+ boolean isAod();
/**
* Subscribe to context changes.
diff --git a/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java b/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java
index 70acaff..9d2fde7 100644
--- a/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java
+++ b/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java
@@ -120,7 +120,7 @@
@Override
public OperationContext updateContext(@NonNull OperationContext operationContext,
boolean isCryptoOperation) {
- operationContext.isAoD = isAoD();
+ operationContext.isAod = isAod();
operationContext.isCrypto = isCryptoOperation;
setFirstSessionId(operationContext);
return operationContext;
@@ -160,7 +160,7 @@
}
@Override
- public boolean isAoD() {
+ public boolean isAod() {
return mIsDozing && mAmbientDisplayConfiguration.alwaysOnEnabled(UserHandle.USER_CURRENT);
}
@@ -177,7 +177,7 @@
private void notifySubscribers() {
mSubscribers.forEach((context, consumer) -> {
- context.isAoD = isAoD();
+ context.isAod = isAod();
consumer.accept(context);
});
}
diff --git a/services/core/java/com/android/server/biometrics/log/BiometricFrameworkStatsLogger.java b/services/core/java/com/android/server/biometrics/log/BiometricFrameworkStatsLogger.java
index 8965227..d6ca8a6 100644
--- a/services/core/java/com/android/server/biometrics/log/BiometricFrameworkStatsLogger.java
+++ b/services/core/java/com/android/server/biometrics/log/BiometricFrameworkStatsLogger.java
@@ -56,7 +56,7 @@
-1 /* sensorId */,
operationContext.id,
sessionType(operationContext.reason),
- operationContext.isAoD);
+ operationContext.isAod);
}
/** {@see FrameworkStatsLog.BIOMETRIC_AUTHENTICATED}. */
@@ -77,7 +77,7 @@
ambientLightLux,
operationContext.id,
sessionType(operationContext.reason),
- operationContext.isAoD);
+ operationContext.isAod);
}
/** {@see FrameworkStatsLog.BIOMETRIC_ENROLLED}. */
@@ -109,7 +109,7 @@
-1 /* sensorId */,
operationContext.id,
sessionType(operationContext.reason),
- operationContext.isAoD);
+ operationContext.isAod);
}
/** {@see FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED}. */
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index d26a780..653776b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -229,7 +229,7 @@
context.y = y;
context.minor = minor;
context.major = major;
- context.isAoD = getBiometricContext().isAoD();
+ context.isAod = getBiometricContext().isAod();
session.getSession().onPointerDownWithContext(context);
} else {
session.getSession().onPointerDown(0 /* pointerId */, x, y, minor, major);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
index e21d901..c92d599 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
@@ -213,7 +213,7 @@
context.y = y;
context.minor = minor;
context.major = major;
- context.isAoD = getBiometricContext().isAoD();
+ context.isAod = getBiometricContext().isAod();
session.getSession().onPointerDownWithContext(context);
} else {
session.getSession().onPointerDown(0 /* pointerId */, x, y, minor, major);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestHal.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestHal.java
index 452c972..6751153 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestHal.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestHal.java
@@ -204,8 +204,8 @@
@Override
public void onPointerDownWithContext(PointerContext context) {
- onPointerDown(
- context.pointerId, context.x, context.y, context.minor, context.major);
+ onPointerDown(context.pointerId, (int) context.x, (int) context.y, context.minor,
+ context.major);
}
@Override
diff --git a/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
index 135276e..94d3d15 100644
--- a/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
+++ b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
@@ -67,4 +67,9 @@
* display.
*/
public abstract boolean isAppRunningOnAnyVirtualDevice(int uid);
+
+ /**
+ * Returns true if the {@code displayId} is owned by any virtual device
+ */
+ public abstract boolean isDisplayOwnedByAnyVirtualDevice(int displayId);
}
diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
index 603f206..108e7bc 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.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 @@
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 @@
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 @@
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 @@
.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 20033ae..ea054a5 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -1319,6 +1319,7 @@
.setLegacyType(ConnectivityManager.TYPE_VPN)
.setLegacyTypeName("VPN")
.setBypassableVpn(mConfig.allowBypass && !mLockdown)
+ .setVpnRequiresValidation(mConfig.requiresInternetValidation)
.build();
capsBuilder.setOwnerUid(mOwnerUID);
@@ -3383,6 +3384,7 @@
}
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/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index 1894c0f..2c6257f 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -2421,10 +2421,10 @@
public static final int STATISTICS_FILE_ITEM = 101;
private void readStatsParcelLocked(File parcel) {
+ Parcel in = Parcel.obtain();
try {
final AtomicFile parcelFile = new AtomicFile(parcel);
byte[] data = parcelFile.readFully();
- Parcel in = Parcel.obtain();
in.unmarshall(data, 0, data.length);
in.setDataPosition(0);
int token;
@@ -2452,6 +2452,8 @@
}
} catch (IOException e) {
Slog.i(TAG, "No initial statistics");
+ } finally {
+ in.recycle();
}
}
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index 35e3db78..a311ba1 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -418,7 +418,7 @@
|| !Objects.equals(deviceProductInfo, other.deviceProductInfo)
|| ownerUid != other.ownerUid
|| !Objects.equals(ownerPackageName, other.ownerPackageName)
- || !Objects.equals(frameRateOverrides, other.frameRateOverrides)
+ || !Arrays.equals(frameRateOverrides, other.frameRateOverrides)
|| !BrightnessSynchronizer.floatEquals(brightnessMinimum, other.brightnessMinimum)
|| !BrightnessSynchronizer.floatEquals(brightnessMaximum, other.brightnessMaximum)
|| !BrightnessSynchronizer.floatEquals(brightnessDefault,
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 7f1482e..f5001102 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -78,6 +78,7 @@
import android.hardware.display.IVirtualDisplayCallback;
import android.hardware.display.VirtualDisplayConfig;
import android.hardware.display.WifiDisplayStatus;
+import android.hardware.graphics.common.DisplayDecorationSupport;
import android.hardware.input.InputManagerInternal;
import android.media.projection.IMediaProjection;
import android.media.projection.IMediaProjectionManager;
@@ -1860,10 +1861,10 @@
return mDisplayModeDirector.getModeSwitchingType();
}
- private boolean getDisplayDecorationSupportInternal(int displayId) {
+ private DisplayDecorationSupport getDisplayDecorationSupportInternal(int displayId) {
final IBinder displayToken = getDisplayToken(displayId);
if (null == displayToken) {
- return false;
+ return null;
}
return SurfaceControl.getDisplayDecorationSupport(displayToken);
}
@@ -3550,7 +3551,7 @@
}
@Override // Binder call
- public boolean getDisplayDecorationSupport(int displayId) {
+ public DisplayDecorationSupport getDisplayDecorationSupport(int displayId) {
final long token = Binder.clearCallingIdentity();
try {
return getDisplayDecorationSupportInternal(displayId);
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index d71e07a..418e91d 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -75,6 +75,7 @@
import com.android.server.policy.WindowManagerPolicy;
import java.io.PrintWriter;
+import java.util.Objects;
/**
* Controls the power state of the display.
@@ -236,42 +237,42 @@
// True if we should fade the screen while turning it off, false if we should play
// a stylish color fade animation instead.
- private boolean mColorFadeFadesConfig;
+ private final boolean mColorFadeFadesConfig;
// True if we need to fake a transition to off when coming out of a doze state.
// Some display hardware will blank itself when coming out of doze in order to hide
// artifacts. For these displays we fake a transition into OFF so that policy can appropriately
// blank itself and begin an appropriate power on animation.
- private boolean mDisplayBlanksAfterDozeConfig;
+ private final boolean mDisplayBlanksAfterDozeConfig;
// True if there are only buckets of brightness values when the display is in the doze state,
// rather than a full range of values. If this is true, then we'll avoid animating the screen
// brightness since it'd likely be multiple jarring brightness transitions instead of just one
// to reach the final state.
- private boolean mBrightnessBucketsInDozeConfig;
+ private final boolean mBrightnessBucketsInDozeConfig;
// The pending power request.
// Initially null until the first call to requestPowerState.
- // Guarded by mLock.
+ @GuardedBy("mLock")
private DisplayPowerRequest mPendingRequestLocked;
// True if a request has been made to wait for the proximity sensor to go negative.
- // Guarded by mLock.
+ @GuardedBy("mLock")
private boolean mPendingWaitForNegativeProximityLocked;
// True if the pending power request or wait for negative proximity flag
// has been changed since the last update occurred.
- // Guarded by mLock.
+ @GuardedBy("mLock")
private boolean mPendingRequestChangedLocked;
// Set to true when the important parts of the pending power request have been applied.
// The important parts are mainly the screen state. Brightness changes may occur
// concurrently.
- // Guarded by mLock.
+ @GuardedBy("mLock")
private boolean mDisplayReadyLocked;
// Set to true if a power state update is required.
- // Guarded by mLock.
+ @GuardedBy("mLock")
private boolean mPendingUpdatePowerStateLocked;
/* The following state must only be accessed by the handler thread. */
@@ -352,8 +353,8 @@
// information.
// At the time of this writing, this value is changed within updatePowerState() only, which is
// limited to the thread used by DisplayControllerHandler.
- private BrightnessReason mBrightnessReason = new BrightnessReason();
- private BrightnessReason mBrightnessReasonTemp = new BrightnessReason();
+ private final BrightnessReason mBrightnessReason = new BrightnessReason();
+ private final BrightnessReason mBrightnessReasonTemp = new BrightnessReason();
// Brightness animation ramp rates in brightness units per second
private float mBrightnessRampRateFastDecrease;
@@ -849,6 +850,7 @@
}
}
+ @GuardedBy("mLock")
private void sendUpdatePowerStateLocked() {
if (!mStopped && !mPendingUpdatePowerStateLocked) {
mPendingUpdatePowerStateLocked = true;
@@ -2318,6 +2320,7 @@
return mAutomaticBrightnessController.convertToNits(brightness);
}
+ @GuardedBy("mLock")
private void updatePendingProximityRequestsLocked() {
mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
mPendingWaitForNegativeProximityLocked = false;
@@ -2421,12 +2424,7 @@
pw.println(" mDisplayBlanksAfterDozeConfig=" + mDisplayBlanksAfterDozeConfig);
pw.println(" mBrightnessBucketsInDozeConfig=" + mBrightnessBucketsInDozeConfig);
- mHandler.runWithScissors(new Runnable() {
- @Override
- public void run() {
- dumpLocal(pw);
- }
- }, 1000);
+ mHandler.runWithScissors(() -> dumpLocal(pw), 1000);
}
private void dumpLocal(PrintWriter pw) {
@@ -2458,6 +2456,9 @@
pw.println(" mAppliedThrottling=" + mAppliedThrottling);
pw.println(" mAppliedScreenBrightnessOverride=" + mAppliedScreenBrightnessOverride);
pw.println(" mAppliedTemporaryBrightness=" + mAppliedTemporaryBrightness);
+ pw.println(" mAppliedTemporaryAutoBrightnessAdjustment="
+ + mAppliedTemporaryAutoBrightnessAdjustment);
+ pw.println(" mAppliedBrightnessBoost=" + mAppliedBrightnessBoost);
pw.println(" mDozing=" + mDozing);
pw.println(" mSkipRampState=" + skipRampStateToString(mSkipRampState));
pw.println(" mScreenOnBlockStartRealTime=" + mScreenOnBlockStartRealTime);
@@ -2465,21 +2466,21 @@
pw.println(" mPendingScreenOnUnblocker=" + mPendingScreenOnUnblocker);
pw.println(" mPendingScreenOffUnblocker=" + mPendingScreenOffUnblocker);
pw.println(" mPendingScreenOff=" + mPendingScreenOff);
- pw.println(" mReportedToPolicy=" +
- reportedToPolicyToString(mReportedScreenStateToPolicy));
+ pw.println(" mReportedToPolicy="
+ + reportedToPolicyToString(mReportedScreenStateToPolicy));
if (mScreenBrightnessRampAnimator != null) {
- pw.println(" mScreenBrightnessRampAnimator.isAnimating()=" +
- mScreenBrightnessRampAnimator.isAnimating());
+ pw.println(" mScreenBrightnessRampAnimator.isAnimating()="
+ + mScreenBrightnessRampAnimator.isAnimating());
}
if (mColorFadeOnAnimator != null) {
- pw.println(" mColorFadeOnAnimator.isStarted()=" +
- mColorFadeOnAnimator.isStarted());
+ pw.println(" mColorFadeOnAnimator.isStarted()="
+ + mColorFadeOnAnimator.isStarted());
}
if (mColorFadeOffAnimator != null) {
- pw.println(" mColorFadeOffAnimator.isStarted()=" +
- mColorFadeOffAnimator.isStarted());
+ pw.println(" mColorFadeOffAnimator.isStarted()="
+ + mColorFadeOffAnimator.isStarted());
}
if (mPowerState != null) {
@@ -2605,7 +2606,7 @@
}
}
- private final void logHbmBrightnessStats(float brightness, int displayStatsId) {
+ private void logHbmBrightnessStats(float brightness, int displayStatsId) {
synchronized (mHandler) {
FrameworkStatsLog.write(
FrameworkStatsLog.DISPLAY_HBM_BRIGHTNESS_CHANGED, displayStatsId, brightness);
@@ -2824,7 +2825,7 @@
@Override
public boolean equals(Object obj) {
- if (obj == null || !(obj instanceof BrightnessReason)) {
+ if (!(obj instanceof BrightnessReason)) {
return false;
}
BrightnessReason other = (BrightnessReason) obj;
@@ -2832,6 +2833,11 @@
}
@Override
+ public int hashCode() {
+ return Objects.hash(reason, modifier);
+ }
+
+ @Override
public String toString() {
return toString(0);
}
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index a31c231..d233c5e 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -182,8 +182,11 @@
private final long mPhysicalDisplayId;
private final SparseArray<DisplayModeRecord> mSupportedModes = new SparseArray<>();
private final ArrayList<Integer> mSupportedColorModes = new ArrayList<>();
+ private final DisplayModeDirector.DesiredDisplayModeSpecs mDisplayModeSpecs =
+ new DisplayModeDirector.DesiredDisplayModeSpecs();
private final boolean mIsDefaultDisplay;
private final BacklightAdapter mBacklightAdapter;
+ private final SidekickInternal mSidekickInternal;
private DisplayDeviceInfo mInfo;
private boolean mHavePendingChanges;
@@ -200,8 +203,6 @@
private int mActiveDisplayModeAtStartId = INVALID_MODE_ID;
private Display.Mode mUserPreferredMode;
private int mActiveModeId = INVALID_MODE_ID;
- private DisplayModeDirector.DesiredDisplayModeSpecs mDisplayModeSpecs =
- new DisplayModeDirector.DesiredDisplayModeSpecs();
private boolean mDisplayModeSpecsInvalid;
private int mActiveColorMode;
private Display.HdrCapabilities mHdrCapabilities;
@@ -210,13 +211,11 @@
private boolean mAllmRequested;
private boolean mGameContentTypeRequested;
private boolean mSidekickActive;
- private SidekickInternal mSidekickInternal;
private SurfaceControl.StaticDisplayInfo mStaticDisplayInfo;
// The supported display modes according to SurfaceFlinger
private SurfaceControl.DisplayMode[] mSfDisplayModes;
// The active display mode in SurfaceFlinger
private SurfaceControl.DisplayMode mActiveSfDisplayMode;
- private DisplayDeviceConfig mDisplayDeviceConfig;
private DisplayEventReceiver.FrameRateOverride[] mFrameRateOverrides =
new DisplayEventReceiver.FrameRateOverride[0];
@@ -233,7 +232,6 @@
mSidekickInternal = LocalServices.getService(SidekickInternal.class);
mBacklightAdapter = new BacklightAdapter(displayToken, isDefaultDisplay,
mSurfaceControlProxy);
- mDisplayDeviceConfig = null;
mActiveDisplayModeAtStartId = dynamicInfo.activeDisplayModeId;
}
@@ -459,9 +457,6 @@
final Context context = getOverlayContext();
mDisplayDeviceConfig = DisplayDeviceConfig.create(context, mPhysicalDisplayId,
mIsDefaultDisplay);
- if (mDisplayDeviceConfig == null) {
- return;
- }
// Load brightness HWC quirk
mBacklightAdapter.setForceSurfaceControl(mDisplayDeviceConfig.hasQuirk(
@@ -997,7 +992,7 @@
public boolean updateFrameRateOverridesLocked(
DisplayEventReceiver.FrameRateOverride[] overrides) {
- if (overrides.equals(mFrameRateOverrides)) {
+ if (Arrays.equals(overrides, mFrameRateOverrides)) {
return false;
}
@@ -1083,8 +1078,8 @@
pw.println("mGameContentTypeRequested=" + mGameContentTypeRequested);
pw.println("mStaticDisplayInfo=" + mStaticDisplayInfo);
pw.println("mSfDisplayModes=");
- for (int i = 0; i < mSfDisplayModes.length; i++) {
- pw.println(" " + mSfDisplayModes[i]);
+ for (SurfaceControl.DisplayMode sfDisplayMode : mSfDisplayModes) {
+ pw.println(" " + sfDisplayMode);
}
pw.println("mActiveSfDisplayMode=" + mActiveSfDisplayMode);
pw.println("mSupportedModes=");
@@ -1238,6 +1233,8 @@
}
public static class Injector {
+ // Native callback.
+ @SuppressWarnings("unused")
private ProxyDisplayEventReceiver mReceiver;
public void setDisplayEventListenerLocked(Looper looper, DisplayEventListener listener) {
mReceiver = new ProxyDisplayEventReceiver(looper, listener);
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index 93c73be..6f5729f 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -825,7 +825,6 @@
*
* @param device The device to associate with the LogicalDisplay.
* @param displayId The display ID to give the new display. If invalid, a new ID is assigned.
- * @param isDefault Indicates if we are creating the default display.
* @return The new logical display if created, null otherwise.
*/
private LogicalDisplay createNewLogicalDisplayLocked(DisplayDevice device, int displayId) {
diff --git a/services/core/java/com/android/server/display/RampAnimator.java b/services/core/java/com/android/server/display/RampAnimator.java
index d8672fc..2567e43 100644
--- a/services/core/java/com/android/server/display/RampAnimator.java
+++ b/services/core/java/com/android/server/display/RampAnimator.java
@@ -55,7 +55,7 @@
* If this is the first time the property is being set or if the rate is 0,
* the value jumps directly to the target.
*
- * @param target The target value.
+ * @param targetLinear The target value.
* @param rate The convergence rate in units per second, or 0 to set the value immediately.
* @return True if the target differs from the previous target.
*/
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index b814782..b2f500a 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -422,7 +422,7 @@
addFreshWindowToken();
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
- null, null, mCurId, mCurSeq, false);
+ null, null, null, mCurId, mCurSeq, false);
}
Slog.w(InputMethodManagerService.TAG,
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
index 80c83e9..29dcdfa 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
@@ -25,6 +25,7 @@
import com.android.internal.inputmethod.SoftInputShowHideReason;
import com.android.internal.view.IInlineSuggestionsRequestCallback;
+import com.android.internal.view.IInputMethodSession;
import com.android.internal.view.InlineSuggestionsRequestInfo;
import com.android.server.LocalServices;
@@ -149,6 +150,24 @@
public abstract void updateImeWindowStatus(boolean disableImeIcon);
/**
+ * Callback when the IInputMethodSession from the accessibility service with the specified
+ * accessibilityConnectionId is created.
+ *
+ * @param accessibilityConnectionId The connection id of the accessibility service.
+ * @param session The session passed back from the accessibility service.
+ */
+ public abstract void onSessionForAccessibilityCreated(int accessibilityConnectionId,
+ IInputMethodSession session);
+
+ /**
+ * Unbind the accessibility service with the specified accessibilityConnectionId from current
+ * client.
+ *
+ * @param accessibilityConnectionId The connection id of the accessibility service.
+ */
+ public abstract void unbindAccessibilityFromCurrentClient(int accessibilityConnectionId);
+
+ /**
* Fake implementation of {@link InputMethodManagerInternal}. All the methods do nothing.
*/
private static final InputMethodManagerInternal NOP =
@@ -211,6 +230,15 @@
@Override
public void updateImeWindowStatus(boolean disableImeIcon) {
}
+
+ @Override
+ public void onSessionForAccessibilityCreated(int accessibilityConnectionId,
+ IInputMethodSession session) {
+ }
+
+ @Override
+ public void unbindAccessibilityFromCurrentClient(int accessibilityConnectionId) {
+ }
};
/**
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index ba15a04..7068ed1 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -94,6 +94,7 @@
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
+import android.os.DeadObjectException;
import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
@@ -120,6 +121,7 @@
import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import android.view.IWindowManager;
import android.view.InputChannel;
@@ -171,6 +173,7 @@
import com.android.internal.view.IInputMethodSession;
import com.android.internal.view.IInputSessionCallback;
import com.android.internal.view.InlineSuggestionsRequestInfo;
+import com.android.server.AccessibilityManagerInternal;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
@@ -228,7 +231,9 @@
private static final int MSG_START_HANDWRITING = 1100;
private static final int MSG_UNBIND_CLIENT = 3000;
+ private static final int MSG_UNBIND_ACCESSIBILITY_SERVICE = 3001;
private static final int MSG_BIND_CLIENT = 3010;
+ private static final int MSG_BIND_ACCESSIBILITY_SERVICE = 3011;
private static final int MSG_SET_ACTIVE = 3020;
private static final int MSG_SET_INTERACTIVE = 3030;
private static final int MSG_REPORT_FULLSCREEN_MODE = 3045;
@@ -351,6 +356,33 @@
}
}
+ /**
+ * Record session state for an accessibility service.
+ */
+ private static class AccessibilitySessionState {
+ final ClientState mClient;
+ // Id of the accessibility service.
+ final int mId;
+
+ public IInputMethodSession mSession;
+
+ @Override
+ public String toString() {
+ return "AccessibilitySessionState{uid " + mClient.uid + " pid " + mClient.pid
+ + " id " + Integer.toHexString(mId)
+ + " session " + Integer.toHexString(
+ System.identityHashCode(mSession))
+ + "}";
+ }
+
+ AccessibilitySessionState(ClientState client, int id,
+ IInputMethodSession session) {
+ mClient = client;
+ mId = id;
+ mSession = session;
+ }
+ }
+
private static final class ClientDeathRecipient implements IBinder.DeathRecipient {
private final InputMethodManagerService mImms;
private final IInputMethodClient mClient;
@@ -376,7 +408,9 @@
final ClientDeathRecipient clientDeathRecipient;
boolean sessionRequested;
+ boolean mSessionRequestedForAccessibility;
SessionState curSession;
+ SparseArray<AccessibilitySessionState> mAccessibilitySessions = new SparseArray<>();
@Override
public String toString() {
@@ -637,10 +671,16 @@
boolean mBoundToMethod;
/**
+ * Have we called bindInput() for accessibility services?
+ */
+ boolean mBoundToAccessibility;
+
+ /**
* Currently enabled session.
*/
@GuardedBy("ImfLock.class")
SessionState mEnabledSession;
+ SparseArray<AccessibilitySessionState> mEnabledAccessibilitySessions = new SparseArray<>();
/**
* True if the device is currently interactive with user. The value is true initially.
@@ -2188,6 +2228,7 @@
if (cs != null) {
client.asBinder().unlinkToDeath(cs.clientDeathRecipient, 0);
clearClientSessionLocked(cs);
+ clearClientSessionForAccessibilityLocked(cs);
if (mCurClient == cs) {
hideCurrentInputLocked(
mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_REMOVE_CLIENT);
@@ -2195,9 +2236,13 @@
mBoundToMethod = false;
IInputMethodInvoker curMethod = getCurMethodLocked();
if (curMethod != null) {
+ // When we unbind input, we are unbinding the client, so we always
+ // unbind ime and a11y together.
curMethod.unbindInput();
+ AccessibilityManagerInternal.get().unbindInput();
}
}
+ mBoundToAccessibility = false;
mCurClient = null;
}
if (mCurFocusedWindowClient == cs) {
@@ -2216,6 +2261,24 @@
}
@NonNull
+ private Message obtainMessageOOO(int what, Object arg1, Object arg2, Object arg3) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = arg1;
+ args.arg2 = arg2;
+ args.arg3 = arg3;
+ return mHandler.obtainMessage(what, 0, 0, args);
+ }
+
+ @NonNull
+ private Message obtainMessageIIOO(int what, int arg1, int arg2,
+ Object arg3, Object arg4) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = arg3;
+ args.arg2 = arg4;
+ return mHandler.obtainMessage(what, arg1, arg2, args);
+ }
+
+ @NonNull
private Message obtainMessageIIIO(int what, int argi1, int argi2, int argi3, Object arg1) {
final SomeArgs args = SomeArgs.obtain();
args.arg1 = arg1;
@@ -2252,13 +2315,18 @@
curMethod.unbindInput();
}
}
+ mBoundToAccessibility = false;
+ // Since we set active false to current client and set mCurClient to null, let's unbind
+ // all accessibility too. That means, when input method get disconnected (including
+ // switching ime), we also unbind accessibility
scheduleSetActiveToClient(mCurClient, false /* active */, false /* fullscreen */,
false /* reportToImeController */);
executeOrSendMessage(mCurClient.client, mHandler.obtainMessage(
MSG_UNBIND_CLIENT, getSequenceNumberLocked(), unbindClientReason,
mCurClient.client));
mCurClient.sessionRequested = false;
+ mCurClient.mSessionRequestedForAccessibility = false;
mCurClient = null;
mMenuController.hideInputMethodMenuLocked();
@@ -2340,11 +2408,63 @@
final InputMethodInfo curInputMethodInfo = mMethodMap.get(curId);
final boolean suppressesSpellChecker =
curInputMethodInfo != null && curInputMethodInfo.suppressesSpellChecker();
+ final SparseArray<IInputMethodSession> accessibilityInputMethodSessions =
+ createAccessibilityInputMethodSessions(mCurClient.mAccessibilitySessions);
return new InputBindResult(InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION,
- session.session, (session.channel != null ? session.channel.dup() : null),
+ session.session, accessibilityInputMethodSessions,
+ (session.channel != null ? session.channel.dup() : null),
curId, getSequenceNumberLocked(), suppressesSpellChecker);
}
+ @GuardedBy("ImfLock.class")
+ @Nullable
+ InputBindResult attachNewAccessibilityLocked(@StartInputReason int startInputReason,
+ boolean initial, int id) {
+ if (!mBoundToAccessibility) {
+ AccessibilityManagerInternal.get().bindInput(mCurClient.binding);
+ mBoundToAccessibility = true;
+ }
+
+ // TODO(b/187453053): grantImplicitAccess to accessibility services access? if so, need to
+ // record accessibility services uid.
+
+ final AccessibilitySessionState accessibilitySession =
+ mCurClient.mAccessibilitySessions.get(id);
+ // We don't start input when session for a11y is created. We start input when
+ // input method start input, a11y manager service is always on.
+ if (startInputReason != StartInputReason.SESSION_CREATED_BY_ACCESSIBILITY) {
+ final Binder startInputToken = new Binder();
+ setEnabledSessionForAccessibilityLocked(mCurClient.mAccessibilitySessions);
+ AccessibilityManagerInternal.get().startInput(startInputToken, mCurInputContext,
+ mCurAttribute, !initial /* restarting */);
+ }
+
+ if (accessibilitySession != null) {
+ final SessionState session = mCurClient.curSession;
+ IInputMethodSession imeSession = session == null ? null : session.session;
+ final SparseArray<IInputMethodSession> accessibilityInputMethodSessions =
+ createAccessibilityInputMethodSessions(mCurClient.mAccessibilitySessions);
+ return new InputBindResult(
+ InputBindResult.ResultCode.SUCCESS_WITH_ACCESSIBILITY_SESSION,
+ imeSession, accessibilityInputMethodSessions, null,
+ getCurIdLocked(), getSequenceNumberLocked(), false);
+ }
+ return null;
+ }
+
+ private SparseArray<IInputMethodSession> createAccessibilityInputMethodSessions(
+ SparseArray<AccessibilitySessionState> accessibilitySessions) {
+ final SparseArray<IInputMethodSession> accessibilityInputMethodSessions =
+ new SparseArray<>();
+ if (accessibilitySessions != null) {
+ for (int i = 0; i < accessibilitySessions.size(); i++) {
+ accessibilityInputMethodSessions.append(accessibilitySessions.keyAt(i),
+ accessibilitySessions.valueAt(i).mSession);
+ }
+ }
+ return accessibilityInputMethodSessions;
+ }
+
/**
* Called by {@link #startInputOrWindowGainedFocusInternalLocked} to bind/unbind/attach the
* selected InputMethod to the given focused IME client.
@@ -2370,7 +2490,7 @@
// party code.
return new InputBindResult(
InputBindResult.ResultCode.ERROR_SYSTEM_NOT_READY,
- null, null, selectedMethodId, getSequenceNumberLocked(), false);
+ null, null, null, selectedMethodId, getSequenceNumberLocked(), false);
}
if (!InputMethodUtils.checkIfPackageBelongsToUid(mAppOpsManager, cs.uid,
@@ -2422,6 +2542,17 @@
if (cs.curSession != null) {
// Fast case: if we are already connected to the input method,
// then just return it.
+ // This doesn't mean a11y sessions are there. When a11y service is
+ // enabled while this client is switched out, this client doesn't have the session.
+ // A11yManagerService will only request missing sessions (will not request existing
+ // sessions again). Note when an a11y service is disabled, it will clear its
+ // session from all clients, so we don't need to worry about disabled a11y services.
+ cs.mSessionRequestedForAccessibility = false;
+ requestClientSessionForAccessibilityLocked(cs);
+ // we can always attach to accessibility because AccessibilityManagerService is
+ // always on.
+ attachNewAccessibilityLocked(startInputReason,
+ (startInputFlags & StartInputFlags.INITIAL_CONNECTION) != 0, -1);
return attachNewInputLocked(startInputReason,
(startInputFlags & StartInputFlags.INITIAL_CONNECTION) != 0);
}
@@ -2464,9 +2595,10 @@
// Return to client, and we will get back with it when
// we have had a session made for it.
requestClientSessionLocked(cs);
+ requestClientSessionForAccessibilityLocked(cs);
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION,
- null, null, getCurIdLocked(), getSequenceNumberLocked(), false);
+ null, null, null, getCurIdLocked(), getSequenceNumberLocked(), false);
} else {
long bindingDuration = SystemClock.uptimeMillis() - getLastBindTimeLocked();
if (bindingDuration < TIME_TO_RECONNECT) {
@@ -2479,7 +2611,7 @@
// to see if we can get back in touch with the service.
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
- null, null, getCurIdLocked(), getSequenceNumberLocked(), false);
+ null, null, null, getCurIdLocked(), getSequenceNumberLocked(), false);
} else {
EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME,
getSelectedMethodIdLocked(), bindingDuration, 0);
@@ -2565,6 +2697,8 @@
method, session, channel);
InputBindResult res = attachNewInputLocked(
StartInputReason.SESSION_CREATED_BY_IME, true);
+ attachNewAccessibilityLocked(StartInputReason.SESSION_CREATED_BY_IME,
+ true, -1);
if (res.method != null) {
executeOrSendMessage(mCurClient.client, obtainMessageOO(
MSG_BIND_CLIENT, mCurClient.client, res));
@@ -2602,7 +2736,9 @@
void reRequestCurrentClientSessionLocked() {
if (mCurClient != null) {
clearClientSessionLocked(mCurClient);
+ clearClientSessionForAccessibilityLocked(mCurClient);
requestClientSessionLocked(mCurClient);
+ requestClientSessionForAccessibilityLocked(mCurClient);
}
}
@@ -2646,6 +2782,19 @@
}
@GuardedBy("ImfLock.class")
+ void requestClientSessionForAccessibilityLocked(ClientState cs) {
+ if (!cs.mSessionRequestedForAccessibility) {
+ if (DEBUG) Slog.v(TAG, "Creating new accessibility sessions for client " + cs);
+ cs.mSessionRequestedForAccessibility = true;
+ ArraySet<Integer> ignoreSet = new ArraySet<>();
+ for (int i = 0; i < cs.mAccessibilitySessions.size(); i++) {
+ ignoreSet.add(cs.mAccessibilitySessions.keyAt(i));
+ }
+ AccessibilityManagerInternal.get().createImeSession(ignoreSet);
+ }
+ }
+
+ @GuardedBy("ImfLock.class")
void clearClientSessionLocked(ClientState cs) {
finishSessionLocked(cs.curSession);
cs.curSession = null;
@@ -2653,6 +2802,24 @@
}
@GuardedBy("ImfLock.class")
+ void clearClientSessionForAccessibilityLocked(ClientState cs) {
+ for (int i = 0; i < cs.mAccessibilitySessions.size(); i++) {
+ finishSessionForAccessibilityLocked(cs.mAccessibilitySessions.valueAt(i));
+ }
+ cs.mAccessibilitySessions.clear();
+ cs.mSessionRequestedForAccessibility = false;
+ }
+
+ @GuardedBy("ImfLock.class")
+ void clearClientSessionForAccessibilityLocked(ClientState cs, int id) {
+ AccessibilitySessionState session = cs.mAccessibilitySessions.get(id);
+ if (session != null) {
+ finishSessionForAccessibilityLocked(session);
+ cs.mAccessibilitySessions.remove(id);
+ }
+ }
+
+ @GuardedBy("ImfLock.class")
private void finishSessionLocked(SessionState sessionState) {
if (sessionState != null) {
if (sessionState.session != null) {
@@ -2672,15 +2839,34 @@
}
@GuardedBy("ImfLock.class")
+ private void finishSessionForAccessibilityLocked(AccessibilitySessionState sessionState) {
+ if (sessionState != null) {
+ if (sessionState.mSession != null) {
+ try {
+ sessionState.mSession.finishSession();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Session failed to close due to remote exception", e);
+ }
+ sessionState.mSession = null;
+ }
+ }
+ }
+
+ @GuardedBy("ImfLock.class")
void clearClientSessionsLocked() {
if (getCurMethodLocked() != null) {
final int numClients = mClients.size();
for (int i = 0; i < numClients; ++i) {
clearClientSessionLocked(mClients.valueAt(i));
+ clearClientSessionForAccessibilityLocked(mClients.valueAt(i));
}
finishSessionLocked(mEnabledSession);
+ for (int i = 0; i < mEnabledAccessibilitySessions.size(); i++) {
+ finishSessionForAccessibilityLocked(mEnabledAccessibilitySessions.valueAt(i));
+ }
mEnabledSession = null;
+ mEnabledAccessibilitySessions.clear();
scheduleNotifyImeUidToAudioService(Process.INVALID_UID);
}
hideStatusBarIconLocked();
@@ -3455,7 +3641,7 @@
}
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
- null, null, null, -1, false);
+ null, null, null, null, -1, false);
}
mCurFocusedWindow = windowToken;
@@ -4250,6 +4436,41 @@
}
}
+ @GuardedBy("ImfLock.class")
+ void setEnabledSessionForAccessibilityLocked(
+ SparseArray<AccessibilitySessionState> accessibilitySessions) {
+ // mEnabledAccessibilitySessions could the same object as accessibilitySessions.
+ SparseArray<IInputMethodSession> disabledSessions = new SparseArray<>();
+ for (int i = 0; i < mEnabledAccessibilitySessions.size(); i++) {
+ if (!accessibilitySessions.contains(mEnabledAccessibilitySessions.keyAt(i))) {
+ AccessibilitySessionState sessionState = mEnabledAccessibilitySessions.valueAt(i);
+ if (sessionState != null) {
+ disabledSessions.append(mEnabledAccessibilitySessions.keyAt(i),
+ sessionState.mSession);
+ }
+ }
+ }
+ if (disabledSessions.size() > 0) {
+ AccessibilityManagerInternal.get().setImeSessionEnabled(disabledSessions,
+ false);
+ }
+ SparseArray<IInputMethodSession> enabledSessions = new SparseArray<>();
+ for (int i = 0; i < accessibilitySessions.size(); i++) {
+ if (!mEnabledAccessibilitySessions.contains(accessibilitySessions.keyAt(i))) {
+ AccessibilitySessionState sessionState = accessibilitySessions.valueAt(i);
+ if (sessionState != null) {
+ enabledSessions.append(accessibilitySessions.keyAt(i), sessionState.mSession);
+ }
+ }
+ }
+ if (enabledSessions.size() > 0) {
+ AccessibilityManagerInternal.get().setImeSessionEnabled(enabledSessions,
+ true);
+ }
+ mEnabledAccessibilitySessions = accessibilitySessions;
+ }
+
+ @SuppressWarnings("unchecked")
@UiThread
@Override
public boolean handleMessage(Message msg) {
@@ -4319,13 +4540,34 @@
// ---------------------------------------------------------
- case MSG_UNBIND_CLIENT:
+ case MSG_UNBIND_CLIENT: {
try {
- ((IInputMethodClient)msg.obj).onUnbindMethod(msg.arg1, msg.arg2);
+ // This unbinds all accessibility services too.
+ ((IInputMethodClient) msg.obj).onUnbindMethod(msg.arg1, msg.arg2);
} catch (RemoteException e) {
// There is nothing interesting about the last client dying.
+ if (!(e instanceof DeadObjectException)) {
+ Slog.w(TAG, "RemoteException when unbinding input method service or"
+ + "accessibility services");
+ }
}
return true;
+ }
+ case MSG_UNBIND_ACCESSIBILITY_SERVICE: {
+ args = (SomeArgs) msg.obj;
+ IInputMethodClient client = (IInputMethodClient) args.arg1;
+ int id = (int) args.arg2;
+ try {
+ client.onUnbindAccessibilityService(msg.arg1, id);
+ } catch (RemoteException e) {
+ // There is nothing interesting about the last client dying.
+ if (!(e instanceof DeadObjectException)) {
+ Slog.w(TAG, "RemoteException when unbinding accessibility services");
+ }
+ }
+ args.recycle();
+ return true;
+ }
case MSG_BIND_CLIENT: {
args = (SomeArgs)msg.obj;
IInputMethodClient client = (IInputMethodClient)args.arg1;
@@ -4344,6 +4586,25 @@
args.recycle();
return true;
}
+ case MSG_BIND_ACCESSIBILITY_SERVICE: {
+ args = (SomeArgs) msg.obj;
+ IInputMethodClient client = (IInputMethodClient) args.arg1;
+ InputBindResult res = (InputBindResult) args.arg2;
+ int id = (int) args.arg3;
+ try {
+ client.onBindAccessibilityService(res, id);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Client died receiving input method " + args.arg2);
+ } finally {
+ // Dispose the channel if the accessibility service is not local to this process
+ // because the remote proxy will get its own copy when unparceled.
+ if (res.channel != null && Binder.isProxy(client)) {
+ res.channel.dispose();
+ }
+ }
+ args.recycle();
+ return true;
+ }
case MSG_SET_ACTIVE: {
args = (SomeArgs) msg.obj;
final ClientState clientState = (ClientState) args.arg1;
@@ -5025,6 +5286,59 @@
mHandler.obtainMessage(MSG_UPDATE_IME_WINDOW_STATUS, disableImeIcon ? 1 : 0, 0)
.sendToTarget();
}
+
+ @Override
+ public void onSessionForAccessibilityCreated(int accessibilityConnectionId,
+ IInputMethodSession session) {
+ synchronized (ImfLock.class) {
+ if (mCurClient != null) {
+ clearClientSessionForAccessibilityLocked(mCurClient, accessibilityConnectionId);
+ mCurClient.mAccessibilitySessions.put(accessibilityConnectionId,
+ new AccessibilitySessionState(mCurClient, accessibilityConnectionId,
+ session));
+ InputBindResult res = attachNewAccessibilityLocked(
+ StartInputReason.SESSION_CREATED_BY_ACCESSIBILITY, true,
+ accessibilityConnectionId);
+ executeOrSendMessage(mCurClient.client, obtainMessageOOO(
+ MSG_BIND_ACCESSIBILITY_SERVICE, mCurClient.client, res,
+ accessibilityConnectionId));
+ }
+ }
+ }
+
+ @Override
+ public void unbindAccessibilityFromCurrentClient(int accessibilityConnectionId) {
+ synchronized (ImfLock.class) {
+ if (mCurClient != null) {
+ if (DEBUG) {
+ Slog.v(TAG, "unbindAccessibilityFromCurrentClientLocked: client="
+ + mCurClient.client.asBinder());
+ }
+ // A11yManagerService unbinds the disabled accessibility service. We don't need
+ // to do it here.
+ @UnbindReason int unbindClientReason =
+ UnbindReason.ACCESSIBILITY_SERVICE_DISABLED;
+ executeOrSendMessage(mCurClient.client, obtainMessageIIOO(
+ MSG_UNBIND_ACCESSIBILITY_SERVICE, getSequenceNumberLocked(),
+ unbindClientReason, mCurClient.client, accessibilityConnectionId));
+ }
+ // We only have sessions when we bound to an input method. Remove this session
+ // from all clients.
+ if (getCurMethodLocked() != null) {
+ final int numClients = mClients.size();
+ for (int i = 0; i < numClients; ++i) {
+ clearClientSessionForAccessibilityLocked(mClients.valueAt(i),
+ accessibilityConnectionId);
+ }
+ AccessibilitySessionState session = mEnabledAccessibilitySessions.get(
+ accessibilityConnectionId);
+ if (session != null) {
+ finishSessionForAccessibilityLocked(session);
+ mEnabledAccessibilitySessions.remove(accessibilityConnectionId);
+ }
+ }
+ }
+ }
}
@BinderThread
@@ -5184,6 +5498,8 @@
p.println(" client=" + ci.client);
p.println(" inputContext=" + ci.inputContext);
p.println(" sessionRequested=" + ci.sessionRequested);
+ p.println(" sessionRequestedForAccessibility="
+ + ci.mSessionRequestedForAccessibility);
p.println(" curSession=" + ci.curSession);
}
p.println(" mCurMethodId=" + getSelectedMethodIdLocked());
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index d48ccd5..025ccd1 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -45,7 +45,6 @@
import android.content.pm.Signature;
import android.content.pm.SigningDetails;
import android.content.pm.SigningInfo;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
import android.net.Uri;
@@ -70,6 +69,7 @@
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.pkg.PackageUserStateInternal;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import java.io.ByteArrayInputStream;
import java.io.File;
@@ -307,6 +307,7 @@
}
List<String> appCertificates = getCertificateFingerprint(packageInfo);
+ List<String> appCertificateLineage = getCertificateLineage(packageInfo);
List<String> installerCertificates =
getInstallerCertificateFingerprint(installerPackageName);
@@ -314,6 +315,7 @@
builder.setPackageName(getPackageNameNormalized(packageName));
builder.setAppCertificates(appCertificates);
+ builder.setAppCertificateLineage(appCertificateLineage);
builder.setVersionCode(intent.getLongExtra(EXTRA_LONG_VERSION_CODE, -1));
builder.setInstallerName(getPackageNameNormalized(installerPackageName));
builder.setInstallerCertificates(installerCertificates);
@@ -460,6 +462,14 @@
return certificateFingerprints;
}
+ private List<String> getCertificateLineage(@NonNull PackageInfo packageInfo) {
+ ArrayList<String> certificateLineage = new ArrayList();
+ for (Signature signature : getSignatureLineage(packageInfo)) {
+ certificateLineage.add(getFingerprint(signature));
+ }
+ return certificateLineage;
+ }
+
/** Get the allowed installers and their associated certificate hashes from <meta-data> tag. */
private Map<String, String> getAllowedInstallers(@NonNull PackageInfo packageInfo) {
Map<String, String> packageCertMap = new HashMap<>();
@@ -541,6 +551,38 @@
return signingInfo.getApkContentsSigners();
}
+ private static Signature[] getSignatureLineage(@NonNull PackageInfo packageInfo) {
+ // Obtain the signing info of the package.
+ SigningInfo signingInfo = packageInfo.signingInfo;
+ if (signingInfo == null) {
+ throw new IllegalArgumentException(
+ "Package signature not found in " + packageInfo);
+ }
+
+ // Obtain the active signatures of the package.
+ Signature[] signatureLineage = getSignatures(packageInfo);
+
+ // Obtain the past signatures of the package.
+ if (!signingInfo.hasMultipleSigners() && signingInfo.hasPastSigningCertificates()) {
+ Signature[] pastSignatures = signingInfo.getSigningCertificateHistory();
+
+ // Merge the signatures and return.
+ Signature[] allSignatures =
+ new Signature[signatureLineage.length + pastSignatures.length];
+ int i;
+ for (i = 0; i < signatureLineage.length; i++) {
+ allSignatures[i] = signatureLineage[i];
+ }
+ for (int j = 0; j < pastSignatures.length; j++) {
+ allSignatures[i] = pastSignatures[j];
+ i++;
+ }
+ signatureLineage = allSignatures;
+ }
+
+ return signatureLineage;
+ }
+
private static String getFingerprint(Signature cert) {
InputStream input = new ByteArrayInputStream(cert.toByteArray());
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 3abe5e2..0f4648a 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -148,6 +148,8 @@
import com.android.server.locksettings.SyntheticPasswordManager.TokenType;
import com.android.server.locksettings.recoverablekeystore.RecoverableKeyStoreManager;
import com.android.server.pm.UserManagerInternal;
+import com.android.server.utils.Watchable;
+import com.android.server.utils.Watcher;
import com.android.server.wm.WindowManagerInternal;
import libcore.util.HexEncoding;
@@ -230,6 +232,7 @@
protected final Handler mHandler;
@VisibleForTesting
protected final LockSettingsStorage mStorage;
+ private final Watcher mStorageWatcher;
private final LockSettingsStrongAuth mStrongAuth;
private final SynchronizedStrongAuthTracker mStrongAuthTracker;
private final BiometricDeferredQueue mBiometricDeferredQueue;
@@ -573,6 +576,12 @@
}
}
+ private class StorageWatcher extends Watcher {
+ public void onChange(Watchable what) {
+ LockSettingsService.this.onChange();
+ }
+ }
+
public LockSettingsService(Context context) {
this(new Injector(context));
}
@@ -614,6 +623,16 @@
mStorage);
LocalServices.addService(LockSettingsInternal.class, new LocalService());
+
+ mStorageWatcher = new StorageWatcher();
+ mStorage.registerObserver(mStorageWatcher);
+ }
+
+ /**
+ * Invalidate caches if the storage has changed.
+ */
+ private void onChange() {
+ LockPatternUtils.invalidateCredentialTypeCache();
}
/**
@@ -1278,6 +1297,11 @@
DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userId);
}
+ /**
+ * This API is cached; whenever the result would change,
+ * {@link com.android.internal.widget.LockPatternUtils#invalidateCredentialTypeCache}
+ * must be called.
+ */
@Override
public int getCredentialType(int userId) {
checkPasswordHavePermission(userId);
@@ -1693,7 +1717,7 @@
return false;
}
setSeparateProfileChallengeEnabledLocked(userId, true, /* unused */ null);
- notifyPasswordChanged(userId);
+ notifyPasswordChanged(credential, userId);
}
if (isCredentialSharedWithParent(userId)) {
// Make sure the profile doesn't get locked straight after setting work challenge.
@@ -2486,9 +2510,11 @@
* Call after {@link #setUserPasswordMetrics} so metrics are updated before
* reporting the password changed.
*/
- private void notifyPasswordChanged(@UserIdInt int userId) {
+ private void notifyPasswordChanged(LockscreenCredential newCredential, @UserIdInt int userId) {
mHandler.post(() -> {
- mInjector.getDevicePolicyManager().reportPasswordChanged(userId);
+ mInjector.getDevicePolicyManager().reportPasswordChanged(
+ PasswordMetrics.computeForCredential(newCredential),
+ userId);
LocalServices.getService(WindowManagerInternal.class).reportPasswordChanged(userId);
});
}
@@ -3423,7 +3449,7 @@
// the caller like DPMS), otherwise it can lead to deadlock.
mHandler.post(() -> unlockUser(userId, null));
}
- notifyPasswordChanged(userId);
+ notifyPasswordChanged(credential, userId);
notifySeparateProfileChallengeChanged(userId);
}
return result;
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
index f69a3bd..f9db5cf 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
@@ -47,6 +47,7 @@
import com.android.internal.widget.LockPatternUtils.CredentialType;
import com.android.server.LocalServices;
import com.android.server.PersistentDataBlockManagerInternal;
+import com.android.server.utils.WatchableImpl;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -66,7 +67,7 @@
/**
* Storage for the lock settings service.
*/
-class LockSettingsStorage {
+class LockSettingsStorage extends WatchableImpl {
private static final String TAG = "LockSettingsStorage";
private static final String TABLE = "locksettings";
@@ -173,7 +174,7 @@
} finally {
db.endTransaction();
}
-
+ dispatchChange(this);
}
@VisibleForTesting
@@ -221,7 +222,7 @@
} finally {
db.endTransaction();
}
-
+ dispatchChange(this);
}
public void prefetchUser(int userId) {
@@ -412,6 +413,7 @@
}
}
mCache.putFile(name, hash);
+ dispatchChange(this);
}
}
@@ -423,6 +425,7 @@
file.delete();
mCache.putFile(name, null);
}
+ dispatchChange(this);
}
}
@@ -500,6 +503,7 @@
Slog.w(TAG, "Failed to zeroize " + path, e);
} finally {
file.delete();
+ dispatchChange(this);
}
mCache.putFile(path, null);
}
@@ -587,6 +591,7 @@
} finally {
db.endTransaction();
}
+ dispatchChange(this);
}
private void deleteFilesAndRemoveCache(String... names) {
@@ -595,6 +600,7 @@
if (file.exists()) {
file.delete();
mCache.putFile(name, null);
+ dispatchChange(this);
}
}
}
@@ -675,6 +681,7 @@
}
persistentDataBlock.setFrpCredentialHandle(PersistentData.toBytes(
persistentType, userId, qualityForUi, payload));
+ dispatchChange(this);
}
public PersistentData readPersistentDataBlock() {
diff --git a/services/core/java/com/android/server/logcat/LogcatManagerService.java b/services/core/java/com/android/server/logcat/LogcatManagerService.java
index 7832296..34614d5 100644
--- a/services/core/java/com/android/server/logcat/LogcatManagerService.java
+++ b/services/core/java/com/android/server/logcat/LogcatManagerService.java
@@ -59,7 +59,7 @@
private ActivityManagerInternal mActivityManagerInternal;
private static final int MAX_UID_IMPORTANCE_COUNT_LISTENER = 2;
private static int sUidImportanceListenerCount = 0;
- private static final int AID_APP_UID = 10000;
+ private static final int AID_SHELL_UID = 2000;
// TODO This allowlist is just a temporary workaround for the tests:
// FrameworksServicesTests
@@ -329,63 +329,13 @@
if (mStart) {
- // TODO See the comments of ALLOWABLE_TESTING_PACKAGES.
- if (isAllowableTestingPackage(mUid)) {
- try {
- getLogdService().approve(mUid, mGid, mPid, mFd);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- return;
+ // TODO Temporarily approve all the requests to unblock testing failures.
+ try {
+ getLogdService().approve(mUid, mGid, mPid, mFd);
+ } catch (RemoteException e) {
+ e.printStackTrace();
}
-
- // If the access request is coming from native apps, approve the logd access
- // TODO: This is needed to make tooling to work. However,
- // we intend to be stricter with respect to native processes in a follow-up CL
- if (mUid < AID_APP_UID) {
- try {
- getLogdService().approve(mUid, mGid, mPid, mFd);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- return;
- }
-
- final int procState = LocalServices.getService(ActivityManagerInternal.class)
- .getUidProcessState(mUid);
- // If the process is foreground, send a notification for user consent
- if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
- String clientInfo = getClientInfo(mUid, mGid, mPid, mFd);
- sendNotification(0, clientInfo, mUid, mGid, mPid, mFd);
- } else {
- /**
- * If the process is background, add a background process change listener and
- * monitor if the process status changes.
- * To avoid clients registering multiple listeners, we limit the number of
- * maximum listeners to MAX_UID_IMPORTANCE_COUNT_LISTENER.
- **/
- if (mActivityManager == null) {
- return;
- }
-
- synchronized (LogcatManagerService.this) {
- if (sUidImportanceListenerCount < MAX_UID_IMPORTANCE_COUNT_LISTENER) {
- // Trigger addOnUidImportanceListener when there is an update from
- // the importance of the process
- mActivityManager.addOnUidImportanceListener(new UidImportanceListener(
- mUid, mGid, mPid, mFd,
- RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE),
- RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE);
- sUidImportanceListenerCount++;
- } else {
- try {
- getLogdService().decline(mUid, mGid, mPid, mFd);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
- }
- }
+ return;
}
}
}
diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java
index 204ebfc..b82e3a3 100644
--- a/services/core/java/com/android/server/media/MediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java
@@ -86,7 +86,7 @@
mProviderInfo = null;
} else {
mProviderInfo = new MediaRoute2ProviderInfo.Builder(providerInfo)
- .setUniqueId(mUniqueId)
+ .setUniqueId(mComponentName.getPackageName(), mUniqueId)
.setSystemRouteProvider(mIsSystemRouteProvider)
.build();
}
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 7f997df..b307266 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -64,9 +64,11 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
@@ -2200,9 +2202,21 @@
}
}
+ // Build a composite RouteDiscoveryPreference that matches all of the routes
+ // that match one or more of the individual discovery preferences. It may also
+ // match additional routes. The composite RouteDiscoveryPreference can be used
+ // to query route providers once to obtain all of the routes of interest, which
+ // can be subsequently filtered for the individual discovery preferences.
+ Set<String> preferredFeatures = new HashSet<>();
+ boolean activeScan = false;
+ for (RouteDiscoveryPreference preference : discoveryPreferences) {
+ preferredFeatures.addAll(preference.getPreferredFeatures());
+ activeScan |= preference.shouldPerformActiveScan();
+ }
+ RouteDiscoveryPreference newPreference = new RouteDiscoveryPreference.Builder(
+ List.copyOf(preferredFeatures), activeScan).build();
+
synchronized (service.mLock) {
- RouteDiscoveryPreference newPreference =
- new RouteDiscoveryPreference.Builder(discoveryPreferences).build();
if (newPreference.equals(mUserRecord.mCompositeDiscoveryPreference)) {
return;
}
diff --git a/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java b/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java
index fd141bd..1ae7ac0 100644
--- a/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java
+++ b/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java
@@ -26,6 +26,7 @@
import android.media.metrics.PlaybackStateEvent;
import android.media.metrics.TrackChangeEvent;
import android.os.Binder;
+import android.os.PersistableBundle;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig.Properties;
import android.util.Base64;
@@ -180,6 +181,20 @@
StatsLog.write(statsEvent);
}
+ public void reportBundleMetrics(String sessionId, PersistableBundle metrics, int userId) {
+ int level = loggingLevel();
+ if (level == LOGGING_LEVEL_BLOCKED) {
+ return;
+ }
+
+ int atomid = metrics.getInt("KEY_STATSD_ATOM_NUMBER");
+ switch (atomid) {
+ default:
+ return;
+ // to be extended as we define statsd atoms
+ }
+ }
+
@Override
public void reportPlaybackStateEvent(
String sessionId, PlaybackStateEvent event, int userId) {
@@ -222,6 +237,21 @@
}
@Override
+ public String getTranscodingSessionId(int userId) {
+ return getSessionIdInternal(userId);
+ }
+
+ @Override
+ public String getEditingSessionId(int userId) {
+ return getSessionIdInternal(userId);
+ }
+
+ @Override
+ public String getBundleSessionId(int userId) {
+ return getSessionIdInternal(userId);
+ }
+
+ @Override
public void reportPlaybackErrorEvent(
String sessionId, PlaybackErrorEvent event, int userId) {
int level = loggingLevel();
diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
index b66c466..33ac6cd 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyLogger.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
@@ -16,14 +16,16 @@
package com.android.server.net;
import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
-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.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;
@@ -328,6 +330,8 @@
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/NetworkPolicyManagerInternal.java b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
index 8ef42ff..3cb5878 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
@@ -91,4 +91,10 @@
*/
public abstract void setMeteredRestrictedPackagesAsync(
Set<String> packageNames, int userId);
+
+ /** Informs that Low Power Standby has become active */
+ public abstract void setLowPowerStandbyActive(boolean active);
+
+ /** Informs that the Low Power Standby allowlist has changed */
+ public abstract void setLowPowerStandbyAllowlist(int[] uids);
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 76d06c8..8d05415 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -46,22 +46,23 @@
import static android.net.ConnectivityManager.BLOCKED_REASON_APP_STANDBY;
import static android.net.ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER;
import static android.net.ConnectivityManager.BLOCKED_REASON_DOZE;
+import static android.net.ConnectivityManager.BLOCKED_REASON_LOW_POWER_STANDBY;
import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
import static android.net.ConnectivityManager.BLOCKED_REASON_RESTRICTED_MODE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
+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.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED;
import static android.net.ConnectivityManager.TYPE_MOBILE;
-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.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;
@@ -70,11 +71,13 @@
import static android.net.NetworkPolicyManager.ALLOWED_METERED_REASON_SYSTEM;
import static android.net.NetworkPolicyManager.ALLOWED_METERED_REASON_USER_EXEMPTED;
import static android.net.NetworkPolicyManager.ALLOWED_REASON_FOREGROUND;
+import static android.net.NetworkPolicyManager.ALLOWED_REASON_LOW_POWER_STANDBY_ALLOWLIST;
import static android.net.NetworkPolicyManager.ALLOWED_REASON_NONE;
import static android.net.NetworkPolicyManager.ALLOWED_REASON_POWER_SAVE_ALLOWLIST;
import static android.net.NetworkPolicyManager.ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST;
import static android.net.NetworkPolicyManager.ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS;
import static android.net.NetworkPolicyManager.ALLOWED_REASON_SYSTEM;
+import static android.net.NetworkPolicyManager.ALLOWED_REASON_TOP;
import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
@@ -88,6 +91,7 @@
import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;
import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_UNMETERED;
import static android.net.NetworkPolicyManager.isProcStateAllowedWhileIdleOrPowerSaveMode;
+import static android.net.NetworkPolicyManager.isProcStateAllowedWhileInLowPowerStandby;
import static android.net.NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground;
import static android.net.NetworkPolicyManager.resolveNetworkId;
import static android.net.NetworkPolicyManager.uidPoliciesToString;
@@ -171,11 +175,9 @@
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;
@@ -279,6 +281,7 @@
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;
@@ -477,6 +480,8 @@
volatile boolean mRestrictBackgroundChangedInBsm;
@GuardedBy("mUidRulesFirstLock")
volatile boolean mRestrictedNetworkingMode;
+ @GuardedBy("mUidRulesFirstLock")
+ volatile boolean mLowPowerStandbyActive;
private final boolean mSuppressDefaultPolicy;
@@ -516,6 +521,8 @@
final SparseIntArray mUidFirewallPowerSaveRules = new SparseIntArray();
@GuardedBy("mUidRulesFirstLock")
final SparseIntArray mUidFirewallRestrictedModeRules = new SparseIntArray();
+ @GuardedBy("mUidRulesFirstLock")
+ final SparseIntArray mUidFirewallLowPowerStandbyModeRules = new SparseIntArray();
/** Set of states for the child firewall chains. True if the chain is active. */
@GuardedBy("mUidRulesFirstLock")
@@ -544,6 +551,9 @@
@GuardedBy("mUidRulesFirstLock")
private final SparseBooleanArray mPowerSaveTempWhitelistAppIds = new SparseBooleanArray();
+ @GuardedBy("mUidRulesFirstLock")
+ private final SparseBooleanArray mLowPowerStandbyAllowlistUids = new SparseBooleanArray();
+
/**
* UIDs that have been allowlisted temporarily to be able to have network access despite being
* idle. Other power saving restrictions still apply.
@@ -1012,10 +1022,11 @@
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 snooze from notifications
mContext.registerReceiver(mSnoozeReceiver,
@@ -1239,6 +1250,12 @@
* 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;
}
};
@@ -1500,7 +1517,8 @@
.setType(TYPE_MOBILE)
.setSubscriberId(subscriberId)
.setMetered(true)
- .setDefaultNetwork(true).build();
+ .setDefaultNetwork(true)
+ .setSubId(subId).build();
if (template.matches(probeIdent)) {
return subId;
}
@@ -1737,7 +1755,8 @@
.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)) {
@@ -1969,7 +1988,8 @@
.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);
@@ -2071,7 +2091,8 @@
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()
@@ -2276,7 +2297,8 @@
.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)) {
@@ -3755,6 +3777,7 @@
fout.print("Restrict power: "); fout.println(mRestrictPower);
fout.print("Device idle: "); fout.println(mDeviceIdleMode);
fout.print("Restricted networking mode: "); fout.println(mRestrictedNetworkingMode);
+ fout.print("Low Power Standby mode: "); fout.println(mLowPowerStandbyActive);
synchronized (mMeteredIfacesLock) {
fout.print("Metered ifaces: ");
fout.println(mMeteredIfaces);
@@ -3890,6 +3913,18 @@
fout.decreaseIndent();
}
+ size = mLowPowerStandbyAllowlistUids.size();
+ if (size > 0) {
+ fout.println("Low Power Standby allowlist uids:");
+ fout.increaseIndent();
+ for (int i = 0; i < size; i++) {
+ fout.print("UID=");
+ fout.print(mLowPowerStandbyAllowlistUids.keyAt(i));
+ fout.println();
+ }
+ fout.decreaseIndent();
+ }
+
final SparseBooleanArray knownUids = new SparseBooleanArray();
collectKeys(mUidState, knownUids);
collectKeys(mUidBlockedState, knownUids);
@@ -3971,6 +4006,12 @@
return isProcStateAllowedWhileIdleOrPowerSaveMode(uidState);
}
+ @GuardedBy("mUidRulesFirstLock")
+ private boolean isUidTop(int uid) {
+ final UidState uidState = mUidState.get(uid);
+ return isProcStateAllowedWhileInLowPowerStandby(uidState);
+ }
+
/**
* Process state of UID changed; if needed, will trigger
* {@link #updateRulesForDataUsageRestrictionsUL(int)} and
@@ -3987,8 +4028,10 @@
// state changed, push updated rules
mUidState.put(uid, newUidState);
updateRestrictBackgroundRulesOnUidStatusChangedUL(uid, oldUidState, newUidState);
- if (isProcStateAllowedWhileIdleOrPowerSaveMode(oldUidState)
- != isProcStateAllowedWhileIdleOrPowerSaveMode(newUidState)) {
+ boolean allowedWhileIdleOrPowerSaveModeChanged =
+ isProcStateAllowedWhileIdleOrPowerSaveMode(oldUidState)
+ != isProcStateAllowedWhileIdleOrPowerSaveMode(newUidState);
+ if (allowedWhileIdleOrPowerSaveModeChanged) {
updateRuleForAppIdleUL(uid);
if (mDeviceIdleMode) {
updateRuleForDeviceIdleUL(uid);
@@ -3998,6 +4041,17 @@
}
updateRulesForPowerRestrictionsUL(uid);
}
+ if (mLowPowerStandbyActive) {
+ boolean allowedInLpsChanged =
+ isProcStateAllowedWhileInLowPowerStandby(oldUidState)
+ != isProcStateAllowedWhileInLowPowerStandby(newUidState);
+ if (allowedInLpsChanged) {
+ if (!allowedWhileIdleOrPowerSaveModeChanged) {
+ updateRulesForPowerRestrictionsUL(uid);
+ }
+ updateRuleForLowPowerStandbyUL(uid);
+ }
+ }
return true;
}
} finally {
@@ -4021,6 +4075,9 @@
updateRuleForRestrictPowerUL(uid);
}
updateRulesForPowerRestrictionsUL(uid);
+ if (mLowPowerStandbyActive) {
+ updateRuleForLowPowerStandbyUL(uid);
+ }
return true;
}
}
@@ -4224,6 +4281,50 @@
}
}
+ @GuardedBy("mUidRulesFirstLock")
+ void updateRulesForLowPowerStandbyUL() {
+ Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForLowPowerStandbyUL");
+ try {
+ if (mLowPowerStandbyActive) {
+ mUidFirewallLowPowerStandbyModeRules.clear();
+ for (int i = mUidState.size() - 1; i >= 0; i--) {
+ final int uid = mUidState.keyAt(i);
+ UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
+ if (hasInternetPermissionUL(uid) && uidBlockedState != null
+ && (uidBlockedState.effectiveBlockedReasons
+ & BLOCKED_REASON_LOW_POWER_STANDBY) == 0) {
+ mUidFirewallLowPowerStandbyModeRules.put(mUidBlockedState.keyAt(i),
+ FIREWALL_RULE_ALLOW);
+ }
+ }
+ setUidFirewallRulesUL(FIREWALL_CHAIN_LOW_POWER_STANDBY,
+ mUidFirewallLowPowerStandbyModeRules, CHAIN_TOGGLE_ENABLE);
+ } else {
+ setUidFirewallRulesUL(FIREWALL_CHAIN_LOW_POWER_STANDBY, null, CHAIN_TOGGLE_DISABLE);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
+ }
+ }
+
+ @GuardedBy("mUidRulesFirstLock")
+ void updateRuleForLowPowerStandbyUL(int uid) {
+ if (!hasInternetPermissionUL(uid)) {
+ return;
+ }
+
+ final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
+ if (mUidState.contains(uid) && uidBlockedState != null
+ && (uidBlockedState.effectiveBlockedReasons & BLOCKED_REASON_LOW_POWER_STANDBY)
+ == 0) {
+ mUidFirewallLowPowerStandbyModeRules.put(uid, FIREWALL_RULE_ALLOW);
+ setUidFirewallRule(FIREWALL_CHAIN_LOW_POWER_STANDBY, uid, FIREWALL_RULE_ALLOW);
+ } else {
+ mUidFirewallLowPowerStandbyModeRules.delete(uid);
+ setUidFirewallRule(FIREWALL_CHAIN_LOW_POWER_STANDBY, uid, FIREWALL_RULE_DEFAULT);
+ }
+ }
+
/**
* Returns whether a uid is allowlisted from power saving restrictions (eg: Battery Saver, Doze
* mode, and app idle).
@@ -4253,6 +4354,14 @@
return mPowerSaveWhitelistExceptIdleAppIds.get(appId);
}
+ /**
+ * Returns whether a uid is allowlisted from low power standby restrictions.
+ */
+ @GuardedBy("mUidRulesFirstLock")
+ private boolean isAllowlistedFromLowPowerStandbyUL(int uid) {
+ return mLowPowerStandbyAllowlistUids.get(uid);
+ }
+
// NOTE: since both fw_dozable and fw_powersave uses the same map
// (mPowerSaveTempWhitelistAppIds) for allowlisting, we can reuse their logic in this method.
@GuardedBy("mUidRulesFirstLock")
@@ -4590,6 +4699,7 @@
mPowerSaveTempWhitelistAppIds.delete(uid);
mAppIdleTempWhitelistAppIds.delete(uid);
mUidFirewallRestrictedModeRules.delete(uid);
+ mUidFirewallLowPowerStandbyModeRules.delete(uid);
synchronized (mUidStateCallbackInfos) {
mUidStateCallbackInfos.remove(uid);
}
@@ -4815,6 +4925,7 @@
}
final boolean isForeground = isUidForegroundOnRestrictPowerUL(uid);
+ final boolean isTop = isUidTop(uid);
final boolean isWhitelisted = isWhitelistedFromPowerSaveUL(uid, mDeviceIdleMode);
@@ -4828,17 +4939,21 @@
int newAllowedReasons = ALLOWED_REASON_NONE;
newBlockedReasons |= (mRestrictPower ? BLOCKED_REASON_BATTERY_SAVER : 0);
newBlockedReasons |= (mDeviceIdleMode ? BLOCKED_REASON_DOZE : 0);
+ newBlockedReasons |= (mLowPowerStandbyActive ? BLOCKED_REASON_LOW_POWER_STANDBY : 0);
newBlockedReasons |= (isUidIdle ? BLOCKED_REASON_APP_STANDBY : 0);
newBlockedReasons |= (uidBlockedState.blockedReasons & BLOCKED_REASON_RESTRICTED_MODE);
newAllowedReasons |= (isSystem(uid) ? ALLOWED_REASON_SYSTEM : 0);
newAllowedReasons |= (isForeground ? ALLOWED_REASON_FOREGROUND : 0);
+ newAllowedReasons |= (isTop ? ALLOWED_REASON_TOP : 0);
newAllowedReasons |= (isWhitelistedFromPowerSaveUL(uid, true)
? ALLOWED_REASON_POWER_SAVE_ALLOWLIST : 0);
newAllowedReasons |= (isWhitelistedFromPowerSaveExceptIdleUL(uid)
? ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST : 0);
newAllowedReasons |= (uidBlockedState.allowedReasons
& ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS);
+ newAllowedReasons |= (isAllowlistedFromLowPowerStandbyUL(uid))
+ ? ALLOWED_REASON_LOW_POWER_STANDBY_ALLOWLIST : 0;
uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons
& BLOCKED_METERED_REASON_MASK) | newBlockedReasons;
@@ -4860,6 +4975,7 @@
+ ", mRestrictPower: " + mRestrictPower
+ ", mDeviceIdleMode: " + mDeviceIdleMode
+ ", isForeground=" + isForeground
+ + ", isTop=" + isTop
+ ", isWhitelisted=" + isWhitelisted
+ ", oldUidBlockedState=" + previousUidBlockedState.toString()
+ ", newUidBlockedState=" + uidBlockedState.toString());
@@ -5390,6 +5506,8 @@
mUidFirewallPowerSaveRules.put(uid, rule);
} else if (chain == FIREWALL_CHAIN_RESTRICTED) {
mUidFirewallRestrictedModeRules.put(uid, rule);
+ } else if (chain == FIREWALL_CHAIN_LOW_POWER_STANDBY) {
+ mUidFirewallLowPowerStandbyModeRules.put(uid, rule);
}
try {
@@ -5437,6 +5555,9 @@
.setFirewallUidRule(FIREWALL_CHAIN_POWERSAVE, uid, FIREWALL_RULE_DEFAULT);
mNetworkManager
.setFirewallUidRule(FIREWALL_CHAIN_RESTRICTED, uid, FIREWALL_RULE_DEFAULT);
+ mNetworkManager
+ .setFirewallUidRule(FIREWALL_CHAIN_LOW_POWER_STANDBY, uid,
+ FIREWALL_RULE_DEFAULT);
mNetworkManager.setUidOnMeteredNetworkAllowlist(uid, false);
mNetworkManager.setUidOnMeteredNetworkDenylist(uid, false);
} catch (IllegalStateException e) {
@@ -5712,6 +5833,67 @@
mHandler.obtainMessage(MSG_METERED_RESTRICTED_PACKAGES_CHANGED,
userId, 0, packageNames).sendToTarget();
}
+
+ @Override
+ public void setLowPowerStandbyActive(boolean active) {
+ Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "setLowPowerStandbyActive");
+ try {
+ synchronized (mUidRulesFirstLock) {
+ if (mLowPowerStandbyActive == active) {
+ return;
+ }
+ mLowPowerStandbyActive = active;
+ synchronized (mNetworkPoliciesSecondLock) {
+ if (!mSystemReady) return;
+ }
+
+ forEachUid("updateRulesForRestrictPower",
+ uid -> updateRulesForPowerRestrictionsUL(uid));
+ updateRulesForLowPowerStandbyUL();
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
+ }
+ }
+
+ @Override
+ public void setLowPowerStandbyAllowlist(int[] uids) {
+ synchronized (mUidRulesFirstLock) {
+ final SparseBooleanArray changedUids = new SparseBooleanArray();
+ for (int i = 0; i < mLowPowerStandbyAllowlistUids.size(); i++) {
+ final int oldUid = mLowPowerStandbyAllowlistUids.keyAt(i);
+ if (!ArrayUtils.contains(uids, oldUid)) {
+ changedUids.put(oldUid, true);
+ }
+ }
+
+ for (int i = 0; i < changedUids.size(); i++) {
+ final int deletedUid = changedUids.keyAt(i);
+ mLowPowerStandbyAllowlistUids.delete(deletedUid);
+ }
+
+ for (int newUid : uids) {
+ if (mLowPowerStandbyAllowlistUids.indexOfKey(newUid) < 0) {
+ changedUids.append(newUid, true);
+ mLowPowerStandbyAllowlistUids.append(newUid, true);
+ }
+ }
+
+ if (!mLowPowerStandbyActive) {
+ return;
+ }
+
+ synchronized (mNetworkPoliciesSecondLock) {
+ if (!mSystemReady) return;
+ }
+
+ for (int i = 0; i < changedUids.size(); i++) {
+ final int changedUid = changedUids.keyAt(i);
+ updateRulesForPowerRestrictionsUL(changedUid);
+ updateRuleForLowPowerStandbyUL(changedUid);
+ }
+ }
+ }
}
private void setMeteredRestrictedPackagesInternal(Set<String> packageNames, int userId) {
@@ -5739,17 +5921,6 @@
}
}
- 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);
@@ -5880,6 +6051,9 @@
effectiveBlockedReasons &= ~BLOCKED_METERED_REASON_DATA_SAVER;
effectiveBlockedReasons &= ~BLOCKED_METERED_REASON_USER_RESTRICTED;
}
+ if ((allowedReasons & ALLOWED_REASON_TOP) != 0) {
+ effectiveBlockedReasons &= ~BLOCKED_REASON_LOW_POWER_STANDBY;
+ }
if ((allowedReasons & ALLOWED_REASON_POWER_SAVE_ALLOWLIST) != 0) {
effectiveBlockedReasons &= ~BLOCKED_REASON_BATTERY_SAVER;
effectiveBlockedReasons &= ~BLOCKED_REASON_DOZE;
@@ -5895,6 +6069,10 @@
if ((allowedReasons & ALLOWED_METERED_REASON_USER_EXEMPTED) != 0) {
effectiveBlockedReasons &= ~BLOCKED_METERED_REASON_DATA_SAVER;
}
+ if ((allowedReasons & ALLOWED_REASON_LOW_POWER_STANDBY_ALLOWLIST) != 0) {
+ effectiveBlockedReasons &= ~BLOCKED_REASON_LOW_POWER_STANDBY;
+ }
+
return effectiveBlockedReasons;
}
@@ -5919,6 +6097,7 @@
BLOCKED_REASON_DOZE,
BLOCKED_REASON_APP_STANDBY,
BLOCKED_REASON_RESTRICTED_MODE,
+ BLOCKED_REASON_LOW_POWER_STANDBY,
BLOCKED_METERED_REASON_DATA_SAVER,
BLOCKED_METERED_REASON_USER_RESTRICTED,
BLOCKED_METERED_REASON_ADMIN_DISABLED,
@@ -5927,9 +6106,11 @@
private static final int[] ALLOWED_REASONS = {
ALLOWED_REASON_SYSTEM,
ALLOWED_REASON_FOREGROUND,
+ ALLOWED_REASON_TOP,
ALLOWED_REASON_POWER_SAVE_ALLOWLIST,
ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST,
ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS,
+ ALLOWED_REASON_LOW_POWER_STANDBY_ALLOWLIST,
ALLOWED_METERED_REASON_USER_EXEMPTED,
ALLOWED_METERED_REASON_SYSTEM,
ALLOWED_METERED_REASON_FOREGROUND,
@@ -5947,6 +6128,8 @@
return "APP_STANDBY";
case BLOCKED_REASON_RESTRICTED_MODE:
return "RESTRICTED_MODE";
+ case BLOCKED_REASON_LOW_POWER_STANDBY:
+ return "LOW_POWER_STANDBY";
case BLOCKED_METERED_REASON_DATA_SAVER:
return "DATA_SAVER";
case BLOCKED_METERED_REASON_USER_RESTRICTED:
@@ -5967,12 +6150,16 @@
return "SYSTEM";
case ALLOWED_REASON_FOREGROUND:
return "FOREGROUND";
+ case ALLOWED_REASON_TOP:
+ return "TOP";
case ALLOWED_REASON_POWER_SAVE_ALLOWLIST:
return "POWER_SAVE_ALLOWLIST";
case ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST:
return "POWER_SAVE_EXCEPT_IDLE_ALLOWLIST";
case ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS:
return "RESTRICTED_MODE_PERMISSIONS";
+ case ALLOWED_REASON_LOW_POWER_STANDBY_ALLOWLIST:
+ return "LOW_POWER_STANDBY_ALLOWLIST";
case ALLOWED_METERED_REASON_USER_EXEMPTED:
return "METERED_USER_EXEMPTED";
case ALLOWED_METERED_REASON_SYSTEM:
@@ -6039,7 +6226,8 @@
int powerBlockedReasons = BLOCKED_REASON_APP_STANDBY
| BLOCKED_REASON_DOZE
- | BLOCKED_REASON_BATTERY_SAVER;
+ | BLOCKED_REASON_BATTERY_SAVER
+ | BLOCKED_REASON_LOW_POWER_STANDBY;
if ((effectiveBlockedReasons & powerBlockedReasons) != 0) {
uidRule |= RULE_REJECT_ALL;
} else if ((blockedReasons & powerBlockedReasons) != 0) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index aafcc58..3d34976 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -83,6 +83,7 @@
import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
+import static android.service.notification.NotificationListenerService.REASON_ASSISTANT_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
@@ -476,6 +477,14 @@
@LoggingOnly
private static final long RATE_LIMIT_TOASTS = 174840628L;
+ /**
+ * Whether listeners understand the more specific reason provided for notification
+ * cancellations from an assistant, rather than using the more general REASON_LISTENER_CANCEL.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2)
+ private static final long NOTIFICATION_LOG_ASSISTANT_CANCEL = 195579280L;
+
private IActivityManager mAm;
private ActivityTaskManagerInternal mAtm;
private ActivityManager mActivityManager;
@@ -4388,6 +4397,13 @@
synchronized (mNotificationLock) {
final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
+ // Cancellation reason. If the token comes from assistant, label the
+ // cancellation as coming from the assistant; default to LISTENER_CANCEL.
+ int reason = REASON_LISTENER_CANCEL;
+ if (mAssistants.isServiceTokenValidLocked(token)) {
+ reason = REASON_ASSISTANT_CANCEL;
+ }
+
if (keys != null) {
final int N = keys.length;
for (int i = 0; i < N; i++) {
@@ -4400,7 +4416,7 @@
}
cancelNotificationFromListenerLocked(info, callingUid, callingPid,
r.getSbn().getPackageName(), r.getSbn().getTag(),
- r.getSbn().getId(), userId);
+ r.getSbn().getId(), userId, reason);
}
} else {
cancelAllLocked(callingUid, callingPid, info.userid,
@@ -4494,12 +4510,13 @@
*/
@GuardedBy("mNotificationLock")
private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
- int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
+ int callingUid, int callingPid, String pkg, String tag, int id, int userId,
+ int reason) {
int mustNotHaveFlags = FLAG_ONGOING_EVENT;
cancelNotification(callingUid, callingPid, pkg, tag, id, 0 /* mustHaveFlags */,
mustNotHaveFlags,
true,
- userId, REASON_LISTENER_CANCEL, info);
+ userId, reason, info);
}
/**
@@ -4641,13 +4658,17 @@
try {
synchronized (mNotificationLock) {
final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
+ int cancelReason = REASON_LISTENER_CANCEL;
+ if (mAssistants.isServiceTokenValidLocked(token)) {
+ cancelReason = REASON_ASSISTANT_CANCEL;
+ }
if (info.supportsProfiles()) {
Slog.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
+ "from " + info.component
+ " use cancelNotification(key) instead.");
} else {
cancelNotificationFromListenerLocked(info, callingUid, callingPid,
- pkg, tag, id, info.userid);
+ pkg, tag, id, info.userid, cancelReason);
}
}
} finally {
@@ -5784,6 +5805,7 @@
|| channel.isImportanceLockedByCriticalDeviceFunction());
final StatusBarNotification adjustedSbn = notificationRecord.getSbn();
userId = adjustedSbn.getUser().getIdentifier();
+ int uid = adjustedSbn.getUid();
ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
if (summaries == null) {
summaries = new ArrayMap<>();
@@ -5830,7 +5852,7 @@
notificationRecord.getIsAppImportanceLocked());
summaries.put(pkg, summarySbn.getKey());
}
- if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
+ if (summaryRecord != null && checkDisqualifyingFeatures(userId, uid,
summaryRecord.getSbn().getId(), summaryRecord.getSbn().getTag(), summaryRecord,
true)) {
return summaryRecord;
@@ -6506,7 +6528,7 @@
@VisibleForTesting
protected void fixNotification(Notification notification, String pkg, String tag, int id,
- int userId) throws NameNotFoundException {
+ int userId) throws NameNotFoundException, RemoteException {
final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
(userId == UserHandle.USER_ALL) ? USER_SYSTEM : userId);
@@ -6540,6 +6562,21 @@
actions.toArray(notification.actions);
}
+ // Ensure MediaStyle has correct permissions for remote device extras
+ if (notification.isStyle(Notification.MediaStyle.class)) {
+ int hasMediaContentControlPermission = mPackageManager.checkPermission(
+ android.Manifest.permission.MEDIA_CONTENT_CONTROL, pkg, userId);
+ if (hasMediaContentControlPermission != PERMISSION_GRANTED) {
+ notification.extras.remove(Notification.EXTRA_MEDIA_REMOTE_DEVICE);
+ notification.extras.remove(Notification.EXTRA_MEDIA_REMOTE_ICON);
+ notification.extras.remove(Notification.EXTRA_MEDIA_REMOTE_INTENT);
+ if (DBG) {
+ Slog.w(TAG, "Package " + pkg + ": Use of setRemotePlayback requires the "
+ + "MEDIA_CONTENT_CONTROL permission");
+ }
+ }
+ }
+
// Remote views? Are they too big?
checkRemoteViews(pkg, tag, id, notification);
}
@@ -6801,7 +6838,6 @@
return false;
}
-
// blocked apps
boolean isBlocked = !areNotificationsEnabledForPackageInt(pkg, uid);
synchronized (mNotificationLock) {
@@ -7194,10 +7230,12 @@
if (mAssistants.isEnabled()) {
mAssistants.onNotificationEnqueuedLocked(r);
mHandler.postDelayed(
- new PostNotificationRunnable(r.getKey(), enqueueElapsedTimeMs),
+ new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
+ r.getUid(), enqueueElapsedTimeMs),
DELAY_FOR_ASSISTANT_TIME);
} else {
- mHandler.post(new PostNotificationRunnable(r.getKey(), enqueueElapsedTimeMs));
+ mHandler.post(new PostNotificationRunnable(r.getKey(),
+ r.getSbn().getPackageName(), r.getUid(), enqueueElapsedTimeMs));
}
}
}
@@ -7221,16 +7259,19 @@
protected class PostNotificationRunnable implements Runnable {
private final String key;
private final long postElapsedTimeMs;
+ private final String pkg;
+ private final int uid;
- PostNotificationRunnable(String key, @ElapsedRealtimeLong long postElapsedTimeMs) {
+ PostNotificationRunnable(String key, String pkg, int uid,
+ @ElapsedRealtimeLong long postElapsedTimeMs) {
this.key = key;
+ this.pkg = pkg;
+ this.uid = uid;
this.postElapsedTimeMs = postElapsedTimeMs;
}
@Override
public void run() {
- String pkg = StatusBarNotification.getPkgFromKey(key);
- int uid = StatusBarNotification.getUidFromKey(key);
boolean appBanned = !areNotificationsEnabledForPackageInt(pkg, uid);
synchronized (mNotificationLock) {
try {
@@ -11049,6 +11090,12 @@
&& (reason == REASON_CHANNEL_REMOVED || reason == REASON_CLEAR_DATA)) {
reason = REASON_CHANNEL_BANNED;
}
+ // apps before T don't know about REASON_ASSISTANT, so replace it with the
+ // previously-used case, REASON_LISTENER_CANCEL
+ if (!CompatChanges.isChangeEnabled(NOTIFICATION_LOG_ASSISTANT_CANCEL, info.uid)
+ && reason == REASON_ASSISTANT_CANCEL) {
+ reason = REASON_LISTENER_CANCEL;
+ }
listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
} catch (RemoteException ex) {
Slog.e(TAG, "unable to notify listener (removed): " + info, ex);
diff --git a/services/core/java/com/android/server/notification/NotificationRecordLogger.java b/services/core/java/com/android/server/notification/NotificationRecordLogger.java
index f3dc2dd..9a89efa 100644
--- a/services/core/java/com/android/server/notification/NotificationRecordLogger.java
+++ b/services/core/java/com/android/server/notification/NotificationRecordLogger.java
@@ -16,6 +16,7 @@
package com.android.server.notification;
+import static android.service.notification.NotificationListenerService.REASON_ASSISTANT_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_CLICK;
import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
@@ -180,7 +181,9 @@
+ " shade.")
NOTIFICATION_CANCEL_USER_SHADE(192),
@UiEvent(doc = "Notification was canceled due to user dismissal from the lockscreen")
- NOTIFICATION_CANCEL_USER_LOCKSCREEN(193);
+ NOTIFICATION_CANCEL_USER_LOCKSCREEN(193),
+ @UiEvent(doc = "Notification was canceled due to an assistant adjustment update.")
+ NOTIFICATION_CANCEL_ASSISTANT(906);
private final int mId;
NotificationCancelledEvent(int id) {
@@ -206,6 +209,9 @@
if ((REASON_CLICK <= reason) && (reason <= REASON_TIMEOUT)) {
return NotificationCancelledEvent.values()[reason];
}
+ if (reason == REASON_ASSISTANT_CANCEL) {
+ return NotificationCancelledEvent.NOTIFICATION_CANCEL_ASSISTANT;
+ }
if (NotificationManagerService.DBG) {
throw new IllegalArgumentException("Unexpected cancel reason " + reason);
}
diff --git a/services/core/java/com/android/server/notification/PermissionHelper.java b/services/core/java/com/android/server/notification/PermissionHelper.java
index 5d18069..d80d9f3 100644
--- a/services/core/java/com/android/server/notification/PermissionHelper.java
+++ b/services/core/java/com/android/server/notification/PermissionHelper.java
@@ -178,8 +178,14 @@
boolean userSet, boolean reviewRequired) {
assertFlag();
final long callingId = Binder.clearCallingIdentity();
+ // Do not change fixed permissions, and do not change non-user set permissions that are
+ // granted by default, or granted by role.
+ if (isPermissionFixed(packageName, userId)
+ || (isPermissionGrantedByDefaultOrRole(packageName, userId) && !userSet)) {
+ return;
+ }
try {
- if (grant) {
+ if (grant && !reviewRequired) {
mPermManager.grantRuntimePermission(packageName, NOTIFICATION_PERMISSION, userId);
} else {
mPermManager.revokeRuntimePermission(packageName, NOTIFICATION_PERMISSION, userId,
@@ -210,8 +216,10 @@
if (pkgPerm == null || pkgPerm.packageName == null) {
return;
}
- setNotificationPermission(pkgPerm.packageName, pkgPerm.userId, pkgPerm.granted,
- pkgPerm.userSet, !pkgPerm.userSet);
+ if (!isPermissionFixed(pkgPerm.packageName, pkgPerm.userId)) {
+ setNotificationPermission(pkgPerm.packageName, pkgPerm.userId, pkgPerm.granted,
+ pkgPerm.userSet, !pkgPerm.userSet);
+ }
}
public boolean isPermissionFixed(String packageName, @UserIdInt int userId) {
@@ -239,7 +247,26 @@
try {
int flags = mPermManager.getPermissionFlags(packageName, NOTIFICATION_PERMISSION,
userId);
- return (flags & PackageManager.FLAG_PERMISSION_USER_SET) != 0;
+ return (flags & (PackageManager.FLAG_PERMISSION_USER_SET
+ | PackageManager.FLAG_PERMISSION_USER_FIXED)) != 0;
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Could not reach system server", e);
+ }
+ return false;
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+
+ boolean isPermissionGrantedByDefaultOrRole(String packageName, @UserIdInt int userId) {
+ assertFlag();
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ try {
+ int flags = mPermManager.getPermissionFlags(packageName, NOTIFICATION_PERMISSION,
+ userId);
+ return (flags & (PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT
+ | PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE)) != 0;
} catch (RemoteException e) {
Slog.e(TAG, "Could not reach system server", e);
}
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index e8ad2bb..1185890 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -391,6 +391,7 @@
if (migrateToPermission) {
r.importance = appImportance;
+ r.migrateToPm = true;
if (r.uid != UNKNOWN_UID) {
// Don't call into permission system until we have a valid uid
PackagePermission pkgPerm = new PackagePermission(
@@ -2575,7 +2576,7 @@
synchronized (mPackagePreferences) {
mPackagePreferences.put(packagePreferencesKey(r.pkg, r.uid), r);
}
- if (mPermissionHelper.isMigrationEnabled()) {
+ if (mPermissionHelper.isMigrationEnabled() && r.migrateToPm) {
try {
PackagePermission p = new PackagePermission(
r.pkg, UserHandle.getUserId(r.uid),
@@ -2841,6 +2842,8 @@
boolean userDemotedMsgApp = false;
boolean hasSentValidBubble = false;
+ boolean migrateToPm = false;
+
Delegate delegate = null;
ArrayMap<String, NotificationChannel> channels = new ArrayMap<>();
Map<String, NotificationChannelGroup> groups = new ConcurrentHashMap<>();
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 2d87099..39ee0f4 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -582,6 +582,8 @@
ApexInfo ai = parsingApexInfo.get(parseResult.scanFile);
if (throwable == null) {
+ // Calling hideAsFinal to assign derived fields for the app info flags.
+ parseResult.parsedPackage.hideAsFinal();
final PackageInfo packageInfo = PackageInfoWithoutStateUtils.generate(
parseResult.parsedPackage, ai, flags);
if (packageInfo == null) {
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 5b2e097..4f1a9e7 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -33,11 +33,6 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.SigningDetails;
import android.content.pm.UserInfo;
-import com.android.server.pm.pkg.component.ParsedComponent;
-import com.android.server.pm.pkg.component.ParsedInstrumentation;
-import com.android.server.pm.pkg.component.ParsedIntentInfo;
-import com.android.server.pm.pkg.component.ParsedMainComponent;
-import com.android.server.pm.pkg.component.ParsedProvider;
import android.os.Binder;
import android.os.Process;
import android.os.Trace;
@@ -62,6 +57,11 @@
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.pkg.component.ParsedComponent;
+import com.android.server.pm.pkg.component.ParsedInstrumentation;
+import com.android.server.pm.pkg.component.ParsedIntentInfo;
+import com.android.server.pm.pkg.component.ParsedMainComponent;
+import com.android.server.pm.pkg.component.ParsedProvider;
import com.android.server.utils.Snappable;
import com.android.server.utils.SnapshotCache;
import com.android.server.utils.Snapshots;
@@ -158,6 +158,7 @@
private final FeatureConfig mFeatureConfig;
private final OverlayReferenceMapper mOverlayReferenceMapper;
private final StateProvider mStateProvider;
+ private final PackageManagerInternal mPmInternal;
private SigningDetails mSystemSigningDetails;
private Set<String> mProtectedBroadcasts = new ArraySet<>();
@@ -250,13 +251,15 @@
String[] forceQueryableList,
boolean systemAppsQueryable,
@Nullable OverlayReferenceMapper.Provider overlayProvider,
- Executor backgroundExecutor) {
+ Executor backgroundExecutor,
+ PackageManagerInternal pmInternal) {
mFeatureConfig = featureConfig;
mForceQueryableByDevicePackageNames = forceQueryableList;
mSystemAppsQueryable = systemAppsQueryable;
mOverlayReferenceMapper = new OverlayReferenceMapper(true /*deferRebuild*/,
overlayProvider);
mStateProvider = stateProvider;
+ mPmInternal = pmInternal;
mBackgroundExecutor = backgroundExecutor;
mSnapshot = makeCache();
}
@@ -289,6 +292,7 @@
}
mBackgroundExecutor = null;
+ mPmInternal = null;
mSnapshot = new SnapshotCache.Sealed<>();
}
@@ -508,7 +512,7 @@
};
AppsFilter appsFilter = new AppsFilter(stateProvider, featureConfig,
forcedQueryablePackageNames, forceSystemAppsQueryable, null,
- injector.getBackgroundExecutor());
+ injector.getBackgroundExecutor(), pms);
featureConfig.setAppsFilter(appsFilter);
return appsFilter;
}
@@ -1236,9 +1240,9 @@
// shared user members to re-establish visibility between them and other packages.
// NOTE: this must come after all removals from data structures but before we update the
// cache
- if (setting.getSharedUser() != null) {
- final ArraySet<? extends PackageStateInternal> sharedUserPackages =
- setting.getSharedUser().getPackageStates();
+ if (setting.hasSharedUser()) {
+ final ArraySet<PackageStateInternal> sharedUserPackages =
+ mPmInternal.getSharedUserPackages(setting.getSharedUserAppId());
for (int i = sharedUserPackages.size() - 1; i >= 0; i--) {
if (sharedUserPackages.valueAt(i) == setting) {
continue;
@@ -1250,9 +1254,9 @@
synchronized (mCacheLock) {
removeAppIdFromVisibilityCache(setting.getAppId());
- if (mShouldFilterCache != null && setting.getSharedUser() != null) {
- final ArraySet<? extends PackageStateInternal> sharedUserPackages =
- setting.getSharedUser().getPackageStates();
+ if (mShouldFilterCache != null && setting.hasSharedUser()) {
+ final ArraySet<PackageStateInternal> sharedUserPackages =
+ mPmInternal.getSharedUserPackages(setting.getSharedUserAppId());
for (int i = sharedUserPackages.size() - 1; i >= 0; i--) {
PackageStateInternal siblingSetting =
sharedUserPackages.valueAt(i);
@@ -1367,13 +1371,14 @@
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "callingSetting instanceof");
}
if (callingSetting instanceof PackageStateInternal) {
- if (((PackageStateInternal) callingSetting).getSharedUser() == null) {
- callingPkgSetting = (PackageStateInternal) callingSetting;
- callingSharedPkgSettings = null;
- } else {
+ final PackageStateInternal packageState = (PackageStateInternal) callingSetting;
+ if (packageState.hasSharedUser()) {
callingPkgSetting = null;
- callingSharedPkgSettings = ((PackageStateInternal) callingSetting)
- .getSharedUser().getPackageStates();
+ callingSharedPkgSettings = mPmInternal.getSharedUserPackages(
+ packageState.getSharedUserAppId());
+ } else {
+ callingPkgSetting = packageState;
+ callingSharedPkgSettings = null;
}
} else {
callingPkgSetting = null;
diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java
index 0ae3418..0d9ccd2 100644
--- a/services/core/java/com/android/server/pm/Computer.java
+++ b/services/core/java/com/android/server/pm/Computer.java
@@ -640,4 +640,12 @@
@Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
Pair<PackageStateInternal, SharedUserApi> getPackageOrSharedUser(int appId);
+
+ @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
+ @Nullable
+ SharedUserApi getSharedUser(int sharedUserAppIde);
+
+ @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
+ @NonNull
+ ArraySet<PackageStateInternal> getSharedUserPackages(int sharedUserAppId);
}
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index c942a43..04f0aab 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -264,7 +264,7 @@
}
@Nullable
- public SharedUserSetting getSharedUser(String name) {
+ public SharedUserSetting getSharedUserFromId(String name) {
try {
return mSettings.getSharedUserLPw(name, 0, 0, false /*create*/);
} catch (PackageManagerException ignored) {
@@ -298,6 +298,31 @@
public Collection<SharedUserSetting> getAllSharedUsers() {
return mSettings.getAllSharedUsersLPw();
}
+
+ @Nullable
+ public SharedUserApi getSharedUserFromPackageName(String packageName) {
+ return mSettings.getSharedUserSettingLPr(packageName);
+ }
+
+ @Nullable
+ public SharedUserApi getSharedUserFromAppId(int sharedUserAppId) {
+ return (SharedUserSetting) mSettings.getSettingLPr(sharedUserAppId);
+ }
+
+ @NonNull
+ public ArraySet<PackageStateInternal> getSharedUserPackages(int sharedUserAppId) {
+ final ArraySet<PackageStateInternal> res = new ArraySet<>();
+ final SharedUserSetting sharedUserSetting =
+ (SharedUserSetting) mSettings.getSettingLPr(sharedUserAppId);
+ if (sharedUserSetting != null) {
+ final ArraySet<? extends PackageStateInternal> sharedUserPackages =
+ sharedUserSetting.getPackageStates();
+ for (PackageStateInternal ps : sharedUserPackages) {
+ res.add(ps);
+ }
+ }
+ return res;
+ }
}
private static final Comparator<ProviderInfo> sProviderInitOrderSorter = (p1, p2) -> {
@@ -1570,7 +1595,8 @@
PackageInfo pi = new PackageInfo();
pi.packageName = ps.getPackageName();
pi.setLongVersionCode(ps.getVersionCode());
- pi.sharedUserId = (ps.getSharedUser() != null) ? ps.getSharedUser().getName() : null;
+ SharedUserApi sharedUser = mSettings.getSharedUserFromPackageName(pi.packageName);
+ pi.sharedUserId = (sharedUser != null) ? sharedUser.getName() : null;
pi.firstInstallTime = state.getFirstInstallTime();
pi.lastUpdateTime = ps.getLastUpdateTime();
@@ -2134,6 +2160,9 @@
private String[] getPackagesForUidInternal(int uid, int callingUid) {
final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null;
final int userId = UserHandle.getUserId(uid);
+ if (Process.isSupplemental(uid)) {
+ uid = getSupplementalProcessUid();
+ }
final int appId = UserHandle.getAppId(uid);
return getPackagesForUidInternalBody(callingUid, userId, appId, isCallerInstantApp);
}
@@ -2369,6 +2398,10 @@
}
public final boolean isCallerSameApp(String packageName, int uid) {
+ if (Process.isSupplemental(uid)) {
+ return (packageName != null
+ && packageName.equals(mService.getSupplementalProcessPackageName()));
+ }
AndroidPackage pkg = mPackages.get(packageName);
return pkg != null
&& UserHandle.getAppId(uid) == pkg.getUid();
@@ -4288,6 +4321,9 @@
if (getInstantAppPackageName(callingUid) != null) {
return null;
}
+ if (Process.isSupplemental(uid)) {
+ uid = getSupplementalProcessUid();
+ }
final int callingUserId = UserHandle.getUserId(callingUid);
final int appId = UserHandle.getAppId(uid);
final Object obj = mSettings.getSettingBase(appId);
@@ -4296,7 +4332,7 @@
if (shouldFilterApplication(sus, callingUid, callingUserId)) {
return null;
}
- return sus.name + ":" + sus.userId;
+ return sus.name + ":" + sus.mAppId;
} else if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
if (shouldFilterApplication(ps, callingUid, callingUserId)) {
@@ -4320,7 +4356,11 @@
final int callingUserId = UserHandle.getUserId(callingUid);
final String[] names = new String[uids.length];
for (int i = uids.length - 1; i >= 0; i--) {
- final int appId = UserHandle.getAppId(uids[i]);
+ int uid = uids[i];
+ if (Process.isSupplemental(uid)) {
+ uid = getSupplementalProcessUid();
+ }
+ final int appId = UserHandle.getAppId(uid);
final Object obj = mSettings.getSettingBase(appId);
if (obj instanceof SharedUserSetting) {
final SharedUserSetting sus = (SharedUserSetting) obj;
@@ -4352,10 +4392,10 @@
if (getInstantAppPackageName(callingUid) != null) {
return Process.INVALID_UID;
}
- final SharedUserSetting suid = mSettings.getSharedUser(sharedUserName);
+ final SharedUserSetting suid = mSettings.getSharedUserFromId(sharedUserName);
if (suid != null && !shouldFilterApplication(suid, callingUid,
UserHandle.getUserId(callingUid))) {
- return suid.userId;
+ return suid.mAppId;
}
return Process.INVALID_UID;
}
@@ -4366,6 +4406,9 @@
if (getInstantAppPackageName(callingUid) != null) {
return 0;
}
+ if (Process.isSupplemental(uid)) {
+ uid = getSupplementalProcessUid();
+ }
final int callingUserId = UserHandle.getUserId(callingUid);
final int appId = UserHandle.getAppId(uid);
final Object obj = mSettings.getSettingBase(appId);
@@ -4391,6 +4434,9 @@
if (getInstantAppPackageName(callingUid) != null) {
return 0;
}
+ if (Process.isSupplemental(uid)) {
+ uid = getSupplementalProcessUid();
+ }
final int callingUserId = UserHandle.getUserId(callingUid);
final int appId = UserHandle.getAppId(uid);
final Object obj = mSettings.getSettingBase(appId);
@@ -4415,6 +4461,9 @@
if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
return false;
}
+ if (Process.isSupplemental(uid)) {
+ uid = getSupplementalProcessUid();
+ }
final int appId = UserHandle.getAppId(uid);
final Object obj = mSettings.getSettingBase(appId);
if (obj instanceof SharedUserSetting) {
@@ -5407,7 +5456,7 @@
public SparseArray<String> getAppsWithSharedUserIds() {
final SparseArray<String> sharedUserIds = new SparseArray<>();
for (SharedUserSetting setting : mSettings.getAllSharedUsers()) {
- sharedUserIds.put(UserHandle.getAppId(setting.userId), setting.name);
+ sharedUserIds.put(UserHandle.getAppId(setting.mAppId), setting.name);
}
return sharedUserIds;
}
@@ -5417,12 +5466,12 @@
public String[] getSharedUserPackagesForPackage(@NonNull String packageName,
@UserIdInt int userId) {
final PackageStateInternal packageSetting = mSettings.getPackage(packageName);
- if (packageSetting == null || packageSetting.getSharedUser() == null) {
+ if (packageSetting == null || mSettings.getSharedUserFromPackageName(packageName) == null) {
return EmptyArray.STRING;
}
ArraySet<? extends PackageStateInternal> packages =
- packageSetting.getSharedUser().getPackageStates();
+ mSettings.getSharedUserFromPackageName(packageName).getPackageStates();
final int numPackages = packages.size();
String[] res = new String[numPackages];
int i = 0;
@@ -5539,6 +5588,9 @@
@Override
public int getUidTargetSdkVersion(int uid) {
+ if (Process.isSupplemental(uid)) {
+ uid = getSupplementalProcessUid();
+ }
final int appId = UserHandle.getAppId(uid);
final SettingBase settingBase = mSettings.getSettingBase(appId);
if (settingBase instanceof SharedUserSetting) {
@@ -5565,6 +5617,9 @@
@Nullable
@Override
public ArrayMap<String, ProcessInfo> getProcessesForUid(int uid) {
+ if (Process.isSupplemental(uid)) {
+ uid = getSupplementalProcessUid();
+ }
final int appId = UserHandle.getAppId(uid);
final SettingBase settingBase = mSettings.getSettingBase(appId);
if (settingBase instanceof SharedUserSetting) {
@@ -5594,4 +5649,20 @@
return null;
}
}
+
+ private int getSupplementalProcessUid() {
+ return getPackage(mService.getSupplementalProcessPackageName()).getUid();
+ }
+
+ @Nullable
+ @Override
+ public SharedUserApi getSharedUser(int sharedUserAppId) {
+ return mSettings.getSharedUserFromAppId(sharedUserAppId);
+ }
+
+ @NonNull
+ @Override
+ public ArraySet<PackageStateInternal> getSharedUserPackages(int sharedUserAppId) {
+ return mSettings.getSharedUserPackages(sharedUserAppId);
+ }
}
diff --git a/services/core/java/com/android/server/pm/ComputerLocked.java b/services/core/java/com/android/server/pm/ComputerLocked.java
index 40d4c03..583348b 100644
--- a/services/core/java/com/android/server/pm/ComputerLocked.java
+++ b/services/core/java/com/android/server/pm/ComputerLocked.java
@@ -852,4 +852,20 @@
return super.getPackageOrSharedUser(appId);
}
}
+
+ @Nullable
+ @Override
+ public SharedUserApi getSharedUser(int sharedUserAppId) {
+ synchronized (mLock) {
+ return super.getSharedUser(sharedUserAppId);
+ }
+ }
+
+ @NonNull
+ @Override
+ public ArraySet<PackageStateInternal> getSharedUserPackages(int sharedUserAppId) {
+ synchronized (mLock) {
+ return super.getSharedUserPackages(sharedUserAppId);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/pm/ComputerTracker.java b/services/core/java/com/android/server/pm/ComputerTracker.java
index 24c08d1..72e67da 100644
--- a/services/core/java/com/android/server/pm/ComputerTracker.java
+++ b/services/core/java/com/android/server/pm/ComputerTracker.java
@@ -1283,4 +1283,20 @@
return current.mComputer.getPackageOrSharedUser(appId);
}
}
+
+ @Nullable
+ @Override
+ public SharedUserApi getSharedUser(int sharedUserAppId) {
+ try (ThreadComputer current = snapshot()) {
+ return current.mComputer.getSharedUser(sharedUserAppId);
+ }
+ }
+
+ @NonNull
+ @Override
+ public ArraySet<PackageStateInternal> getSharedUserPackages(int sharedUserAppId) {
+ try (ThreadComputer current = snapshot()) {
+ return current.mComputer.getSharedUserPackages(sharedUserAppId);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index db860fe..3220b31 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -222,8 +222,12 @@
deleteFlags | PackageManager.DELETE_CHATTY, info, true);
}
if (res && pkg != null) {
+ final boolean packageInstalledForSomeUsers;
+ synchronized (mPm.mLock) {
+ packageInstalledForSomeUsers = mPm.mPackages.get(pkg.getPackageName()) != null;
+ }
mPm.mInstantAppRegistry.onPackageUninstalled(pkg, uninstalledPs,
- info.mRemovedUsers);
+ info.mRemovedUsers, packageInstalledForSomeUsers);
}
synchronized (mPm.mLock) {
if (res) {
@@ -463,13 +467,14 @@
private void clearPackageStateForUserLIF(PackageSetting ps, int userId,
PackageRemovedInfo outInfo, int flags) {
final AndroidPackage pkg;
+ final SharedUserSetting sus;
synchronized (mPm.mLock) {
pkg = mPm.mPackages.get(ps.getPackageName());
+ sus = mPm.mSettings.getSharedUserSettingLPr(ps);
}
mAppDataHelper.destroyAppProfilesLIF(pkg);
- final SharedUserSetting sus = ps.getSharedUser();
final List<AndroidPackage> sharedUserPkgs =
sus != null ? sus.getPackages() : Collections.emptyList();
final PreferredActivityHelper preferredActivityHelper = new PreferredActivityHelper(mPm);
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index c418a10..684e6ba 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -86,7 +86,6 @@
import static com.android.server.pm.PackageManagerServiceUtils.compressedFileExists;
import static com.android.server.pm.PackageManagerServiceUtils.deriveAbiOverride;
import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
-import static com.android.server.pm.PackageManagerServiceUtils.verifySignatures;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -254,15 +253,21 @@
final String realPkgName = request.mRealPkgName;
final List<String> changedAbiCodePath = result.mChangedAbiCodePath;
final PackageSetting pkgSetting;
- if (request.mPkgSetting != null && request.mPkgSetting.getSharedUser() != null
- && request.mPkgSetting.getSharedUser() != result.mPkgSetting.getSharedUser()) {
- // shared user changed, remove from old shared user
- final SharedUserSetting sus = request.mPkgSetting.getSharedUser();
- sus.removePackage(request.mPkgSetting);
- // Prune unused SharedUserSetting
- if (mPm.mSettings.checkAndPruneSharedUserLPw(sus, false)) {
- // Set the app ID in removed info for UID_REMOVED broadcasts
- reconciledPkg.mInstallResult.mRemovedInfo.mRemovedAppId = sus.userId;
+ if (request.mPkgSetting != null) {
+ SharedUserSetting requestSharedUserSetting = mPm.mSettings.getSharedUserSettingLPr(
+ request.mPkgSetting);
+ SharedUserSetting resultSharedUserSetting = mPm.mSettings.getSharedUserSettingLPr(
+ result.mPkgSetting);
+ if (requestSharedUserSetting != null
+ && requestSharedUserSetting != resultSharedUserSetting) {
+ // shared user changed, remove from old shared user
+ requestSharedUserSetting.removePackage(request.mPkgSetting);
+ // Prune unused SharedUserSetting
+ if (mPm.mSettings.checkAndPruneSharedUserLPw(requestSharedUserSetting, false)) {
+ // Set the app ID in removed info for UID_REMOVED broadcasts
+ reconciledPkg.mInstallResult.mRemovedInfo.mRemovedAppId =
+ requestSharedUserSetting.mAppId;
+ }
}
}
if (result.mExistingSettingCopied) {
@@ -279,8 +284,9 @@
mPm.mSettings.removeRenamedPackageLPw(parsedPackage.getPackageName());
}
}
- if (pkgSetting.getSharedUser() != null) {
- pkgSetting.getSharedUser().addPackage(pkgSetting);
+ SharedUserSetting sharedUserSetting = mPm.mSettings.getSharedUserSettingLPr(pkgSetting);
+ if (sharedUserSetting != null) {
+ sharedUserSetting.addPackage(pkgSetting);
}
if (reconciledPkg.mInstallArgs != null
&& reconciledPkg.mInstallArgs.mForceQueryableOverride) {
@@ -327,8 +333,8 @@
ksms.removeAppKeySetDataLPw(pkg.getPackageName());
}
if (reconciledPkg.mSharedUserSignaturesChanged) {
- pkgSetting.getSharedUser().signaturesChanged = Boolean.TRUE;
- pkgSetting.getSharedUser().signatures.mSigningDetails = reconciledPkg.mSigningDetails;
+ sharedUserSetting.signaturesChanged = Boolean.TRUE;
+ sharedUserSetting.signatures.mSigningDetails = reconciledPkg.mSigningDetails;
}
pkgSetting.setSigningDetails(reconciledPkg.mSigningDetails);
@@ -963,7 +969,7 @@
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
reconciledPackages = ReconcilePackageUtils.reconcilePackages(
reconcileRequest, mSharedLibraries,
- mPm.mSettings.getKeySetManagerService());
+ mPm.mSettings.getKeySetManagerService(), mPm.mSettings);
} catch (ReconcileFailure e) {
for (InstallRequest request : requests) {
request.mInstallResult.setError("Reconciliation failed...", e);
@@ -1242,7 +1248,10 @@
// we'll check this again later when scanning, but we want to
// bail early here before tripping over redefined permissions.
final KeySetManagerService ksms = mPm.mSettings.getKeySetManagerService();
- if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
+ final SharedUserSetting signatureCheckSus = mPm.mSettings.getSharedUserSettingLPr(
+ signatureCheckPs);
+ if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, signatureCheckSus,
+ scanFlags)) {
if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, parsedPackage)) {
throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
+ parsedPackage.getPackageName() + " upgrade keys do not match the "
@@ -1257,7 +1266,9 @@
ReconcilePackageUtils.isRecoverSignatureUpdateNeeded(
mPm.getSettingsVersionForPackage(parsedPackage));
// We don't care about disabledPkgSetting on install for now.
- final boolean compatMatch = verifySignatures(signatureCheckPs, null,
+ final boolean compatMatch =
+ PackageManagerServiceUtils.verifySignatures(signatureCheckPs,
+ signatureCheckSus, null,
parsedPackage.getSigningDetails(), compareCompat, compareRecover,
isRollback);
// The new KeySets will be re-added later in the scanning process.
@@ -1496,6 +1507,7 @@
int targetParseFlags = parseFlags;
final PackageSetting ps;
final PackageSetting disabledPs;
+ final SharedUserSetting sharedUserSetting;
if (replace) {
final String pkgName11 = parsedPackage.getPackageName();
synchronized (mPm.mLock) {
@@ -1527,10 +1539,11 @@
ps = mPm.mSettings.getPackageLPr(pkgName11);
disabledPs = mPm.mSettings.getDisabledSystemPkgLPr(ps);
+ sharedUserSetting = mPm.mSettings.getSharedUserSettingLPr(ps);
// verify signatures are valid
final KeySetManagerService ksms = mPm.mSettings.getKeySetManagerService();
- if (ksms.shouldCheckUpgradeKeySetLocked(ps, scanFlags)) {
+ if (ksms.shouldCheckUpgradeKeySetLocked(ps, sharedUserSetting, scanFlags)) {
if (!ksms.checkUpgradeKeySetLocked(ps, parsedPackage)) {
throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
"New package not signed by keys specified by upgrade-keysets: "
@@ -1743,16 +1756,18 @@
final PackageSetting sourcePackageSetting;
final KeySetManagerService ksms;
+ final SharedUserSetting sharedUserSetting;
synchronized (mPm.mLock) {
sourcePackageSetting = mPm.mSettings.getPackageLPr(sourcePackageName);
ksms = mPm.mSettings.getKeySetManagerService();
+ sharedUserSetting = mPm.mSettings.getSharedUserSettingLPr(sourcePackageSetting);
}
final SigningDetails sourceSigningDetails = (sourcePackageSetting == null
? SigningDetails.UNKNOWN : sourcePackageSetting.getSigningDetails());
if (sourcePackageName.equals(parsedPackage.getPackageName())
&& (ksms.shouldCheckUpgradeKeySetLocked(
- sourcePackageSetting, scanFlags))) {
+ sourcePackageSetting, sharedUserSetting, scanFlags))) {
return ksms.checkUpgradeKeySetLocked(sourcePackageSetting, parsedPackage);
} else {
@@ -3574,7 +3589,8 @@
mPm.getSettingsVersionForPackage(parsedPackage)));
final Map<String, ReconciledPackage> reconcileResult =
ReconcilePackageUtils.reconcilePackages(reconcileRequest,
- mSharedLibraries, mPm.mSettings.getKeySetManagerService());
+ mSharedLibraries, mPm.mSettings.getKeySetManagerService(),
+ mPm.mSettings);
appIdCreated = optimisticallyRegisterAppId(scanResult);
commitReconciledScanResultLocked(reconcileResult.get(pkgName),
mPm.mUserManager.getUserIds());
@@ -3658,6 +3674,7 @@
final PackageSetting installedPkgSetting;
final PackageSetting originalPkgSetting;
final SharedUserSetting sharedUserSetting;
+ SharedUserSetting oldSharedUserSetting = null;
synchronized (mPm.mLock) {
platformPackage = mPm.getPlatformPackage();
@@ -3683,17 +3700,21 @@
&& (parseFlags & ParsingPackageUtils.PARSE_CHATTY) != 0
&& sharedUserSetting != null) {
Log.d(TAG, "Shared UserID " + parsedPackage.getSharedUserId()
- + " (uid=" + sharedUserSetting.userId + "):"
+ + " (uid=" + sharedUserSetting.mAppId + "):"
+ " packages=" + sharedUserSetting.packages);
}
+ if (installedPkgSetting != null) {
+ oldSharedUserSetting = mPm.mSettings.getSharedUserSettingLPr(installedPkgSetting);
+ }
}
final boolean isPlatformPackage = platformPackage != null
&& platformPackage.getPackageName().equals(parsedPackage.getPackageName());
- return new ScanRequest(parsedPackage, sharedUserSetting,
+ return new ScanRequest(parsedPackage, oldSharedUserSetting,
installedPkgSetting == null ? null : installedPkgSetting.getPkg() /* oldPkg */,
installedPkgSetting /* packageSetting */,
+ sharedUserSetting,
disabledPkgSetting /* disabledPackageSetting */,
originalPkgSetting /* originalPkgSetting */,
realPkgName, parseFlags, scanFlags, isPlatformPackage, user, cpuAbiOverride);
@@ -3703,8 +3724,8 @@
private ScanResult scanPackageNewLI(@NonNull ParsedPackage parsedPackage,
final @ParsingPackageUtils.ParseFlags int parseFlags,
@PackageManagerService.ScanFlags int scanFlags, long currentTime,
- @Nullable UserHandle user, String cpuAbiOverride) throws PackageManagerException {
-
+ @Nullable UserHandle user, String cpuAbiOverride)
+ throws PackageManagerException {
final ScanRequest initialScanRequest = prepareInitialScanRequest(parsedPackage, parseFlags,
scanFlags, user, cpuAbiOverride);
final PackageSetting installedPkgSetting = initialScanRequest.mPkgSetting;
@@ -3725,8 +3746,9 @@
synchronized (mPm.mLock) {
assertPackageIsValid(parsedPackage, parseFlags, newScanFlags);
final ScanRequest request = new ScanRequest(parsedPackage,
- initialScanRequest.mSharedUserSetting,
- initialScanRequest.mOldPkg, installedPkgSetting, disabledPkgSetting,
+ initialScanRequest.mOldSharedUserSetting,
+ initialScanRequest.mOldPkg, installedPkgSetting,
+ initialScanRequest.mSharedUserSetting, disabledPkgSetting,
initialScanRequest.mOriginalPkgSetting, initialScanRequest.mRealPkgName,
parseFlags, scanFlags, initialScanRequest.mIsPlatformPackage, user,
cpuAbiOverride);
@@ -3775,8 +3797,9 @@
if (scanSystemPartition && isSystemPkgUpdated) {
// we're updating the disabled package, so, scan it as the package setting
final ScanRequest request = new ScanRequest(parsedPackage,
- initialScanRequest.mSharedUserSetting,
+ mPm.mSettings.getSharedUserSettingLPr(disabledPkgSetting),
null, disabledPkgSetting /* pkgSetting */,
+ initialScanRequest.mSharedUserSetting,
null /* disabledPkgSetting */, null /* originalPkgSetting */,
null, parseFlags, scanFlags,
initialScanRequest.mIsPlatformPackage, user, null);
@@ -3994,12 +4017,14 @@
if (!verifyPackageUpdateLPr(originalPs, pkg)) {
// the new package is incompatible with the original
continue;
- } else if (originalPs.getSharedUser() != null) {
- if (!originalPs.getSharedUser().name.equals(pkg.getSharedUserId())) {
+ } else if (mPm.mSettings.getSharedUserSettingLPr(originalPs) != null) {
+ final String sharedUserSettingsName =
+ mPm.mSettings.getSharedUserSettingLPr(originalPs).name;
+ if (!sharedUserSettingsName.equals(pkg.getSharedUserId())) {
// the shared user id is incompatible with the original
Slog.w(TAG, "Unable to migrate data from " + originalPs.getPackageName()
- + " to " + pkg.getPackageName() + ": old uid "
- + originalPs.getSharedUser().name
+ + " to " + pkg.getPackageName() + ": old shared user settings name "
+ + sharedUserSettingsName
+ " differs from " + pkg.getSharedUserId());
continue;
}
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index ea6e458..39a2839 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -444,14 +444,14 @@
}
public void onPackageUninstalled(@NonNull AndroidPackage pkg, @NonNull PackageSetting ps,
- @NonNull int[] userIds) {
+ @NonNull int[] userIds, boolean packageInstalledForSomeUsers) {
if (ps == null) {
return;
}
synchronized (mLock) {
for (int userId : userIds) {
- if (ps.getInstalled(userId)) {
+ if (packageInstalledForSomeUsers && ps.getInstalled(userId)) {
continue;
}
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index afca350..5c29833 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -32,6 +32,7 @@
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.pkg.SharedUserApi;
import com.android.server.utils.WatchedArrayMap;
import org.xmlpull.v1.XmlPullParser;
@@ -354,9 +355,10 @@
return mKeySets.get(id) != null;
}
- public boolean shouldCheckUpgradeKeySetLocked(PackageStateInternal oldPs, int scanFlags) {
+ public boolean shouldCheckUpgradeKeySetLocked(PackageStateInternal oldPs,
+ SharedUserApi sharedUserSetting, int scanFlags) {
// Can't rotate keys during boot or if sharedUser.
- if (oldPs == null || (scanFlags&SCAN_INITIAL) != 0 || (oldPs.getSharedUser() != null)
+ if (oldPs == null || (scanFlags & SCAN_INITIAL) != 0 || (sharedUserSetting != null)
|| !oldPs.getKeySetData().isUsingUpgradeKeySets()) {
return false;
}
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index ca87685..6b3ce77 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -18,6 +18,7 @@
import static android.app.ActivityOptions.KEY_SPLASH_SCREEN_THEME;
import static android.app.PendingIntent.FLAG_IMMUTABLE;
+import static android.app.PendingIntent.FLAG_MUTABLE;
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
@@ -872,7 +873,7 @@
PendingIntent injectCreatePendingIntent(int requestCode, @NonNull Intent[] intents,
int flags, Bundle options, String ownerPackage, int ownerUserId) {
return mActivityManagerInternal.getPendingIntentActivityAsApp(requestCode, intents,
- flags, options, ownerPackage, ownerUserId);
+ flags, null /* options */, ownerPackage, ownerUserId);
}
@Override
@@ -1218,8 +1219,9 @@
}
@Override
- public PendingIntent getActivityLaunchIntent(ComponentName component, Bundle opts,
+ public PendingIntent getActivityLaunchIntent(String callingPackage, ComponentName component,
UserHandle user) {
+ ensureShortcutPermission(callingPackage);
if (!canAccessProfile(user.getIdentifier(), "Cannot start activity")) {
throw new ActivityNotFoundException("Activity could not be found");
}
@@ -1237,7 +1239,7 @@
// calling identity to mirror the startActivityAsUser() call which does not validate
// the calling user
return PendingIntent.getActivityAsUser(mContext, 0 /* requestCode */, launchIntent,
- FLAG_IMMUTABLE, opts, user);
+ FLAG_MUTABLE, null /* opts */, user);
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 44b9877..d230004 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -29,7 +29,6 @@
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
import static android.content.pm.PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SPLIT;
-import static android.content.pm.PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
import static android.content.pm.PackageManager.INSTALL_STAGED;
import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
@@ -62,8 +61,6 @@
import android.app.admin.DevicePolicyManagerInternal;
import android.content.ComponentName;
import android.content.Context;
-import android.content.IIntentReceiver;
-import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
@@ -104,7 +101,6 @@
import android.os.FileBridge;
import android.os.FileUtils;
import android.os.Handler;
-import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
@@ -562,19 +558,6 @@
return install();
}
- private void updateRemoteStatusReceiver(IntentSender remoteStatusReceiver) {
- synchronized (mLock) {
- setRemoteStatusReceiver(remoteStatusReceiver);
- if (isMultiPackage()) {
- final IntentSender childIntentSender = new ChildStatusIntentReceiver(
- mChildSessions.clone(), remoteStatusReceiver).getIntentSender();
- for (int i = mChildSessions.size() - 1; i >= 0; --i) {
- mChildSessions.valueAt(i).setRemoteStatusReceiver(childIntentSender);
- }
- }
- }
- }
-
@Override
public boolean hasParentSessionId() {
return PackageInstallerSession.this.hasParentSessionId();
@@ -1778,71 +1761,6 @@
}
}
- private class ChildStatusIntentReceiver {
- private final SparseArray<PackageInstallerSession> mChildSessionsRemaining;
- private final IntentSender mStatusReceiver;
- private final IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
- @Override
- public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
- IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
- statusUpdate(intent);
- }
- };
-
- private ChildStatusIntentReceiver(SparseArray<PackageInstallerSession> remainingSessions,
- IntentSender statusReceiver) {
- this.mChildSessionsRemaining = remainingSessions;
- this.mStatusReceiver = statusReceiver;
- }
-
- public IntentSender getIntentSender() {
- return new IntentSender((IIntentSender) mLocalSender);
- }
-
- public void statusUpdate(Intent intent) {
- mHandler.post(() -> {
- if (mChildSessionsRemaining.size() == 0) {
- // no children to deal with, ignore.
- return;
- }
- final boolean destroyed;
- synchronized (mLock) {
- destroyed = mDestroyed;
- }
- if (destroyed) {
- // the parent has already been terminated, ignore.
- return;
- }
- final int sessionId = intent.getIntExtra(
- PackageInstaller.EXTRA_SESSION_ID, 0);
- final int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS,
- PackageInstaller.STATUS_FAILURE);
- final int sessionIndex = mChildSessionsRemaining.indexOfKey(sessionId);
- final String message = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
- if (PackageInstaller.STATUS_SUCCESS == status) {
- mChildSessionsRemaining.removeAt(sessionIndex);
- if (mChildSessionsRemaining.size() == 0) {
- destroyInternal();
- dispatchSessionFinished(INSTALL_SUCCEEDED,
- "Session installed", null);
- }
- } else if (PackageInstaller.STATUS_PENDING_USER_ACTION == status) {
- try {
- mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
- } catch (IntentSender.SendIntentException ignore) {
- }
- } else { // failure, let's forward and clean up this session.
- intent.putExtra(PackageInstaller.EXTRA_SESSION_ID,
- PackageInstallerSession.this.sessionId);
- mChildSessionsRemaining.clear(); // we're done. Don't send any more.
- destroyInternal();
- dispatchSessionFinished(INSTALL_FAILED_INTERNAL_ERROR,
- "Child session " + sessionId + " failed: " + message, null);
- }
- });
- }
- }
-
/**
* Returns whether or not a package can be installed while Secure FRP is enabled.
* <p>
@@ -2049,28 +1967,15 @@
}
private void onSessionVerificationFailure(int error, String msg) {
- final String msgWithErrorCode = PackageManager.installStatusToString(error, msg);
- Slog.e(TAG, "Failed to verify session " + sessionId + " [" + msgWithErrorCode + "]");
+ Slog.e(TAG, "Failed to verify session " + sessionId);
if (isStaged()) {
- // This will clean up the session when it reaches the terminal state
- mStagedSession.setSessionFailed(
- SessionInfo.SESSION_VERIFICATION_FAILED, msgWithErrorCode);
mStagedSession.notifyEndPreRebootVerification();
- } else {
- // Session is sealed and committed but could not be verified, we need to destroy it.
- destroy();
}
// Dispatch message to remove session from PackageInstallerService.
dispatchSessionFinished(error, msg, null);
maybeFinishChildSessions(error, msg);
}
- private void onSessionInstallationFailure(int error, String detailedMessage) {
- Slog.e(TAG, "Install of session " + sessionId + " failed: " + detailedMessage);
- destroyInternal();
- dispatchSessionFinished(error, detailedMessage, null);
- }
-
private void onSystemDataLoaderUnrecoverable() {
final DeletePackageHelper deletePackageHelper = new DeletePackageHelper(mPm);
final String packageName = getPackageName();
@@ -2285,7 +2190,9 @@
verifyNonStaged();
} catch (PackageManagerException e) {
final String completeMsg = ExceptionUtils.getCompleteMessage(e);
- onSessionVerificationFailure(e.error, completeMsg);
+ final String errorMsg = PackageManager.installStatusToString(e.error, completeMsg);
+ setSessionFailed(e.error, errorMsg);
+ onSessionVerificationFailure(e.error, errorMsg);
}
}
@@ -2428,7 +2335,7 @@
// the flag.
mStageDirInUse = true;
}
- mSessionProvider.getSessionVerifier().verifyNonStaged(this, (error, msg) -> {
+ mSessionProvider.getSessionVerifier().verify(this, (error, msg) -> {
mHandler.post(() -> {
if (error == INSTALL_SUCCEEDED) {
onVerificationComplete();
@@ -2518,23 +2425,12 @@
@WorkerThread
private void onVerificationComplete() {
- // APK verification is done. Continue the installation depending on whether it is a
- // staged session or not. For a staged session, we will hand it over to the staging
- // manager to complete the installation.
if (isStaged()) {
- mSessionProvider.getSessionVerifier().verifyStaged(mStagedSession, (error, msg) -> {
- mStagedSession.notifyEndPreRebootVerification();
- if (error == SessionInfo.SESSION_NO_ERROR) {
- mStagingManager.commitSession(mStagedSession);
- sendUpdateToRemoteStatusReceiver(INSTALL_SUCCEEDED, "Session staged", null);
- } else {
- dispatchSessionFinished(INSTALL_FAILED_VERIFICATION_FAILURE, msg, null);
- maybeFinishChildSessions(INSTALL_FAILED_VERIFICATION_FAILURE, msg);
- }
- });
+ mStagedSession.notifyEndPreRebootVerification();
+ mStagingManager.commitSession(mStagedSession);
+ sendUpdateToRemoteStatusReceiver(INSTALL_SUCCEEDED, "Session staged", null);
return;
}
-
install();
}
@@ -4142,7 +4038,7 @@
}
}
- private void setSessionReady() {
+ void setSessionReady() {
synchronized (mLock) {
// Do not allow destroyed/failed session to change state
if (mDestroyed || mSessionFailed) return;
@@ -4155,7 +4051,7 @@
mCallback.onSessionChanged(this);
}
- private void setSessionFailed(int errorCode, String errorMessage) {
+ void setSessionFailed(int errorCode, String errorMessage) {
synchronized (mLock) {
// Do not allow destroyed/failed session to change state
if (mDestroyed || mSessionFailed) return;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ee5c638..5c68fac 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1515,7 +1515,8 @@
return;
}
AndroidPackage pkg = packageState.getPkg();
- SharedUserApi sharedUser = packageState.getSharedUser();
+ SharedUserApi sharedUser = m.mComputer.getSharedUser(
+ packageState.getSharedUserAppId());
String oldSeInfo = AndroidPackageUtils.getSeInfo(pkg, packageState);
if (pkg == null) {
@@ -7557,7 +7558,7 @@
if (packageState == null) {
return new ArraySet<>();
}
- return packageState.getUserStateOrDefault(userId).getEnabledComponentsNoCopy();
+ return packageState.getUserStateOrDefault(userId).getEnabledComponents();
}
@Override
@@ -7566,7 +7567,7 @@
if (packageState == null) {
return new ArraySet<>();
}
- return packageState.getUserStateOrDefault(userId).getDisabledComponentsNoCopy();
+ return packageState.getUserStateOrDefault(userId).getDisabledComponents();
}
@Override
@@ -7867,6 +7868,18 @@
migrateAppsData);
}
+ @Override
+ @NonNull
+ public ArraySet<PackageStateInternal> getSharedUserPackages(int sharedUserAppId) {
+ return PackageManagerService.this.mComputer.getSharedUserPackages(sharedUserAppId);
+ }
+
+ @Override
+ @Nullable
+ public SharedUserApi getSharedUserApi(int sharedUserAppId) {
+ return mComputer.getSharedUser(sharedUserAppId);
+ }
+
@NonNull
@Override
public PackageStateMutator.InitialState recordInitialState() {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index d6340b5..0dae12f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -505,6 +505,7 @@
* @throws PackageManagerException if the signatures did not match.
*/
public static boolean verifySignatures(PackageSetting pkgSetting,
+ @Nullable SharedUserSetting sharedUserSetting,
PackageSetting disabledPkgSetting, SigningDetails parsedSignatures,
boolean compareCompat, boolean compareRecover, boolean isRollback)
throws PackageManagerException {
@@ -555,10 +556,8 @@
}
}
// Check for shared user signatures
- if (pkgSetting.getSharedUser() != null
- && pkgSetting.getSharedUser().signatures.mSigningDetails
- != SigningDetails.UNKNOWN) {
-
+ if (sharedUserSetting != null
+ && sharedUserSetting.getSigningDetails() != SigningDetails.UNKNOWN) {
// Already existing package. Make sure signatures match. In case of signing certificate
// rotation, the packages with newer certs need to be ok with being sharedUserId with
// the older ones. We check to see if either the new package is signed by an older cert
@@ -566,32 +565,32 @@
// with being sharedUser with the existing signing cert.
boolean match =
parsedSignatures.checkCapability(
- pkgSetting.getSharedUser().signatures.mSigningDetails,
+ sharedUserSetting.getSigningDetails(),
SigningDetails.CertCapabilities.SHARED_USER_ID)
- || pkgSetting.getSharedUser().signatures.mSigningDetails.checkCapability(
+ || sharedUserSetting.getSigningDetails().checkCapability(
parsedSignatures,
SigningDetails.CertCapabilities.SHARED_USER_ID);
// Special case: if the sharedUserId capability check failed it could be due to this
// being the only package in the sharedUserId so far and the lineage being updated to
// deny the sharedUserId capability of the previous key in the lineage.
- if (!match && pkgSetting.getSharedUser().packages.size() == 1
- && pkgSetting.getSharedUser().packages
+ if (!match && sharedUserSetting.packages.size() == 1
+ && sharedUserSetting.packages
.valueAt(0).getPackageName().equals(packageName)) {
match = true;
}
if (!match && compareCompat) {
match = matchSignaturesCompat(
- packageName, pkgSetting.getSharedUser().signatures, parsedSignatures);
+ packageName, sharedUserSetting.signatures, parsedSignatures);
}
if (!match && compareRecover) {
match =
matchSignaturesRecover(packageName,
- pkgSetting.getSharedUser().signatures.mSigningDetails,
+ sharedUserSetting.signatures.mSigningDetails,
parsedSignatures,
SigningDetails.CertCapabilities.SHARED_USER_ID)
|| matchSignaturesRecover(packageName,
parsedSignatures,
- pkgSetting.getSharedUser().signatures.mSigningDetails,
+ sharedUserSetting.signatures.mSigningDetails,
SigningDetails.CertCapabilities.SHARED_USER_ID);
compatMatch |= match;
}
@@ -599,14 +598,14 @@
throw new PackageManagerException(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
"Package " + packageName
+ " has no signatures that match those in shared user "
- + pkgSetting.getSharedUser().name + "; ignoring!");
+ + sharedUserSetting.name + "; ignoring!");
}
// It is possible that this package contains a lineage that blocks sharedUserId access
// to an already installed package in the sharedUserId signed with a previous key.
// Iterate over all of the packages in the sharedUserId and ensure any that are signed
// with a key in this package's lineage have the SHARED_USER_ID capability granted.
if (parsedSignatures.hasPastSigningCertificates()) {
- for (PackageSetting shUidPkgSetting : pkgSetting.getSharedUser().packages) {
+ for (PackageSetting shUidPkgSetting : sharedUserSetting.packages) {
// if the current package in the sharedUserId is the package being updated then
// skip this check as the update may revoke the sharedUserId capability from
// the key with which this app was previously signed.
@@ -633,7 +632,7 @@
// If the lineage of this package diverges from the lineage of the sharedUserId then
// do not allow the installation to proceed.
if (!parsedSignatures.hasCommonAncestor(
- pkgSetting.getSharedUser().signatures.mSigningDetails)) {
+ sharedUserSetting.signatures.mSigningDetails)) {
throw new PackageManagerException(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
"Package " + packageName + " has a signing lineage "
+ "that diverges from the lineage of the sharedUserId");
diff --git a/services/core/java/com/android/server/pm/PackageSessionVerifier.java b/services/core/java/com/android/server/pm/PackageSessionVerifier.java
index 9db215e..6b57deb 100644
--- a/services/core/java/com/android/server/pm/PackageSessionVerifier.java
+++ b/services/core/java/com/android/server/pm/PackageSessionVerifier.java
@@ -94,7 +94,7 @@
/**
* Runs verifications that are common to both staged and non-staged sessions.
*/
- public void verifyNonStaged(PackageInstallerSession session, Callback callback) {
+ public void verify(PackageInstallerSession session, Callback callback) {
mHandler.post(() -> {
try {
storeSession(session.mStagedSession);
@@ -109,6 +109,8 @@
}
verifyAPK(session, callback);
} catch (PackageManagerException e) {
+ String errorMessage = PackageManager.installStatusToString(e.error, e.getMessage());
+ session.setSessionFailed(SessionInfo.SESSION_VERIFICATION_FAILED, errorMessage);
callback.onResult(e.error, e.getMessage());
}
});
@@ -128,7 +130,19 @@
@Override
public void onPackageInstalled(String basePackageName, int returnCode, String msg,
Bundle extras) {
- callback.onResult(returnCode, msg);
+ if (session.isStaged() && returnCode == PackageManager.INSTALL_SUCCEEDED) {
+ // Continue verification for staged sessions
+ verifyStaged(session.mStagedSession, callback);
+ return;
+ }
+ if (returnCode != PackageManager.INSTALL_SUCCEEDED) {
+ String errorMessage = PackageManager.installStatusToString(returnCode, msg);
+ session.setSessionFailed(SessionInfo.SESSION_VERIFICATION_FAILED, errorMessage);
+ callback.onResult(returnCode, msg);
+ } else {
+ session.setSessionReady();
+ callback.onResult(PackageManager.INSTALL_SUCCEEDED, null);
+ }
}
};
final VerificationParams verifyingSession = makeVerificationParams(session, observer);
@@ -171,7 +185,7 @@
* Note it is the responsibility of the caller to ensure the staging files remain unchanged
* while the verification is in progress.
*/
- void verifyStaged(StagingManager.StagedSession session, Callback callback) {
+ private void verifyStaged(StagingManager.StagedSession session, Callback callback) {
Slog.d(TAG, "Starting preRebootVerification for session " + session.sessionId());
mHandler.post(() -> {
try {
@@ -202,7 +216,7 @@
}
private void onVerificationSuccess(StagingManager.StagedSession session, Callback callback) {
- callback.onResult(SessionInfo.SESSION_NO_ERROR, null);
+ callback.onResult(PackageManager.INSTALL_SUCCEEDED, null);
}
private void onVerificationFailure(StagingManager.StagedSession session, Callback callback,
@@ -213,7 +227,7 @@
// failed on next step and staging directory for session will be deleted.
}
session.setSessionFailed(errorCode, errorMessage);
- callback.onResult(errorCode, errorMessage);
+ callback.onResult(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE, errorMessage);
}
private void dispatchVerifyApex(StagingManager.StagedSession session, Callback callback) {
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index bd32d03..f06ae1e 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -52,6 +52,7 @@
import com.android.server.pm.pkg.PackageUserStateInternal;
import com.android.server.pm.pkg.SuspendParams;
import com.android.server.utils.SnapshotCache;
+import com.android.server.utils.WatchedArraySet;
import libcore.util.EmptyArray;
@@ -76,12 +77,9 @@
public class PackageSetting extends SettingBase implements PackageStateInternal {
/**
- * Temporary holding space for the shared user ID. While parsing package settings, the
- * shared users tag may come after the packages. In this case, we must delay linking the
- * shared user setting with the package setting. The shared user ID lets us link the
- * two objects.
+ * The shared user ID lets us link this object to {@link SharedUserSetting}.
*/
- private int sharedUserId;
+ private int mSharedUserAppId;
@Nullable
private Map<String, Set<String>> mimeGroups;
@@ -130,13 +128,6 @@
@Nullable
private AndroidPackage pkg;
- /**
- * WARNING. The object reference is important. We perform integer equality and NOT
- * object equality to check whether shared user settings are the same.
- */
- @Nullable
- private SharedUserSetting sharedUser;
-
/** @see AndroidPackage#getPath() */
@NonNull
private File mPath;
@@ -210,7 +201,7 @@
String legacyNativeLibraryPath, String primaryCpuAbi,
String secondaryCpuAbi, String cpuAbiOverride,
long longVersionCode, int pkgFlags, int pkgPrivateFlags,
- int sharedUserId,
+ int sharedUserAppId,
String[] usesSdkLibraries, long[] usesSdkLibrariesVersionsMajor,
String[] usesStaticLibraries, long[] usesStaticLibrariesVersions,
Map<String, Set<String>> mimeGroups,
@@ -231,7 +222,7 @@
this.versionCode = longVersionCode;
this.signatures = new PackageSignatures();
this.installSource = InstallSource.EMPTY;
- this.sharedUserId = sharedUserId;
+ this.mSharedUserAppId = sharedUserAppId;
mDomainSetId = domainSetId;
copyMimeGroups(mimeGroups);
mSnapshot = makeCache();
@@ -259,9 +250,8 @@
PackageSetting(@NonNull PackageSetting original, boolean sealedSnapshot) {
super(original);
- copyPackageSetting(original);
+ copyPackageSetting(original, sealedSnapshot);
if (sealedSnapshot) {
- sharedUser = sharedUser == null ? null : sharedUser.snapshot();
mSnapshot = new SnapshotCache.Sealed();
} else {
mSnapshot = makeCache();
@@ -313,10 +303,6 @@
proto.end(packageToken);
}
- public boolean isSharedUser() {
- return sharedUser != null;
- }
-
public PackageSetting setAppId(int appId) {
this.mAppId = appId;
onChanged();
@@ -489,11 +475,18 @@
return this;
}
- public int getSharedUserIdInt() {
- if (sharedUser != null) {
- return sharedUser.userId;
- }
- return sharedUserId;
+ public void setSharedUserAppId(int sharedUserAppId) {
+ mSharedUserAppId = sharedUserAppId;
+ }
+
+ @Override
+ public int getSharedUserAppId() {
+ return mSharedUserAppId;
+ }
+
+ @Override
+ public boolean hasSharedUser() {
+ return mSharedUserAppId > 0;
}
@Override
@@ -523,7 +516,7 @@
/** Updates all fields in the current setting from another. */
public void updateFrom(PackageSetting other) {
- copyPackageSetting(other);
+ copyPackageSetting(other, false /* sealedSnapshot */);
Set<String> mimeGroupNames = other.mimeGroups != null ? other.mimeGroups.keySet() : null;
updateMimeGroups(mimeGroupNames);
@@ -564,9 +557,7 @@
@Deprecated
@Override
public LegacyPermissionState getLegacyPermissionState() {
- return (sharedUser != null)
- ? sharedUser.getLegacyPermissionState()
- : super.getLegacyPermissionState();
+ return super.getLegacyPermissionState();
}
public PackageSetting setInstallPermissionsFixed(boolean installPermissionsFixed) {
@@ -618,16 +609,15 @@
return this;
}
- public void copyPackageSetting(PackageSetting other) {
+ public void copyPackageSetting(PackageSetting other, boolean sealedSnapshot) {
super.copySettingBase(other);
- sharedUserId = other.sharedUserId;
+ mSharedUserAppId = other.mSharedUserAppId;
mLoadingProgress = other.mLoadingProgress;
legacyNativeLibraryPath = other.legacyNativeLibraryPath;
mName = other.mName;
mRealName = other.mRealName;
mAppId = other.mAppId;
pkg = other.pkg;
- sharedUser = other.sharedUser;
mPath = other.mPath;
mPathString = other.mPathString;
mPrimaryCpuAbi = other.mPrimaryCpuAbi;
@@ -661,8 +651,12 @@
other.usesStaticLibrariesVersions.length) : null;
mUserStates.clear();
for (int i = 0; i < other.mUserStates.size(); i++) {
- mUserStates.put(other.mUserStates.keyAt(i),
- new PackageUserStateImpl(this, other.mUserStates.valueAt(i)));
+ if (sealedSnapshot) {
+ mUserStates.put(other.mUserStates.keyAt(i),
+ other.mUserStates.valueAt(i).snapshot());
+ } else {
+ mUserStates.put(other.mUserStates.keyAt(i), other.mUserStates.valueAt(i));
+ }
}
if (mOldCodePaths != null) {
@@ -882,42 +876,48 @@
setUserState(userId, otherState.getCeDataInode(), otherState.getEnabledState(),
otherState.isInstalled(), otherState.isStopped(), otherState.isNotLaunched(),
otherState.isHidden(), otherState.getDistractionFlags(),
- otherState.getSuspendParams(), otherState.isInstantApp(),
+ otherState.getSuspendParams() == null
+ ? null : otherState.getSuspendParams().untrackedStorage(),
+ otherState.isInstantApp(),
otherState.isVirtualPreload(), otherState.getLastDisableAppCaller(),
- new ArraySet<>(otherState.getEnabledComponentsNoCopy()),
- new ArraySet<>(otherState.getDisabledComponentsNoCopy()),
+ otherState.getEnabledComponentsNoCopy() == null
+ ? null : otherState.getEnabledComponentsNoCopy().untrackedStorage(),
+ otherState.getDisabledComponentsNoCopy() == null
+ ? null : otherState.getDisabledComponentsNoCopy().untrackedStorage(),
otherState.getInstallReason(), otherState.getUninstallReason(),
otherState.getHarmfulAppWarning(), otherState.getSplashScreenTheme(),
otherState.getFirstInstallTime());
}
- ArraySet<String> getEnabledComponents(int userId) {
+ WatchedArraySet<String> getEnabledComponents(int userId) {
return readUserState(userId).getEnabledComponentsNoCopy();
}
- ArraySet<String> getDisabledComponents(int userId) {
+ WatchedArraySet<String> getDisabledComponents(int userId) {
return readUserState(userId).getDisabledComponentsNoCopy();
}
- void setEnabledComponents(ArraySet<String> components, int userId) {
+ /** Test only */
+ void setEnabledComponents(WatchedArraySet<String> components, int userId) {
modifyUserState(userId).setEnabledComponents(components);
onChanged();
}
- void setDisabledComponents(ArraySet<String> components, int userId) {
+ /** Test only */
+ void setDisabledComponents(WatchedArraySet<String> components, int userId) {
modifyUserState(userId).setDisabledComponents(components);
onChanged();
}
- void setEnabledComponentsCopy(ArraySet<String> components, int userId) {
+ void setEnabledComponentsCopy(WatchedArraySet<String> components, int userId) {
modifyUserState(userId).setEnabledComponents(components != null
- ? new ArraySet<String>(components) : null);
+ ? components.untrackedStorage() : null);
onChanged();
}
- void setDisabledComponentsCopy(ArraySet<String> components, int userId) {
+ void setDisabledComponentsCopy(WatchedArraySet<String> components, int userId) {
modifyUserState(userId).setDisabledComponents(components != null
- ? new ArraySet<String>(components) : null);
+ ? components.untrackedStorage() : null);
onChanged();
}
@@ -1168,12 +1168,6 @@
return getPkg();
}
- @Nullable
- @Override
- public int getSharedUserId() {
- return sharedUser == null ? -1 : sharedUser.userId;
- }
-
@NonNull
public SigningInfo getSigningInfo() {
return new SigningInfo(signatures.mSigningDetails);
@@ -1238,12 +1232,6 @@
return this;
}
- public PackageSetting setSharedUser(SharedUserSetting sharedUser) {
- this.sharedUser = sharedUser;
- onChanged();
- return this;
- }
-
public PackageSetting setCategoryOverride(int categoryHint) {
this.categoryOverride = categoryHint;
onChanged();
@@ -1377,15 +1365,6 @@
}
/**
- * WARNING. The object reference is important. We perform integer equality and NOT
- * object equality to check whether shared user settings are the same.
- */
- @DataClass.Generated.Member
- public @Nullable SharedUserSetting getSharedUser() {
- return sharedUser;
- }
-
- /**
* @see AndroidPackage#getPath()
*/
@DataClass.Generated.Member
@@ -1488,10 +1467,10 @@
}
@DataClass.Generated(
- time = 1643648635766L,
+ time = 1644270960923L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/PackageSetting.java",
- inputSignatures = "private int sharedUserId\nprivate @android.annotation.Nullable java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mimeGroups\nprivate @java.lang.Deprecated @android.annotation.Nullable java.util.Set<java.lang.String> mOldCodePaths\nprivate @android.annotation.Nullable java.lang.String[] usesSdkLibraries\nprivate @android.annotation.Nullable long[] usesSdkLibrariesVersionsMajor\nprivate @android.annotation.Nullable java.lang.String[] usesStaticLibraries\nprivate @android.annotation.Nullable long[] usesStaticLibrariesVersions\nprivate @android.annotation.Nullable @java.lang.Deprecated java.lang.String legacyNativeLibraryPath\nprivate @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.Nullable java.lang.String mRealName\nprivate int mAppId\nprivate @android.annotation.Nullable com.android.server.pm.parsing.pkg.AndroidPackage pkg\nprivate @android.annotation.Nullable com.android.server.pm.SharedUserSetting sharedUser\nprivate @android.annotation.NonNull java.io.File mPath\nprivate @android.annotation.NonNull java.lang.String mPathString\nprivate float mLoadingProgress\nprivate @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate long mLastModifiedTime\nprivate long lastUpdateTime\nprivate long versionCode\nprivate @android.annotation.NonNull com.android.server.pm.PackageSignatures signatures\nprivate boolean installPermissionsFixed\nprivate @android.annotation.NonNull com.android.server.pm.PackageKeySetData keySetData\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserStateImpl> mUserStates\nprivate @android.annotation.NonNull com.android.server.pm.InstallSource installSource\nprivate @android.annotation.Nullable java.lang.String volumeUuid\nprivate int categoryOverride\nprivate boolean updateAvailable\nprivate boolean forceQueryableOverride\nprivate final @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized pkgState\nprivate @android.annotation.NonNull java.util.UUID mDomainSetId\nprivate final @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> mSnapshot\nprivate com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> makeCache()\npublic com.android.server.pm.PackageSetting snapshot()\npublic void dumpDebug(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\npublic boolean isSharedUser()\npublic com.android.server.pm.PackageSetting setAppId(int)\npublic com.android.server.pm.PackageSetting setCpuAbiOverride(java.lang.String)\npublic com.android.server.pm.PackageSetting setFirstInstallTimeFromReplaced(com.android.server.pm.pkg.PackageStateInternal,int[])\npublic com.android.server.pm.PackageSetting setFirstInstallTime(long,int)\npublic com.android.server.pm.PackageSetting setForceQueryableOverride(boolean)\npublic com.android.server.pm.PackageSetting setInstallerPackageName(java.lang.String)\npublic com.android.server.pm.PackageSetting setInstallSource(com.android.server.pm.InstallSource)\n com.android.server.pm.PackageSetting removeInstallerPackage(java.lang.String)\npublic com.android.server.pm.PackageSetting setIsOrphaned(boolean)\npublic com.android.server.pm.PackageSetting setKeySetData(com.android.server.pm.PackageKeySetData)\npublic com.android.server.pm.PackageSetting setLastModifiedTime(long)\npublic com.android.server.pm.PackageSetting setLastUpdateTime(long)\npublic com.android.server.pm.PackageSetting setLongVersionCode(long)\npublic boolean setMimeGroup(java.lang.String,android.util.ArraySet<java.lang.String>)\npublic com.android.server.pm.PackageSetting setPkg(com.android.server.pm.parsing.pkg.AndroidPackage)\npublic com.android.server.pm.PackageSetting setPkgStateLibraryFiles(java.util.Collection<java.lang.String>)\npublic com.android.server.pm.PackageSetting setPrimaryCpuAbi(java.lang.String)\npublic com.android.server.pm.PackageSetting setSecondaryCpuAbi(java.lang.String)\npublic com.android.server.pm.PackageSetting setSignatures(com.android.server.pm.PackageSignatures)\npublic com.android.server.pm.PackageSetting setVolumeUuid(java.lang.String)\npublic @java.lang.Override boolean isExternalStorage()\npublic com.android.server.pm.PackageSetting setUpdateAvailable(boolean)\npublic int getSharedUserIdInt()\npublic @java.lang.Override java.lang.String toString()\nprotected void copyMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic void updateFrom(com.android.server.pm.PackageSetting)\n com.android.server.pm.PackageSetting updateMimeGroups(java.util.Set<java.lang.String>)\npublic @java.lang.Deprecated @java.lang.Override com.android.server.pm.permission.LegacyPermissionState getLegacyPermissionState()\npublic com.android.server.pm.PackageSetting setInstallPermissionsFixed(boolean)\npublic boolean isPrivileged()\npublic boolean isOem()\npublic boolean isVendor()\npublic boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic boolean isSystemExt()\npublic boolean isOdm()\npublic boolean isSystem()\npublic android.content.pm.SigningDetails getSigningDetails()\npublic com.android.server.pm.PackageSetting setSigningDetails(android.content.pm.SigningDetails)\npublic void copyPackageSetting(com.android.server.pm.PackageSetting)\n @com.android.internal.annotations.VisibleForTesting com.android.server.pm.pkg.PackageUserStateImpl modifyUserState(int)\npublic com.android.server.pm.pkg.PackageUserStateImpl getOrCreateUserState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateInternal readUserState(int)\n void setEnabled(int,int,java.lang.String)\n int getEnabled(int)\n void setInstalled(boolean,int)\n boolean getInstalled(int)\n int getInstallReason(int)\n void setInstallReason(int,int)\n int getUninstallReason(int)\n void setUninstallReason(int,int)\n @android.annotation.NonNull android.content.pm.overlay.OverlayPaths getOverlayPaths(int)\n boolean setOverlayPathsForLibrary(java.lang.String,android.content.pm.overlay.OverlayPaths,int)\n boolean isAnyInstalled(int[])\n int[] queryInstalledUsers(int[],boolean)\n long getCeDataInode(int)\n void setCeDataInode(long,int)\n boolean getStopped(int)\n void setStopped(boolean,int)\n boolean getNotLaunched(int)\n void setNotLaunched(boolean,int)\n boolean getHidden(int)\n void setHidden(boolean,int)\n int getDistractionFlags(int)\n void setDistractionFlags(int,int)\npublic boolean getInstantApp(int)\n void setInstantApp(boolean,int)\n boolean getVirtualPreload(int)\n void setVirtualPreload(boolean,int)\n void setUserState(int,long,int,boolean,boolean,boolean,boolean,int,android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>,boolean,boolean,java.lang.String,android.util.ArraySet<java.lang.String>,android.util.ArraySet<java.lang.String>,int,int,java.lang.String,java.lang.String,long)\n void setUserState(int,com.android.server.pm.pkg.PackageUserStateInternal)\n android.util.ArraySet<java.lang.String> getEnabledComponents(int)\n android.util.ArraySet<java.lang.String> getDisabledComponents(int)\n void setEnabledComponents(android.util.ArraySet<java.lang.String>,int)\n void setDisabledComponents(android.util.ArraySet<java.lang.String>,int)\n void setEnabledComponentsCopy(android.util.ArraySet<java.lang.String>,int)\n void setDisabledComponentsCopy(android.util.ArraySet<java.lang.String>,int)\n com.android.server.pm.pkg.PackageUserStateImpl modifyUserStateComponents(int,boolean,boolean)\n void addDisabledComponent(java.lang.String,int)\n void addEnabledComponent(java.lang.String,int)\n boolean enableComponentLPw(java.lang.String,int)\n boolean disableComponentLPw(java.lang.String,int)\n boolean restoreComponentLPw(java.lang.String,int)\n int getCurrentEnabledStateLPr(java.lang.String,int)\n void removeUser(int)\npublic int[] getNotInstalledUserIds()\n void writePackageUserPermissionsProto(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\nprotected void writeUsersInfoToProto(android.util.proto.ProtoOutputStream,long)\n com.android.server.pm.PackageSetting setPath(java.io.File)\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideNonLocalizedLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer,int)\npublic void resetOverrideComponentLabelIcon(int)\npublic @android.annotation.Nullable java.lang.String getSplashScreenTheme(int)\npublic boolean isLoading()\npublic com.android.server.pm.PackageSetting setLoadingProgress(float)\npublic @android.annotation.NonNull @java.lang.Override long getVersionCode()\npublic @android.annotation.Nullable @java.lang.Override java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getMimeGroups()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String getPackageName()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.pm.pkg.AndroidPackageApi getAndroidPackage()\npublic @android.annotation.Nullable @java.lang.Override int getSharedUserId()\npublic @android.annotation.NonNull android.content.pm.SigningInfo getSigningInfo()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesSdkLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesSdkLibrariesVersionsMajor()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesStaticLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesStaticLibrariesVersions()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<android.content.pm.SharedLibraryInfo> getUsesLibraryInfos()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<java.lang.String> getUsesLibraryFiles()\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @android.annotation.NonNull @java.lang.Override long[] getLastPackageUsageTime()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic com.android.server.pm.PackageSetting setDomainSetId(java.util.UUID)\npublic com.android.server.pm.PackageSetting setSharedUser(com.android.server.pm.SharedUserSetting)\npublic com.android.server.pm.PackageSetting setCategoryOverride(int)\npublic com.android.server.pm.PackageSetting setLegacyNativeLibraryPath(java.lang.String)\npublic com.android.server.pm.PackageSetting setMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic com.android.server.pm.PackageSetting setOldCodePaths(java.util.Set<java.lang.String>)\npublic com.android.server.pm.PackageSetting setUsesSdkLibraries(java.lang.String[])\npublic com.android.server.pm.PackageSetting setUsesSdkLibrariesVersionsMajor(long[])\npublic com.android.server.pm.PackageSetting setUsesStaticLibraries(java.lang.String[])\npublic com.android.server.pm.PackageSetting setUsesStaticLibrariesVersions(long[])\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageStateUnserialized getTransientState()\npublic @android.annotation.NonNull android.util.SparseArray<? extends PackageUserStateInternal> getUserStates()\npublic com.android.server.pm.PackageSetting addMimeTypes(java.lang.String,java.util.Set<java.lang.String>)\nclass PackageSetting extends com.android.server.pm.SettingBase implements [com.android.server.pm.pkg.PackageStateInternal]\n@com.android.internal.util.DataClass(genGetters=true, genConstructor=false, genSetters=false, genBuilder=false)")
+ inputSignatures = "private int mSharedUserAppId\nprivate @android.annotation.Nullable java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mimeGroups\nprivate @java.lang.Deprecated @android.annotation.Nullable java.util.Set<java.lang.String> mOldCodePaths\nprivate @android.annotation.Nullable java.lang.String[] usesSdkLibraries\nprivate @android.annotation.Nullable long[] usesSdkLibrariesVersionsMajor\nprivate @android.annotation.Nullable java.lang.String[] usesStaticLibraries\nprivate @android.annotation.Nullable long[] usesStaticLibrariesVersions\nprivate @android.annotation.Nullable @java.lang.Deprecated java.lang.String legacyNativeLibraryPath\nprivate @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.Nullable java.lang.String mRealName\nprivate int mAppId\nprivate @android.annotation.Nullable com.android.server.pm.parsing.pkg.AndroidPackage pkg\nprivate @android.annotation.NonNull java.io.File mPath\nprivate @android.annotation.NonNull java.lang.String mPathString\nprivate float mLoadingProgress\nprivate @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate long mLastModifiedTime\nprivate long lastUpdateTime\nprivate long versionCode\nprivate @android.annotation.NonNull com.android.server.pm.PackageSignatures signatures\nprivate boolean installPermissionsFixed\nprivate @android.annotation.NonNull com.android.server.pm.PackageKeySetData keySetData\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserStateImpl> mUserStates\nprivate @android.annotation.NonNull com.android.server.pm.InstallSource installSource\nprivate @android.annotation.Nullable java.lang.String volumeUuid\nprivate int categoryOverride\nprivate boolean updateAvailable\nprivate boolean forceQueryableOverride\nprivate final @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized pkgState\nprivate @android.annotation.NonNull java.util.UUID mDomainSetId\nprivate final @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> mSnapshot\nprivate com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> makeCache()\npublic com.android.server.pm.PackageSetting snapshot()\npublic void dumpDebug(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\npublic com.android.server.pm.PackageSetting setAppId(int)\npublic com.android.server.pm.PackageSetting setCpuAbiOverride(java.lang.String)\npublic com.android.server.pm.PackageSetting setFirstInstallTimeFromReplaced(com.android.server.pm.pkg.PackageStateInternal,int[])\npublic com.android.server.pm.PackageSetting setFirstInstallTime(long,int)\npublic com.android.server.pm.PackageSetting setForceQueryableOverride(boolean)\npublic com.android.server.pm.PackageSetting setInstallerPackageName(java.lang.String)\npublic com.android.server.pm.PackageSetting setInstallSource(com.android.server.pm.InstallSource)\n com.android.server.pm.PackageSetting removeInstallerPackage(java.lang.String)\npublic com.android.server.pm.PackageSetting setIsOrphaned(boolean)\npublic com.android.server.pm.PackageSetting setKeySetData(com.android.server.pm.PackageKeySetData)\npublic com.android.server.pm.PackageSetting setLastModifiedTime(long)\npublic com.android.server.pm.PackageSetting setLastUpdateTime(long)\npublic com.android.server.pm.PackageSetting setLongVersionCode(long)\npublic boolean setMimeGroup(java.lang.String,android.util.ArraySet<java.lang.String>)\npublic com.android.server.pm.PackageSetting setPkg(com.android.server.pm.parsing.pkg.AndroidPackage)\npublic com.android.server.pm.PackageSetting setPkgStateLibraryFiles(java.util.Collection<java.lang.String>)\npublic com.android.server.pm.PackageSetting setPrimaryCpuAbi(java.lang.String)\npublic com.android.server.pm.PackageSetting setSecondaryCpuAbi(java.lang.String)\npublic com.android.server.pm.PackageSetting setSignatures(com.android.server.pm.PackageSignatures)\npublic com.android.server.pm.PackageSetting setVolumeUuid(java.lang.String)\npublic @java.lang.Override boolean isExternalStorage()\npublic com.android.server.pm.PackageSetting setUpdateAvailable(boolean)\npublic void setSharedUserAppId(int)\npublic @java.lang.Override int getSharedUserAppId()\npublic @java.lang.Override boolean hasSharedUser()\npublic @java.lang.Override java.lang.String toString()\nprotected void copyMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic void updateFrom(com.android.server.pm.PackageSetting)\n com.android.server.pm.PackageSetting updateMimeGroups(java.util.Set<java.lang.String>)\npublic @java.lang.Deprecated @java.lang.Override com.android.server.pm.permission.LegacyPermissionState getLegacyPermissionState()\npublic com.android.server.pm.PackageSetting setInstallPermissionsFixed(boolean)\npublic boolean isPrivileged()\npublic boolean isOem()\npublic boolean isVendor()\npublic boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic boolean isSystemExt()\npublic boolean isOdm()\npublic boolean isSystem()\npublic android.content.pm.SigningDetails getSigningDetails()\npublic com.android.server.pm.PackageSetting setSigningDetails(android.content.pm.SigningDetails)\npublic void copyPackageSetting(com.android.server.pm.PackageSetting)\n @com.android.internal.annotations.VisibleForTesting com.android.server.pm.pkg.PackageUserStateImpl modifyUserState(int)\npublic com.android.server.pm.pkg.PackageUserStateImpl getOrCreateUserState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateInternal readUserState(int)\n void setEnabled(int,int,java.lang.String)\n int getEnabled(int)\n void setInstalled(boolean,int)\n boolean getInstalled(int)\n int getInstallReason(int)\n void setInstallReason(int,int)\n int getUninstallReason(int)\n void setUninstallReason(int,int)\n @android.annotation.NonNull android.content.pm.overlay.OverlayPaths getOverlayPaths(int)\n boolean setOverlayPathsForLibrary(java.lang.String,android.content.pm.overlay.OverlayPaths,int)\n boolean isAnyInstalled(int[])\n int[] queryInstalledUsers(int[],boolean)\n long getCeDataInode(int)\n void setCeDataInode(long,int)\n boolean getStopped(int)\n void setStopped(boolean,int)\n boolean getNotLaunched(int)\n void setNotLaunched(boolean,int)\n boolean getHidden(int)\n void setHidden(boolean,int)\n int getDistractionFlags(int)\n void setDistractionFlags(int,int)\npublic boolean getInstantApp(int)\n void setInstantApp(boolean,int)\n boolean getVirtualPreload(int)\n void setVirtualPreload(boolean,int)\n void setUserState(int,long,int,boolean,boolean,boolean,boolean,int,android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>,boolean,boolean,java.lang.String,android.util.ArraySet<java.lang.String>,android.util.ArraySet<java.lang.String>,int,int,java.lang.String,java.lang.String,long)\n void setUserState(int,com.android.server.pm.pkg.PackageUserStateInternal)\n android.util.ArraySet<java.lang.String> getEnabledComponents(int)\n android.util.ArraySet<java.lang.String> getDisabledComponents(int)\n void setEnabledComponents(android.util.ArraySet<java.lang.String>,int)\n void setDisabledComponents(android.util.ArraySet<java.lang.String>,int)\n void setEnabledComponentsCopy(android.util.ArraySet<java.lang.String>,int)\n void setDisabledComponentsCopy(android.util.ArraySet<java.lang.String>,int)\n com.android.server.pm.pkg.PackageUserStateImpl modifyUserStateComponents(int,boolean,boolean)\n void addDisabledComponent(java.lang.String,int)\n void addEnabledComponent(java.lang.String,int)\n boolean enableComponentLPw(java.lang.String,int)\n boolean disableComponentLPw(java.lang.String,int)\n boolean restoreComponentLPw(java.lang.String,int)\n int getCurrentEnabledStateLPr(java.lang.String,int)\n void removeUser(int)\npublic int[] getNotInstalledUserIds()\n void writePackageUserPermissionsProto(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\nprotected void writeUsersInfoToProto(android.util.proto.ProtoOutputStream,long)\n com.android.server.pm.PackageSetting setPath(java.io.File)\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideNonLocalizedLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer,int)\npublic void resetOverrideComponentLabelIcon(int)\npublic @android.annotation.Nullable java.lang.String getSplashScreenTheme(int)\npublic boolean isLoading()\npublic com.android.server.pm.PackageSetting setLoadingProgress(float)\npublic @android.annotation.NonNull @java.lang.Override long getVersionCode()\npublic @android.annotation.Nullable @java.lang.Override java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getMimeGroups()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String getPackageName()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.pm.pkg.AndroidPackageApi getAndroidPackage()\npublic @android.annotation.NonNull android.content.pm.SigningInfo getSigningInfo()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesSdkLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesSdkLibrariesVersionsMajor()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesStaticLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesStaticLibrariesVersions()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<android.content.pm.SharedLibraryInfo> getUsesLibraryInfos()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<java.lang.String> getUsesLibraryFiles()\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @android.annotation.NonNull @java.lang.Override long[] getLastPackageUsageTime()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic com.android.server.pm.PackageSetting setDomainSetId(java.util.UUID)\npublic com.android.server.pm.PackageSetting setCategoryOverride(int)\npublic com.android.server.pm.PackageSetting setLegacyNativeLibraryPath(java.lang.String)\npublic com.android.server.pm.PackageSetting setMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic com.android.server.pm.PackageSetting setOldCodePaths(java.util.Set<java.lang.String>)\npublic com.android.server.pm.PackageSetting setUsesSdkLibraries(java.lang.String[])\npublic com.android.server.pm.PackageSetting setUsesSdkLibrariesVersionsMajor(long[])\npublic com.android.server.pm.PackageSetting setUsesStaticLibraries(java.lang.String[])\npublic com.android.server.pm.PackageSetting setUsesStaticLibrariesVersions(long[])\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageStateUnserialized getTransientState()\npublic @android.annotation.NonNull android.util.SparseArray<? extends PackageUserStateInternal> getUserStates()\npublic com.android.server.pm.PackageSetting addMimeTypes(java.lang.String,java.util.Set<java.lang.String>)\nclass PackageSetting extends com.android.server.pm.SettingBase implements [com.android.server.pm.pkg.PackageStateInternal]\n@com.android.internal.util.DataClass(genGetters=true, genConstructor=false, genSetters=false, genBuilder=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
index f3d88ed..0b69cd3 100644
--- a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
+++ b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
@@ -22,19 +22,18 @@
import static com.android.server.pm.PackageManagerService.SCAN_BOOTING;
import static com.android.server.pm.PackageManagerService.SCAN_DONT_KILL_APP;
import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
-import static com.android.server.pm.PackageManagerServiceUtils.verifySignatures;
import android.content.pm.PackageManager;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.Signature;
import android.content.pm.SigningDetails;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import android.os.SystemProperties;
import android.util.ArrayMap;
import android.util.Log;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.utils.WatchedLongSparseArray;
import java.util.List;
@@ -43,7 +42,7 @@
final class ReconcilePackageUtils {
public static Map<String, ReconciledPackage> reconcilePackages(
final ReconcileRequest request, SharedLibrariesImpl sharedLibraries,
- KeySetManagerService ksms)
+ KeySetManagerService ksms, Settings settings)
throws ReconcileFailure {
final Map<String, ScanResult> scannedPackages = request.mScannedPackages;
@@ -121,7 +120,10 @@
boolean removeAppKeySetData = false;
boolean sharedUserSignaturesChanged = false;
SigningDetails signingDetails = null;
- if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
+ SharedUserSetting sharedUserSetting = settings.getSharedUserSettingLPr(
+ signatureCheckPs);
+ if (ksms.shouldCheckUpgradeKeySetLocked(
+ signatureCheckPs, sharedUserSetting, scanFlags)) {
if (ksms.checkUpgradeKeySetLocked(signatureCheckPs, parsedPackage)) {
// We just determined the app is signed correctly, so bring
// over the latest parsed certs.
@@ -139,6 +141,7 @@
}
signingDetails = parsedPackage.getSigningDetails();
} else {
+
try {
final Settings.VersionInfo versionInfo =
request.mVersionInfos.get(installPackageName);
@@ -146,9 +149,11 @@
final boolean compareRecover = isRecoverSignatureUpdateNeeded(versionInfo);
final boolean isRollback = installArgs != null
&& installArgs.mInstallReason == PackageManager.INSTALL_REASON_ROLLBACK;
- final boolean compatMatch = verifySignatures(signatureCheckPs,
- disabledPkgSetting, parsedPackage.getSigningDetails(), compareCompat,
- compareRecover, isRollback);
+ final boolean compatMatch =
+ PackageManagerServiceUtils.verifySignatures(signatureCheckPs,
+ sharedUserSetting, disabledPkgSetting,
+ parsedPackage.getSigningDetails(), compareCompat,
+ compareRecover, isRollback);
// The new KeySets will be re-added later in the scanning process.
if (compatMatch) {
removeAppKeySetData = true;
@@ -161,21 +166,21 @@
// newer
// signing certificate than the existing one, and if so, copy over the new
// details
- if (signatureCheckPs.getSharedUser() != null) {
+ if (sharedUserSetting != null) {
// Attempt to merge the existing lineage for the shared SigningDetails with
// the lineage of the new package; if the shared SigningDetails are not
// returned this indicates the new package added new signers to the lineage
// and/or changed the capabilities of existing signers in the lineage.
SigningDetails sharedSigningDetails =
- signatureCheckPs.getSharedUser().signatures.mSigningDetails;
+ sharedUserSetting.signatures.mSigningDetails;
SigningDetails mergedDetails = sharedSigningDetails.mergeLineageWith(
signingDetails);
if (mergedDetails != sharedSigningDetails) {
- signatureCheckPs.getSharedUser().signatures.mSigningDetails =
+ sharedUserSetting.signatures.mSigningDetails =
mergedDetails;
}
- if (signatureCheckPs.getSharedUser().signaturesChanged == null) {
- signatureCheckPs.getSharedUser().signaturesChanged = Boolean.FALSE;
+ if (sharedUserSetting.signaturesChanged == null) {
+ sharedUserSetting.signaturesChanged = Boolean.FALSE;
}
}
} catch (PackageManagerException e) {
@@ -192,10 +197,10 @@
// updating
// the signatures on the first package scanned for the shared user (i.e. if the
// signaturesChanged state hasn't been initialized yet in SharedUserSetting).
- if (signatureCheckPs.getSharedUser() != null) {
- final Signature[] sharedUserSignatures = signatureCheckPs.getSharedUser()
+ if (sharedUserSetting != null) {
+ final Signature[] sharedUserSignatures = sharedUserSetting
.signatures.mSigningDetails.getSignatures();
- if (signatureCheckPs.getSharedUser().signaturesChanged != null
+ if (sharedUserSetting.signaturesChanged != null
&& compareSignatures(sharedUserSignatures,
parsedPackage.getSigningDetails().getSignatures())
!= PackageManager.SIGNATURE_MATCH) {
@@ -209,7 +214,7 @@
throw new ReconcileFailure(
INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
"Signature mismatch for shared user: "
- + scanResult.mPkgSetting.getSharedUser());
+ + sharedUserSetting);
} else {
// Treat mismatched signatures on system packages using a shared
// UID as
@@ -219,14 +224,14 @@
"Signature mismatch on system package "
+ parsedPackage.getPackageName()
+ " for shared user "
- + scanResult.mPkgSetting.getSharedUser());
+ + sharedUserSetting);
}
}
sharedUserSignaturesChanged = true;
- signatureCheckPs.getSharedUser().signatures.mSigningDetails =
+ sharedUserSetting.signatures.mSigningDetails =
parsedPackage.getSigningDetails();
- signatureCheckPs.getSharedUser().signaturesChanged = Boolean.TRUE;
+ sharedUserSetting.signaturesChanged = Boolean.TRUE;
}
// File a report about this.
String msg = "System package " + parsedPackage.getPackageName()
diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java
index 7e898cb..079903e 100644
--- a/services/core/java/com/android/server/pm/RemovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java
@@ -279,7 +279,7 @@
if (!mPm.mSettings.isDisabledSystemPackageLPr(packageName)) {
// If we don't have a disabled system package to reinstall, the package is
// really gone and its permission state should be removed.
- final SharedUserSetting sus = deletedPs.getSharedUser();
+ SharedUserSetting sus = mPm.mSettings.getSharedUserSettingLPr(deletedPs);
List<AndroidPackage> sharedUserPkgs =
sus != null ? sus.getPackages() : Collections.emptyList();
mPermissionManager.onPackageUninstalled(packageName, deletedPs.getAppId(),
diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java
index 79ab563..99d9d58 100644
--- a/services/core/java/com/android/server/pm/ScanPackageUtils.java
+++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java
@@ -125,6 +125,7 @@
final @ParsingPackageUtils.ParseFlags int parseFlags = request.mParseFlags;
final @PackageManagerService.ScanFlags int scanFlags = request.mScanFlags;
final String realPkgName = request.mRealPkgName;
+ final SharedUserSetting oldSharedUserSetting = request.mOldSharedUserSetting;
final SharedUserSetting sharedUserSetting = request.mSharedUserSetting;
final UserHandle user = request.mUser;
final boolean isPlatformPackage = request.mIsPlatformPackage;
@@ -165,18 +166,18 @@
int previousAppId = Process.INVALID_UID;
- if (pkgSetting != null && pkgSetting.getSharedUser() != sharedUserSetting) {
- if (pkgSetting.getSharedUser() != null && sharedUserSetting == null) {
+ if (pkgSetting != null && oldSharedUserSetting != sharedUserSetting) {
+ if (oldSharedUserSetting != null && sharedUserSetting == null) {
previousAppId = pkgSetting.getAppId();
// Log that something is leaving shareduid and keep going
Slog.i(TAG,
"Package " + parsedPackage.getPackageName() + " shared user changed from "
- + pkgSetting.getSharedUser().name + " to " + "<nothing>.");
+ + oldSharedUserSetting.name + " to " + "<nothing>.");
} else {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Package " + parsedPackage.getPackageName() + " shared user changed from "
- + (pkgSetting.getSharedUser() != null
- ? pkgSetting.getSharedUser().name : "<nothing>")
+ + (oldSharedUserSetting != null
+ ? oldSharedUserSetting.name : "<nothing>")
+ " to "
+ (sharedUserSetting != null ? sharedUserSetting.name : "<nothing>")
+ "; replacing with new");
@@ -234,8 +235,8 @@
// TODO(narayan): This update is bogus. nativeLibraryDir & primaryCpuAbi,
// secondaryCpuAbi are not known at this point so we always update them
// to null here, only to reset them at a later point.
- Settings.updatePackageSetting(pkgSetting, disabledPkgSetting, sharedUserSetting,
- destCodeFile, parsedPackage.getNativeLibraryDir(),
+ Settings.updatePackageSetting(pkgSetting, disabledPkgSetting, oldSharedUserSetting,
+ sharedUserSetting, destCodeFile, parsedPackage.getNativeLibraryDir(),
AndroidPackageUtils.getPrimaryCpuAbi(parsedPackage, pkgSetting),
AndroidPackageUtils.getSecondaryCpuAbi(parsedPackage, pkgSetting),
PackageInfoUtils.appInfoFlags(parsedPackage, pkgSetting),
@@ -390,16 +391,16 @@
+ " abiOverride=" + pkgSetting.getCpuAbiOverride());
}
- if ((scanFlags & SCAN_BOOTING) == 0 && pkgSetting.getSharedUser() != null) {
+ if ((scanFlags & SCAN_BOOTING) == 0 && oldSharedUserSetting != null) {
// We don't do this here during boot because we can do it all
// at once after scanning all existing packages.
//
// We also do this *before* we perform dexopt on this package, so that
// we can avoid redundant dexopts, and also to make sure we've got the
// code and package path correct.
- changedAbiCodePath = applyAdjustedAbiToSharedUser(pkgSetting.getSharedUser(),
+ changedAbiCodePath = applyAdjustedAbiToSharedUser(oldSharedUserSetting,
parsedPackage, packageAbiHelper.getAdjustedAbiForSharedUser(
- pkgSetting.getSharedUser().packages, parsedPackage));
+ oldSharedUserSetting.packages, parsedPackage));
}
parsedPackage.setFactoryTest(isUnderFactoryTest && parsedPackage.getRequestedPermissions()
diff --git a/services/core/java/com/android/server/pm/ScanRequest.java b/services/core/java/com/android/server/pm/ScanRequest.java
index 34abdb1..98d11bd 100644
--- a/services/core/java/com/android/server/pm/ScanRequest.java
+++ b/services/core/java/com/android/server/pm/ScanRequest.java
@@ -32,14 +32,16 @@
@NonNull public final ParsedPackage mParsedPackage;
/** The package this package replaces */
@Nullable public final AndroidPackage mOldPkg;
- /** Shared user settings, if the package has a shared user */
- @Nullable public final SharedUserSetting mSharedUserSetting;
+ /** Shared user settings, if the old package has a shared user */
+ @Nullable public final SharedUserSetting mOldSharedUserSetting;
/**
* Package settings of the currently installed version.
* <p><em>IMPORTANT:</em> The contents of this object may be modified
* during scan.
*/
@Nullable public final PackageSetting mPkgSetting;
+ /** Shared user settings of the currently installed package */
+ @Nullable public final SharedUserSetting mSharedUserSetting;
/** A copy of the settings for the currently installed version */
@Nullable public final PackageSetting mOldPkgSetting;
/** Package settings for the disabled version on the /system partition */
@@ -59,9 +61,10 @@
ScanRequest(
@NonNull ParsedPackage parsedPackage,
- @Nullable SharedUserSetting sharedUserSetting,
+ @Nullable SharedUserSetting oldSharedUserSetting,
@Nullable AndroidPackage oldPkg,
@Nullable PackageSetting pkgSetting,
+ @Nullable SharedUserSetting sharedUserSetting,
@Nullable PackageSetting disabledPkgSetting,
@Nullable PackageSetting originalPkgSetting,
@Nullable String realPkgName,
@@ -73,6 +76,7 @@
mParsedPackage = parsedPackage;
mOldPkg = oldPkg;
mPkgSetting = pkgSetting;
+ mOldSharedUserSetting = oldSharedUserSetting;
mSharedUserSetting = sharedUserSetting;
mOldPkgSetting = pkgSetting == null ? null : new PackageSetting(pkgSetting);
mDisabledPkgSetting = disabledPkgSetting;
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 279de83..5966917 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -51,13 +51,6 @@
import android.content.pm.UserInfo;
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.overlay.OverlayPaths;
-import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
-import com.android.server.pm.pkg.component.ParsedComponent;
-import com.android.server.pm.pkg.component.ParsedIntentInfo;
-import com.android.server.pm.pkg.component.ParsedMainComponent;
-import com.android.server.pm.pkg.component.ParsedPermission;
-import com.android.server.pm.pkg.component.ParsedProcess;
-import com.android.server.pm.pkg.PackageUserStateUtils;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -118,10 +111,18 @@
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.PackageUserState;
import com.android.server.pm.pkg.PackageUserStateInternal;
+import com.android.server.pm.pkg.PackageUserStateUtils;
import com.android.server.pm.pkg.SuspendParams;
+import com.android.server.pm.pkg.component.ParsedComponent;
+import com.android.server.pm.pkg.component.ParsedIntentInfo;
+import com.android.server.pm.pkg.component.ParsedMainComponent;
+import com.android.server.pm.pkg.component.ParsedPermission;
+import com.android.server.pm.pkg.component.ParsedProcess;
+import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
import com.android.server.pm.verify.domain.DomainVerificationLegacySettings;
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
import com.android.server.pm.verify.domain.DomainVerificationPersistence;
+import com.android.server.utils.Slogf;
import com.android.server.utils.Snappable;
import com.android.server.utils.SnapshotCache;
import com.android.server.utils.TimingsTraceAndSlog;
@@ -779,13 +780,13 @@
SharedUserSetting s = mSharedUsers.get(name);
if (s == null && create) {
s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
- s.userId = acquireAndRegisterNewAppIdLPw(s);
- if (s.userId < 0) {
+ s.mAppId = acquireAndRegisterNewAppIdLPw(s);
+ if (s.mAppId < 0) {
// < 0 means we couldn't assign a userid; throw exception
throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
"Creating shared user " + name + " failed");
}
- Log.i(PackageManagerService.TAG, "New shared user " + name + ": id=" + s.userId);
+ Log.i(PackageManagerService.TAG, "New shared user " + name + ": id=" + s.mAppId);
mSharedUsers.put(name, s);
}
return s;
@@ -817,8 +818,9 @@
disabled = p;
}
mDisabledSysPackages.put(name, disabled);
- if (disabled.getSharedUser() != null) {
- disabled.getSharedUser().mDisabledPackages.add(disabled);
+ SharedUserSetting sharedUserSetting = getSharedUserSettingLPr(disabled);
+ if (sharedUserSetting != null) {
+ sharedUserSetting.mDisabledPackages.add(disabled);
}
return true;
}
@@ -831,8 +833,9 @@
Log.w(PackageManagerService.TAG, "Package " + name + " is not disabled");
return null;
}
- if (p.getSharedUser() != null) {
- p.getSharedUser().mDisabledPackages.remove(p);
+ SharedUserSetting sharedUserSetting = getSharedUserSettingLPr(p);
+ if (sharedUserSetting != null) {
+ sharedUserSetting.mDisabledPackages.remove(p);
}
p.getPkgState().setUpdatedSystemApp(false);
PackageSetting ret = addPackageLPw(name, p.getRealName(), p.getPath(),
@@ -855,9 +858,12 @@
void removeDisabledSystemPackageLPw(String name) {
final PackageSetting p = mDisabledSysPackages.remove(name);
- if (p != null && p.getSharedUser() != null) {
- p.getSharedUser().mDisabledPackages.remove(p);
- checkAndPruneSharedUserLPw(p.getSharedUser(), false);
+ if (p != null) {
+ SharedUserSetting sharedUserSetting = getSharedUserSettingLPr(p);
+ if (sharedUserSetting != null) {
+ sharedUserSetting.mDisabledPackages.remove(p);
+ checkAndPruneSharedUserLPw(sharedUserSetting, false);
+ }
}
}
@@ -892,7 +898,7 @@
SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags, int pkgPrivateFlags) {
SharedUserSetting s = mSharedUsers.get(name);
if (s != null) {
- if (s.userId == uid) {
+ if (s.mAppId == uid) {
return s;
}
PackageManagerService.reportSettingsProblem(Log.ERROR,
@@ -900,7 +906,7 @@
return null;
}
s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
- s.userId = uid;
+ s.mAppId = uid;
if (registerExistingAppIdLPw(uid, s, name)) {
mSharedUsers.put(name, s);
return s;
@@ -973,7 +979,9 @@
usesStaticLibraries, usesStaticLibrariesVersions,
createMimeGroups(mimeGroupNames), domainSetId);
pkgSetting.setLastModifiedTime(codePath.lastModified());
- pkgSetting.setSharedUser(sharedUser);
+ if (sharedUser != null) {
+ pkgSetting.setSharedUserAppId(sharedUser.mAppId);
+ }
// If this is not a system app, it starts out stopped.
if ((pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
if (DEBUG_STOPPED) {
@@ -982,7 +990,8 @@
Slog.i(PackageManagerService.TAG, "Stopping package " + pkgName, e);
}
List<UserInfo> users = getAllUsers(userManager);
- final int installUserId = installUser != null ? installUser.getIdentifier() : 0;
+ int installUserId = installUser != null ? installUser.getIdentifier()
+ : UserHandle.USER_SYSTEM;
if (users != null && allowInstall) {
for (UserInfo user : users) {
// By default we consider this app to be installed
@@ -993,8 +1002,14 @@
// user we are installing for.
final boolean installed = installUser == null
|| (installUserId == UserHandle.USER_ALL
- && !isAdbInstallDisallowed(userManager, user.id))
+ && !isAdbInstallDisallowed(userManager, user.id)
+ && !user.preCreated)
|| installUserId == user.id;
+ if (DEBUG_MU) {
+ Slogf.d(TAG, "createNewSetting(pkg=%s, installUserId=%s, user=%s, "
+ + "installed=%b)",
+ pkgName, installUserId, user.toFullString(), installed);
+ }
pkgSetting.setUserState(user.id, 0, COMPONENT_ENABLED_STATE_DEFAULT,
installed,
true /*stopped*/,
@@ -1017,7 +1032,7 @@
}
}
if (sharedUser != null) {
- pkgSetting.setAppId(sharedUser.userId);
+ pkgSetting.setAppId(sharedUser.mAppId);
} else {
// Clone the setting here for disabled system packages
if (disabledPkg != null) {
@@ -1061,7 +1076,9 @@
* WARNING: The provided PackageSetting object may be mutated.
*/
static void updatePackageSetting(@NonNull PackageSetting pkgSetting,
- @Nullable PackageSetting disabledPkg, @Nullable SharedUserSetting sharedUser,
+ @Nullable PackageSetting disabledPkg,
+ @Nullable SharedUserSetting existingSharedUserSetting,
+ @Nullable SharedUserSetting sharedUser,
@NonNull File codePath, @Nullable String legacyNativeLibraryPath,
@Nullable String primaryCpuAbi, @Nullable String secondaryCpuAbi, int pkgFlags,
int pkgPrivateFlags, @NonNull UserManagerService userManager,
@@ -1070,16 +1087,18 @@
@Nullable Set<String> mimeGroupNames, @NonNull UUID domainSetId)
throws PackageManagerException {
final String pkgName = pkgSetting.getPackageName();
- if (!Objects.equals(pkgSetting.getSharedUser(), sharedUser) && sharedUser != null) {
- PackageManagerService.reportSettingsProblem(Log.WARN,
- "Package " + pkgName + " shared user changed from "
- + (pkgSetting.getSharedUser() != null
- ? pkgSetting.getSharedUser().name : "<nothing>")
- + " to " + sharedUser.name);
- throw new PackageManagerException(INSTALL_FAILED_UID_CHANGED,
- "Updating application package " + pkgName + " failed");
+ if (sharedUser != null) {
+ if (!Objects.equals(existingSharedUserSetting, sharedUser)) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Package " + pkgName + " shared user changed from "
+ + (existingSharedUserSetting != null
+ ? existingSharedUserSetting.name : "<nothing>")
+ + " to " + sharedUser.name);
+ throw new PackageManagerException(INSTALL_FAILED_UID_CHANGED,
+ "Updating application package " + pkgName + " failed");
+ }
+ pkgSetting.setSharedUserAppId(sharedUser.mAppId);
}
- pkgSetting.setSharedUser(sharedUser);
if (!pkgSetting.getPath().equals(codePath)) {
final boolean isSystem = pkgSetting.isSystem();
@@ -1220,11 +1239,13 @@
}
// If this app defines a shared user id initialize
// the shared user signatures as well.
- if (p.getSharedUser() != null
- && p.getSharedUser().signatures.mSigningDetails.getSignatures() == null) {
- p.getSharedUser().signatures.mSigningDetails = pkg.getSigningDetails();
+ SharedUserSetting sharedUserSetting = getSharedUserSettingLPr(p);
+ if (sharedUserSetting != null) {
+ if (sharedUserSetting.signatures.mSigningDetails.getSignatures() == null) {
+ sharedUserSetting.signatures.mSigningDetails = pkg.getSigningDetails();
+ }
}
- addPackageSettingLPw(p, p.getSharedUser());
+ addPackageSettingLPw(p, sharedUserSetting);
}
// Utility method that adds a PackageSetting to mPackages and
@@ -1233,23 +1254,24 @@
private void addPackageSettingLPw(PackageSetting p, SharedUserSetting sharedUser) {
mPackages.put(p.getPackageName(), p);
if (sharedUser != null) {
- if (p.getSharedUser() != null && p.getSharedUser() != sharedUser) {
+ SharedUserSetting existingSharedUserSetting = getSharedUserSettingLPr(p);
+ if (existingSharedUserSetting != null && existingSharedUserSetting != sharedUser) {
PackageManagerService.reportSettingsProblem(Log.ERROR,
"Package " + p.getPackageName() + " was user "
- + p.getSharedUser() + " but is now " + sharedUser
+ + existingSharedUserSetting + " but is now " + sharedUser
+ "; I am not changing its files so it will probably fail!");
- p.getSharedUser().removePackage(p);
- } else if (p.getAppId() != sharedUser.userId) {
+ sharedUser.removePackage(p);
+ } else if (p.getAppId() != sharedUser.mAppId) {
PackageManagerService.reportSettingsProblem(Log.ERROR,
- "Package " + p.getPackageName() + " was user id " + p.getAppId()
- + " but is now user " + sharedUser
- + " with id " + sharedUser.userId
- + "; I am not changing its files so it will probably fail!");
+ "Package " + p.getPackageName() + " was user id " + p.getAppId()
+ + " but is now user " + sharedUser
+ + " with id " + sharedUser.mAppId
+ + "; I am not changing its files so it will probably fail!");
}
sharedUser.addPackage(p);
- p.setSharedUser(sharedUser);
- p.setAppId(sharedUser.userId);
+ p.setSharedUserAppId(sharedUser.mAppId);
+ p.setAppId(sharedUser.mAppId);
}
// If the we know about this user id, we have to update it as it
@@ -1269,7 +1291,7 @@
boolean checkAndPruneSharedUserLPw(SharedUserSetting s, boolean skipCheck) {
if (skipCheck || (s.packages.isEmpty() && s.mDisabledPackages.isEmpty())) {
if (mSharedUsers.remove(s.name) != null) {
- removeAppIdLPw(s.userId);
+ removeAppIdLPw(s.mAppId);
return true;
}
}
@@ -1280,10 +1302,11 @@
final PackageSetting p = mPackages.remove(name);
if (p != null) {
removeInstallerPackageStatus(name);
- if (p.getSharedUser() != null) {
- p.getSharedUser().removePackage(p);
- if (checkAndPruneSharedUserLPw(p.getSharedUser(), false)) {
- return p.getSharedUser().userId;
+ SharedUserSetting sharedUserSetting = getSharedUserSettingLPr(p);
+ if (sharedUserSetting != null) {
+ sharedUserSetting.removePackage(p);
+ if (checkAndPruneSharedUserLPw(sharedUserSetting, false)) {
+ return sharedUserSetting.mAppId;
}
} else {
removeAppIdLPw(p.getAppId());
@@ -2039,11 +2062,14 @@
serializer.startTag(null, TAG_PACKAGE_RESTRICTIONS);
- if (DEBUG_MU) Log.i(TAG, "Writing " + userPackagesStateFile);
+ if (DEBUG_MU) {
+ Slogf.i(TAG, "Writing %s (%d packages)", userPackagesStateFile,
+ mPackages.values().size());
+ }
for (final PackageSetting pkg : mPackages.values()) {
final PackageUserStateInternal ustate = pkg.readUserState(userId);
if (DEBUG_MU) {
- Log.i(TAG, " pkg=" + pkg.getPackageName()
+ Log.v(TAG, " pkg=" + pkg.getPackageName()
+ ", installed=" + ustate.isInstalled()
+ ", state=" + ustate.getEnabledState());
}
@@ -2116,20 +2142,24 @@
serializer.endTag(null, TAG_SUSPEND_PARAMS);
}
}
- if (!ArrayUtils.isEmpty(ustate.getEnabledComponentsNoCopy())) {
+ final ArraySet<String> enabledComponents = ustate.getEnabledComponents();
+ if (enabledComponents != null && enabledComponents.size() > 0) {
serializer.startTag(null, TAG_ENABLED_COMPONENTS);
- for (final String name : ustate.getEnabledComponentsNoCopy()) {
+ for (int i = 0; i < enabledComponents.size(); i++) {
serializer.startTag(null, TAG_ITEM);
- serializer.attribute(null, ATTR_NAME, name);
+ serializer.attribute(null, ATTR_NAME,
+ enabledComponents.valueAt(i));
serializer.endTag(null, TAG_ITEM);
}
serializer.endTag(null, TAG_ENABLED_COMPONENTS);
}
- if (!ArrayUtils.isEmpty(ustate.getDisabledComponentsNoCopy())) {
+ final ArraySet<String> disabledComponents = ustate.getDisabledComponents();
+ if (disabledComponents != null && disabledComponents.size() > 0) {
serializer.startTag(null, TAG_DISABLED_COMPONENTS);
- for (final String name : ustate.getDisabledComponentsNoCopy()) {
+ for (int i = 0; i < disabledComponents.size(); i++) {
serializer.startTag(null, TAG_ITEM);
- serializer.attribute(null, ATTR_NAME, name);
+ serializer.attribute(null, ATTR_NAME,
+ disabledComponents.valueAt(i));
serializer.endTag(null, TAG_ITEM);
}
serializer.endTag(null, TAG_DISABLED_COMPONENTS);
@@ -2454,7 +2484,7 @@
for (final SharedUserSetting usr : mSharedUsers.values()) {
serializer.startTag(null, "shared-user");
serializer.attribute(null, ATTR_NAME, usr.name);
- serializer.attributeInt(null, "userId", usr.userId);
+ serializer.attributeInt(null, "userId", usr.mAppId);
usr.signatures.writeXml(serializer, "sigs", mPastSignatures.untrackedStorage());
serializer.endTag(null, "shared-user");
}
@@ -2773,7 +2803,7 @@
serializer.attribute(null, "cpuAbiOverride", pkg.getCpuAbiOverride());
}
- if (pkg.getSharedUser() == null) {
+ if (!pkg.hasSharedUser()) {
serializer.attributeInt(null, "userId", pkg.getAppId());
} else {
serializer.attributeInt(null, "sharedUserId", pkg.getAppId());
@@ -2816,7 +2846,7 @@
serializer.attributeLongHex(null, "ft", pkg.getLastModifiedTime());
serializer.attributeLongHex(null, "ut", pkg.getLastUpdateTime());
serializer.attributeLong(null, "version", pkg.getVersionCode());
- if (pkg.getSharedUser() == null) {
+ if (!pkg.hasSharedUser()) {
serializer.attributeInt(null, "userId", pkg.getAppId());
} else {
serializer.attributeInt(null, "sharedUserId", pkg.getAppId());
@@ -3088,21 +3118,22 @@
for (int i = 0; i < N; i++) {
final PackageSetting p = mPendingPackages.get(i);
- final int sharedUserId = p.getSharedUserIdInt();
- final Object idObj = getSettingLPr(sharedUserId);
+ final int sharedUserAppId = p.getSharedUserAppId();
+ if (sharedUserAppId <= 0) {
+ continue;
+ }
+ final Object idObj = getSettingLPr(sharedUserAppId);
if (idObj instanceof SharedUserSetting) {
final SharedUserSetting sharedUser = (SharedUserSetting) idObj;
- p.setSharedUser(sharedUser);
- p.setAppId(sharedUser.userId);
addPackageSettingLPw(p, sharedUser);
} else if (idObj != null) {
String msg = "Bad package setting: package " + p.getPackageName()
- + " has shared uid " + sharedUserId + " that is not a shared uid\n";
+ + " has shared uid " + sharedUserAppId + " that is not a shared uid\n";
mReadMessages.append(msg);
PackageManagerService.reportSettingsProblem(Log.ERROR, msg);
} else {
String msg = "Bad package setting: package " + p.getPackageName()
- + " has shared uid " + sharedUserId + " that is not defined\n";
+ + " has shared uid " + sharedUserAppId + " that is not defined\n";
mReadMessages.append(msg);
PackageManagerService.reportSettingsProblem(Log.ERROR, msg);
}
@@ -3135,8 +3166,9 @@
for (PackageSetting disabledPs : mDisabledSysPackages.values()) {
final Object id = getSettingLPr(disabledPs.getAppId());
if (id instanceof SharedUserSetting) {
- disabledPs.setSharedUser((SharedUserSetting) id);
- disabledPs.getSharedUser().mDisabledPackages.add(disabledPs);
+ SharedUserSetting sharedUserSetting = (SharedUserSetting) id;
+ sharedUserSetting.mDisabledPackages.add(disabledPs);
+ disabledPs.setSharedUserAppId(sharedUserSetting.mAppId);
}
}
@@ -3552,7 +3584,9 @@
ps.setLastUpdateTime(parser.getAttributeLongHex(null, "ut", 0));
ps.setAppId(parser.getAttributeInt(null, "userId", 0));
if (ps.getAppId() <= 0) {
- ps.setAppId(parser.getAttributeInt(null, "sharedUserId", 0));
+ final int sharedUserAppId = parser.getAttributeInt(null, "sharedUserId", 0);
+ ps.setAppId(sharedUserAppId);
+ ps.setSharedUserAppId(sharedUserAppId);
}
final float loadingProgress =
parser.getAttributeFloat(null, "loadingProgress", 0);
@@ -3567,7 +3601,13 @@
}
if (parser.getName().equals(TAG_PERMISSIONS)) {
- readInstallPermissionsLPr(parser, ps.getLegacyPermissionState(), users);
+ final LegacyPermissionState legacyState;
+ if (ps.hasSharedUser()) {
+ legacyState = getSettingLPr(ps.getSharedUserAppId()).getLegacyPermissionState();
+ } else {
+ legacyState = ps.getLegacyPermissionState();
+ }
+ readInstallPermissionsLPr(parser, legacyState, users);
} else if (parser.getName().equals(TAG_USES_STATIC_LIB)) {
readUsesStaticLibLPw(parser, ps);
} else if (parser.getName().equals(TAG_USES_SDK_LIB)) {
@@ -3592,7 +3632,7 @@
String name = null;
String realName = null;
int userId = 0;
- int sharedUserId = 0;
+ int sharedUserAppId = 0;
String codePathStr = null;
String legacyCpuAbiString = null;
String legacyNativeLibraryPathStr = null;
@@ -3624,7 +3664,7 @@
name = parser.getAttributeValue(null, ATTR_NAME);
realName = parser.getAttributeValue(null, "realName");
userId = parser.getAttributeInt(null, "userId", 0);
- sharedUserId = parser.getAttributeInt(null, "sharedUserId", 0);
+ sharedUserAppId = parser.getAttributeInt(null, "sharedUserId", 0);
codePathStr = parser.getAttributeValue(null, "codePath");
legacyCpuAbiString = parser.getAttributeValue(null, "requiredCpuAbi");
@@ -3718,7 +3758,7 @@
lastUpdateTime = parser.getAttributeLongHex(null, "ut", 0);
if (PackageManagerService.DEBUG_SETTINGS)
Log.v(PackageManagerService.TAG, "Reading package: " + name + " userId=" + userId
- + " sharedUserId=" + sharedUserId);
+ + " sharedUserId=" + sharedUserAppId);
if (realName != null) {
realName = realName.intern();
}
@@ -3748,12 +3788,12 @@
packageSetting.setLastModifiedTime(timeStamp);
packageSetting.setLastUpdateTime(lastUpdateTime);
}
- } else if (sharedUserId != 0) {
- if (sharedUserId > 0) {
+ } else if (sharedUserAppId != 0) {
+ if (sharedUserAppId > 0) {
packageSetting = new PackageSetting(name.intern(), realName,
new File(codePathStr), legacyNativeLibraryPathStr,
primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
- versionCode, pkgFlags, pkgPrivateFlags, sharedUserId,
+ versionCode, pkgFlags, pkgPrivateFlags, sharedUserAppId,
null /* usesSdkLibraries */,
null /* usesSdkLibrariesVersions */,
null /* usesStaticLibraries */,
@@ -3764,11 +3804,11 @@
mPendingPackages.add(packageSetting);
if (PackageManagerService.DEBUG_SETTINGS)
Log.i(PackageManagerService.TAG, "Reading package " + name
- + ": sharedUserId=" + sharedUserId + " pkg=" + packageSetting);
+ + ": sharedUserId=" + sharedUserAppId + " pkg=" + packageSetting);
} else {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Error in package manager settings: package " + name
- + " has bad sharedId " + sharedUserId + " at "
+ + " has bad sharedId " + sharedUserAppId + " at "
+ parser.getPositionDescription());
}
} else {
@@ -3838,8 +3878,14 @@
packageSetting.getSignatures()
.readXml(parser,mPastSignatures.untrackedStorage());
} else if (tagName.equals(TAG_PERMISSIONS)) {
- readInstallPermissionsLPr(parser,
- packageSetting.getLegacyPermissionState(), users);
+ final LegacyPermissionState legacyState;
+ if (packageSetting.hasSharedUser()) {
+ legacyState = getSettingLPr(
+ packageSetting.getSharedUserAppId()).getLegacyPermissionState();
+ } else {
+ legacyState = packageSetting.getLegacyPermissionState();
+ }
+ readInstallPermissionsLPr(parser, legacyState, users);
packageSetting.setInstallPermissionsFixed(true);
} else if (tagName.equals("proper-signing-keyset")) {
long id = parser.getAttributeLong(null, "identifier");
@@ -4294,6 +4340,19 @@
return pkg.getCurrentEnabledStateLPr(classNameStr, userId);
}
+ SharedUserSetting getSharedUserSettingLPr(String packageName) {
+ final PackageSetting ps = mPackages.get(packageName);
+ return getSharedUserSettingLPr(ps);
+ }
+
+ @Nullable
+ SharedUserSetting getSharedUserSettingLPr(PackageSetting ps) {
+ if (ps == null || !ps.hasSharedUser()) {
+ return null;
+ }
+ return (SharedUserSetting) getSettingLPr(ps.getSharedUserAppId());
+ }
+
/**
* Returns all users on the device, including pre-created and dying users.
*
@@ -4512,8 +4571,9 @@
pw.print(prefix); pw.print(" userId="); pw.println(ps.getAppId());
- if (ps.getSharedUser() != null) {
- pw.print(prefix); pw.print(" sharedUser="); pw.println(ps.getSharedUser());
+ SharedUserSetting sharedUserSetting = getSharedUserSettingLPr(ps);
+ if (sharedUserSetting != null) {
+ pw.print(prefix); pw.print(" sharedUser="); pw.println(sharedUserSetting);
}
pw.print(prefix); pw.print(" pkg="); pw.println(pkg);
pw.print(prefix); pw.print(" codePath="); pw.println(ps.getPathString());
@@ -4797,7 +4857,7 @@
}
}
- if (ps.getSharedUser() == null || permissionNames != null || dumpAll) {
+ if (!ps.hasSharedUser() || permissionNames != null || dumpAll) {
dumpInstallPermissionsLPr(pw, prefix + " ", permissionNames, permissionsState, users);
}
@@ -4917,7 +4977,7 @@
pw.println(lastDisabledAppCaller);
}
- if (ps.getSharedUser() == null) {
+ if (!ps.hasSharedUser()) {
dumpGidsLPr(pw, prefix + " ", mPermissionDataProvider.getGidsForUid(
UserHandle.getUid(user.id, ps.getAppId())));
dumpRuntimePermissionsLPr(pw, prefix + " ", permissionNames, permissionsState
@@ -4931,18 +4991,18 @@
}
if (permissionNames == null) {
- Set<String> cmp = userState.getDisabledComponents();
+ WatchedArraySet<String> cmp = userState.getDisabledComponentsNoCopy();
if (cmp != null && cmp.size() > 0) {
pw.print(prefix); pw.println(" disabledComponents:");
- for (String s : cmp) {
- pw.print(prefix); pw.print(" "); pw.println(s);
+ for (int i = 0; i < cmp.size(); i++) {
+ pw.print(prefix); pw.print(" "); pw.println(cmp.valueAt(i));
}
}
- cmp = userState.getEnabledComponents();
+ cmp = userState.getEnabledComponentsNoCopy();
if (cmp != null && cmp.size() > 0) {
pw.print(prefix); pw.println(" enabledComponents:");
- for (String s : cmp) {
- pw.print(prefix); pw.print(" "); pw.println(s);
+ for (int i = 0; i < cmp.size(); i++) {
+ pw.print(prefix); pw.print(" "); pw.println(cmp.valueAt(i));
}
}
}
@@ -4970,7 +5030,7 @@
}
if (!checkin && packageName != null) {
- dumpState.setSharedUser(ps.getSharedUser());
+ dumpState.setSharedUser(getSharedUserSettingLPr(ps));
}
if (!checkin && !printedSomething) {
@@ -5053,7 +5113,7 @@
continue;
}
final LegacyPermissionState permissionsState =
- mPermissionDataProvider.getLegacyPermissionState(su.userId);
+ mPermissionDataProvider.getLegacyPermissionState(su.mAppId);
if (permissionNames != null
&& !permissionsState.hasPermissionState(permissionNames)) {
continue;
@@ -5073,7 +5133,7 @@
pw.println("):");
String prefix = " ";
- pw.print(prefix); pw.print("userId="); pw.println(su.userId);
+ pw.print(prefix); pw.print("userId="); pw.println(su.mAppId);
pw.print(prefix); pw.println("Packages");
final int numPackages = su.packages.size();
@@ -5097,7 +5157,7 @@
for (UserInfo user : users) {
final int userId = user.id;
final int[] gids = mPermissionDataProvider.getGidsForUid(UserHandle.getUid(
- userId, su.userId));
+ userId, su.mAppId));
final Collection<PermissionState> permissions =
permissionsState.getPermissionStates(userId);
if (!ArrayUtils.isEmpty(gids) || !permissions.isEmpty()) {
@@ -5108,7 +5168,7 @@
}
}
} else {
- pw.print("suid,"); pw.print(su.userId); pw.print(","); pw.println(su.name);
+ pw.print("suid,"); pw.print(su.mAppId); pw.print(","); pw.println(su.name);
}
}
}
@@ -5510,7 +5570,7 @@
for (int i = 0; i < packagesSize; i++) {
String packageName = packageStates.keyAt(i);
PackageStateInternal packageState = packageStates.valueAt(i);
- if (packageState.getSharedUser() == null) {
+ if (!packageState.hasSharedUser()) {
List<RuntimePermissionsState.PermissionState> permissions =
getPermissionsFromPermissionsState(
packageState.getLegacyPermissionState(), userId);
@@ -5616,8 +5676,9 @@
packageSetting.getLegacyPermissionState(),
userId);
packageSetting.setInstallPermissionsFixed(true);
- } else if (packageSetting.getSharedUser() == null && !isUpgradeToR) {
- Slog.w(TAG, "Missing permission state for package: " + packageName);
+ } else if (!packageSetting.hasSharedUser() && !isUpgradeToR) {
+ Slogf.w(TAG, "Missing permission state for package %s on user %d",
+ packageName, userId);
packageSetting.getLegacyPermissionState().setMissing(true, userId);
}
}
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index 5ef1471..d0e1e6c 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -19,9 +19,6 @@
import android.annotation.NonNull;
import android.content.pm.ApplicationInfo;
import android.content.pm.SigningDetails;
-import com.android.server.pm.pkg.component.ComponentMutateUtils;
-import com.android.server.pm.pkg.component.ParsedProcess;
-import com.android.server.pm.pkg.component.ParsedProcessImpl;
import android.service.pm.PackageServiceDumpProto;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -29,8 +26,12 @@
import com.android.internal.util.ArrayUtils;
import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.permission.LegacyPermissionState;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.SharedUserApi;
+import com.android.server.pm.pkg.component.ComponentMutateUtils;
+import com.android.server.pm.pkg.component.ParsedProcess;
+import com.android.server.pm.pkg.component.ParsedProcessImpl;
import com.android.server.utils.SnapshotCache;
import libcore.util.EmptyArray;
@@ -46,7 +47,7 @@
public final class SharedUserSetting extends SettingBase implements SharedUserApi {
final String name;
- int userId;
+ int mAppId;
/** @see SharedUserApi#getUidFlags() **/
int uidFlags;
@@ -98,7 +99,7 @@
private SharedUserSetting(SharedUserSetting orig) {
super(orig);
name = orig.name;
- userId = orig.userId;
+ mAppId = orig.mAppId;
uidFlags = orig.uidFlags;
uidPrivateFlags = orig.uidPrivateFlags;
packages = new ArraySet<>(orig.packages);
@@ -133,12 +134,12 @@
@Override
public String toString() {
return "SharedUserSetting{" + Integer.toHexString(System.identityHashCode(this)) + " "
- + name + "/" + userId + "}";
+ + name + "/" + mAppId + "}";
}
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
long token = proto.start(fieldId);
- proto.write(PackageServiceDumpProto.SharedUserProto.UID, userId);
+ proto.write(PackageServiceDumpProto.SharedUserProto.UID, mAppId);
proto.write(PackageServiceDumpProto.SharedUserProto.NAME, name);
proto.end(token);
}
@@ -286,7 +287,7 @@
/** Updates all fields in this shared user setting from another. */
public SharedUserSetting updateFrom(SharedUserSetting sharedUser) {
super.copySettingBase(sharedUser);
- this.userId = sharedUser.userId;
+ this.mAppId = sharedUser.mAppId;
this.uidFlags = sharedUser.uidFlags;
this.uidPrivateFlags = sharedUser.uidPrivateFlags;
this.seInfoTargetSdkVersion = sharedUser.seInfoTargetSdkVersion;
@@ -315,8 +316,8 @@
}
@Override
- public int getUserId() {
- return userId;
+ public int getAppId() {
+ return mAppId;
}
@Override
@@ -363,4 +364,10 @@
public ArrayMap<String, ParsedProcess> getProcesses() {
return processes;
}
+
+ @NonNull
+ @Override
+ public LegacyPermissionState getSharedUserLegacyPermissionState() {
+ return super.getLegacyPermissionState();
+ }
}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index bda2589..8921fee 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -442,6 +442,16 @@
sortShortcutsToActivities();
final ArrayList<ShortcutInfo> activityShortcuts = all.get(newShortcut.getActivity());
+ if (activityShortcuts != null && activityShortcuts.size() > maxShortcuts) {
+ Slog.e(TAG, "Error pushing shortcut. There are already "
+ + activityShortcuts.size() + " shortcuts, exceeding the " + maxShortcuts
+ + " shortcuts limit when pushing the new shortcut " + newShortcut
+ + ". Id of shortcuts currently available in system memory are "
+ + activityShortcuts.stream().map(ShortcutInfo::getId)
+ .collect(Collectors.joining(",", "[", "]")));
+ // TODO: This should not have happened. If it does, identify the root cause where
+ // possible, otherwise bail-out early to prevent memory issue.
+ }
if (activityShortcuts != null && activityShortcuts.size() == maxShortcuts) {
// Max has reached. Delete the shortcut with lowest rank.
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 2760578..1cf2dc5 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -735,6 +735,9 @@
if (DEBUG || DEBUG_REBOOT) {
Slog.d(TAG, "unloadUserLocked: user=" + userId);
}
+ // Cancel any ongoing background tasks.
+ getUserShortcutsLocked(userId).cancelAllInFlightTasks();
+
// Save all dirty information.
saveDirtyInfo(false);
@@ -3736,6 +3739,7 @@
synchronized (mLock) {
if (mHandler.hasCallbacks(mSaveDirtyInfoRunner)) {
mHandler.removeCallbacks(mSaveDirtyInfoRunner);
+ forEachLoadedUserLocked(ShortcutUser::cancelAllInFlightTasks);
saveDirtyInfo(false);
}
mShutdown.set(true);
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index 408f045..4bb5dcf 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -33,6 +33,7 @@
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.logging.MetricsLogger;
@@ -50,7 +51,9 @@
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -138,6 +141,11 @@
private String mLastAppScanOsFingerprint;
private String mRestoreFromOsFingerprint;
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private final ArrayList<AndroidFuture<AppSearchSession>> mInFlightSessions = new ArrayList<>();
+
public ShortcutUser(ShortcutService service, int userId) {
mService = service;
mUserId = userId;
@@ -718,6 +726,10 @@
AndroidFuture<AppSearchSession> getAppSearch(
@NonNull final AppSearchManager.SearchContext searchContext) {
final AndroidFuture<AppSearchSession> future = new AndroidFuture<>();
+ synchronized (mLock) {
+ mInFlightSessions.removeIf(CompletableFuture::isDone);
+ mInFlightSessions.add(future);
+ }
if (mAppSearchManager == null) {
future.completeExceptionally(new RuntimeException("app search manager is null"));
return future;
@@ -743,4 +755,13 @@
}
return future;
}
+
+ void cancelAllInFlightTasks() {
+ synchronized (mLock) {
+ for (AndroidFuture<AppSearchSession> session : mInFlightSessions) {
+ session.cancel(true);
+ }
+ mInFlightSessions.clear();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index ccbdfed..52a7bed 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -23,11 +23,8 @@
import android.apex.ApexSessionParams;
import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.IIntentReceiver;
-import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.IntentSender;
import android.content.pm.ApexStagedEvent;
import android.content.pm.IStagedApexObserver;
import android.content.pm.PackageInstaller;
@@ -36,7 +33,6 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.StagedApexInfo;
-import android.os.Bundle;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.RemoteException;
@@ -78,8 +74,6 @@
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
/**
@@ -809,35 +803,6 @@
BackgroundThread.getExecutor().execute(() -> logFailedApexSessionsIfNecessary());
}
- private static class LocalIntentReceiverSync {
- private final LinkedBlockingQueue<Intent> mResult = new LinkedBlockingQueue<>();
-
- private final IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
- @Override
- public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
- IIntentReceiver finishedReceiver, String requiredPermission,
- Bundle options) {
- try {
- mResult.offer(intent, 5, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- }
- };
-
- public IntentSender getIntentSender() {
- return new IntentSender((IIntentSender) mLocalSender);
- }
-
- public Intent getResult() {
- try {
- return mResult.take();
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- }
- }
-
private StagedSession getStagedSession(int sessionId) {
StagedSession session;
synchronized (mStagedSessions) {
diff --git a/services/core/java/com/android/server/pm/SuspendPackageHelper.java b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
index 1ea8b24..85d1367 100644
--- a/services/core/java/com/android/server/pm/SuspendPackageHelper.java
+++ b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
@@ -52,6 +52,7 @@
import com.android.server.pm.pkg.PackageUserStateInternal;
import com.android.server.pm.pkg.SuspendParams;
import com.android.server.pm.pkg.mutate.PackageUserStateWrite;
+import com.android.server.utils.WatchedArrayMap;
import java.util.ArrayList;
import java.util.Arrays;
@@ -145,7 +146,7 @@
continue;
}
- final ArrayMap<String, SuspendParams> suspendParamsMap =
+ final WatchedArrayMap<String, SuspendParams> suspendParamsMap =
packageState.getUserStateOrDefault(userId).getSuspendParams();
final SuspendParams suspendParams = suspendParamsMap == null
? null : suspendParamsMap.get(packageName);
@@ -297,7 +298,8 @@
continue;
}
- ArrayMap<String, SuspendParams> suspendParamsMap = packageUserState.getSuspendParams();
+ WatchedArrayMap<String, SuspendParams> suspendParamsMap =
+ packageUserState.getSuspendParams();
int countRemoved = 0;
for (int index = 0; index < suspendParamsMap.size(); index++) {
String suspendingPackage = suspendParamsMap.keyAt(index);
@@ -440,7 +442,8 @@
return null;
}
- final ArrayMap<String, SuspendParams> suspendParamsMap = userState.getSuspendParams();
+ final WatchedArrayMap<String, SuspendParams> suspendParamsMap =
+ userState.getSuspendParams();
if (suspendParamsMap == null) {
return null;
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index e63d721..5c4d011 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1517,7 +1517,6 @@
return userTypeDetails.getBadgeNoBackground();
}
- @Override
public boolean isProfile(@UserIdInt int userId) {
checkQueryOrInteractPermissionIfCallerInOtherProfileGroup(userId, "isProfile");
synchronized (mUsersLock) {
@@ -1526,21 +1525,19 @@
}
}
+ /**
+ * Returns the user type (if it is a profile), empty string (if it isn't a profile),
+ * or null (if the user doesn't exist).
+ */
@Override
- public boolean isManagedProfile(@UserIdInt int userId) {
- checkQueryOrInteractPermissionIfCallerInOtherProfileGroup(userId, "isManagedProfile");
+ public @Nullable String getProfileType(@UserIdInt int userId) {
+ checkQueryOrInteractPermissionIfCallerInOtherProfileGroup(userId, "getProfileType");
synchronized (mUsersLock) {
UserInfo userInfo = getUserInfoLU(userId);
- return userInfo != null && userInfo.isManagedProfile();
- }
- }
-
- @Override
- public boolean isCloneProfile(@UserIdInt int userId) {
- checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId, "isCloneProfile");
- synchronized (mUsersLock) {
- UserInfo userInfo = getUserInfoLU(userId);
- return userInfo != null && userInfo.isCloneProfile();
+ if (userInfo != null) {
+ return userInfo.isProfile() ? userInfo.userType : "";
+ }
+ return null;
}
}
@@ -5163,6 +5160,8 @@
nextId = scanNextAvailableIdLocked();
}
}
+ // If we got here, we probably recycled user ids, so invalidate any caches.
+ UserManager.invalidateStaticUserProperties();
if (nextId < 0) {
throw new IllegalStateException("No user id available!");
}
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index 6e6585e..1e3b67c 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -332,13 +332,13 @@
}
String typeName = parser.getAttributeValue(null, "name");
- if (typeName == null) {
+ if (typeName == null || typeName.equals("")) {
Slog.w(LOG_TAG, "Skipping user type with no name in "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
}
- typeName.intern();
+ typeName = typeName.intern();
UserTypeDetails.Builder builder;
if (typeName.startsWith("android.")) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index ed351fd..ed47bfb7 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -17,6 +17,7 @@
package com.android.server.pm.permission;
import static android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY;
+import static android.Manifest.permission.POST_NOTIFICATIONS;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import static android.content.pm.PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT;
@@ -41,6 +42,7 @@
import static android.content.pm.PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE;
import static android.content.pm.PackageManager.MASK_PERMISSION_FLAGS_ALL;
import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+import static android.os.Process.INVALID_UID;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.permission.PermissionManager.KILL_APP_REASON_GIDS_CHANGED;
import static android.permission.PermissionManager.KILL_APP_REASON_PERMISSIONS_REVOKED;
@@ -129,6 +131,7 @@
import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.pkg.AndroidPackageApi;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.component.ComponentMutateUtils;
import com.android.server.pm.pkg.component.ParsedPermission;
@@ -752,11 +755,14 @@
flagValues &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
flagMask &= ~PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
flagValues &= ~PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
- flagValues &= ~PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
flagValues &= ~FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
flagValues &= ~FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
flagValues &= ~FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
flagValues &= ~PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
+ // REVIEW_REQUIRED can only be set by non-system apps for for POST_NOTIFICATIONS
+ if (!POST_NOTIFICATIONS.equals(permName)) {
+ flagValues &= ~PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
+ }
}
final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
@@ -2538,16 +2544,18 @@
if (uidState.isMissing()) {
Collection<String> uidRequestedPermissions;
int targetSdkVersion;
- if (ps.getSharedUser() == null) {
+ if (!ps.hasSharedUser()) {
uidRequestedPermissions = pkg.getRequestedPermissions();
targetSdkVersion = pkg.getTargetSdkVersion();
} else {
uidRequestedPermissions = new ArraySet<>();
targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
- List<AndroidPackage> packages = ps.getSharedUser().getPackages();
+ final ArraySet<PackageStateInternal> packages =
+ mPackageManagerInt.getSharedUserPackages(ps.getSharedUserAppId());
int packagesSize = packages.size();
for (int i = 0; i < packagesSize; i++) {
- AndroidPackage sharedUserPackage = packages.get(i);
+ AndroidPackageApi sharedUserPackage =
+ packages.valueAt(i).getAndroidPackage();
uidRequestedPermissions.addAll(
sharedUserPackage.getRequestedPermissions());
targetSdkVersion = Math.min(targetSdkVersion,
@@ -2589,7 +2597,7 @@
if (replace) {
userState.setInstallPermissionsFixed(ps.getPackageName(), false);
- if (ps.getSharedUser() == null) {
+ if (!ps.hasSharedUser()) {
origState = new UidPermissionState(uidState);
uidState.reset();
} else {
@@ -2599,7 +2607,8 @@
// changed runtime permissions here are promotion of an install to
// runtime and revocation of a runtime from a shared user.
if (revokeUnusedSharedUserPermissionsLocked(
- ps.getSharedUser().getPackages(), uidState)) {
+ mPackageManagerInt.getSharedUserPackages(ps.getSharedUserAppId()),
+ uidState)) {
updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
runtimePermissionsRevoked = true;
}
@@ -3166,44 +3175,12 @@
inheritPermissionStateToNewImplicitPermissionLocked(sourcePerms, newPerm, ps,
pkg);
}
- } else if (NOTIFICATION_PERMISSIONS.contains(newPerm)) {
- //&& (origPs.getPermissionState(newPerm) == null) {
- // TODO(b/205888750): add back line about origPs once all TODO sections below are
- // propagated through droidfood
- Permission bp = mRegistry.getPermission(newPerm);
- if (bp == null) {
- throw new IllegalStateException("Unknown new permission " + newPerm);
- }
- if (!isUserSetOrPregrantedOrFixed(ps.getPermissionFlags(newPerm))) {
- updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
- int setFlag = ps.isPermissionGranted(newPerm)
- ? 0 : FLAG_PERMISSION_REVIEW_REQUIRED;
- ps.updatePermissionFlags(bp, FLAG_PERMISSION_REVIEW_REQUIRED, setFlag);
- // TODO(b/205888750): remove if/else block once propagated through droidfood
- if (ps.isPermissionGranted(newPerm)
- && pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M) {
- ps.revokePermission(bp);
- } else if (!ps.isPermissionGranted(newPerm)
- && pkg.getTargetSdkVersion() < Build.VERSION_CODES.M) {
- ps.grantPermission(bp);
- }
- } else {
- // TODO(b/205888750): remove once propagated through droidfood
- ps.updatePermissionFlags(bp, FLAG_PERMISSION_REVOKE_WHEN_REQUESTED
- | FLAG_PERMISSION_REVIEW_REQUIRED, 0);
- }
}
}
return updatedUserIds;
}
- private boolean isUserSetOrPregrantedOrFixed(int flags) {
- return (flags & (FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_USER_FIXED
- | FLAG_PERMISSION_POLICY_FIXED | FLAG_PERMISSION_SYSTEM_FIXED
- | FLAG_PERMISSION_GRANTED_BY_DEFAULT | FLAG_PERMISSION_GRANTED_BY_ROLE)) != 0;
- }
-
@NonNull
@Override
public List<SplitPermissionInfoParcelable> getSplitPermissions() {
@@ -3845,13 +3822,14 @@
@GuardedBy("mLock")
private boolean revokeUnusedSharedUserPermissionsLocked(
- List<AndroidPackage> pkgList, UidPermissionState uidState) {
+ ArraySet<PackageStateInternal> pkgList, UidPermissionState uidState) {
// Collect all used permissions in the UID
final ArraySet<String> usedPermissions = new ArraySet<>();
if (pkgList == null || pkgList.size() == 0) {
return false;
}
- for (AndroidPackage pkg : pkgList) {
+ for (PackageStateInternal pkgState : pkgList) {
+ final AndroidPackageApi pkg = pkgState.getAndroidPackage();
if (pkg.getRequestedPermissions().isEmpty()) {
continue;
}
@@ -4485,8 +4463,13 @@
final int[] userIds = getAllUserIds();
mPackageManagerInt.forEachPackageState(ps -> {
final int appId = ps.getAppId();
- final LegacyPermissionState legacyState = ps.getLegacyPermissionState();
-
+ final LegacyPermissionState legacyState;
+ if (ps.hasSharedUser()) {
+ legacyState = mPackageManagerInt.getSharedUserApi(
+ ps.getSharedUserAppId()).getSharedUserLegacyPermissionState();
+ } else {
+ legacyState = ps.getLegacyPermissionState();
+ }
synchronized (mLock) {
for (final int userId : userIds) {
final UserPermissionState userState = mState.getOrCreateUserState(userId);
@@ -4526,7 +4509,13 @@
}
mPackageManagerInt.forEachPackageSetting(ps -> {
ps.setInstallPermissionsFixed(false);
- final LegacyPermissionState legacyState = ps.getLegacyPermissionState();
+ final LegacyPermissionState legacyState;
+ if (ps.hasSharedUser()) {
+ legacyState = mPackageManagerInt.getSharedUserApi(
+ ps.getSharedUserAppId()).getSharedUserLegacyPermissionState();
+ } else {
+ legacyState = ps.getLegacyPermissionState();
+ }
legacyState.reset();
final int appId = ps.getAppId();
@@ -4872,7 +4861,7 @@
final PackageStateInternal ps =
mPackageManagerInt.getPackageStateInternal(pkg.getPackageName());
- if (ps.getSharedUser() != null) {
+ if (ps.hasSharedUser()) {
// The package is joining a shared user group. This can only happen when a system
// app left shared UID with an update, and then the update is uninstalled.
// If no apps remain in its original shared UID group, clone the current
@@ -4963,7 +4952,7 @@
private void onPackageInstalledInternal(@NonNull AndroidPackage pkg, int previousAppId,
@NonNull PermissionManagerServiceInternal.PackageInstalledParams params,
@UserIdInt int[] userIds) {
- if (previousAppId != Process.INVALID_UID) {
+ if (previousAppId != INVALID_UID) {
handleAppIdMigration(pkg, previousAppId);
}
updatePermissions(pkg.getPackageName(), pkg);
diff --git a/services/core/java/com/android/server/pm/pkg/PackageState.java b/services/core/java/com/android/server/pm/pkg/PackageState.java
index 9fa9644..7726d7f 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageState.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageState.java
@@ -159,12 +159,18 @@
String getSecondaryCpuAbi();
/**
- * Retrieves the shared user ID. Note that the actual shared user data is not available here and
- * must be queried separately.
- *
- * @return the shared user this package is a part of, or -1 if it's not part of a shared user.
+ * Whether the package shares the same user ID as other packages
*/
- int getSharedUserId();
+ boolean hasSharedUser();
+
+ /**
+ * Retrieves the shared user app ID. Note that the actual shared user data is not available here
+ * and must be queried separately.
+ *
+ * @return the app ID of the shared user that this package is a part of, or -1 if it's not part
+ * of a shared user.
+ */
+ int getSharedUserAppId();
@NonNull
SigningInfo getSigningInfo();
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java b/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
index 9395ca5..3170304 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
@@ -24,6 +24,7 @@
import android.content.pm.SharedLibraryInfo;
import android.content.pm.SigningInfo;
import android.content.pm.overlay.OverlayPaths;
+import android.util.ArraySet;
import android.util.SparseArray;
import com.android.internal.util.DataClass;
@@ -126,8 +127,8 @@
private final String mPrimaryCpuAbi;
@Nullable
private final String mSecondaryCpuAbi;
- @Nullable
- private final int mSharedUserId;
+ private final boolean mHasSharedUser;
+ private final int mSharedUserAppId;
@NonNull
private final String[] mUsesSdkLibraries;
@NonNull
@@ -172,7 +173,8 @@
mPath = pkgState.getPath();
mPrimaryCpuAbi = pkgState.getPrimaryCpuAbi();
mSecondaryCpuAbi = pkgState.getSecondaryCpuAbi();
- mSharedUserId = pkgState.getSharedUserId();
+ mHasSharedUser = pkgState.hasSharedUser();
+ mSharedUserAppId = pkgState.getSharedUserAppId();
mUsesSdkLibraries = pkgState.getUsesSdkLibraries();
mUsesSdkLibrariesVersionsMajor = pkgState.getUsesSdkLibrariesVersionsMajor();
mUsesStaticLibraries = pkgState.getUsesStaticLibraries();
@@ -271,6 +273,15 @@
return mLongVersionCode;
}
+ @Override
+ public boolean hasSharedUser() {
+ return mHasSharedUser;
+ }
+
+ @Override
+ public int getSharedUserAppId() {
+ return mSharedUserAppId;
+ }
/**
* @hide
*/
@@ -319,11 +330,11 @@
private final long mCeDataInode;
@NonNull
- private final Set<String> mDisabledComponents;
+ private final ArraySet<String> mDisabledComponents;
@PackageManager.DistractionRestriction
private final int mDistractionFlags;
@NonNull
- private final Set<String> mEnabledComponents;
+ private final ArraySet<String> mEnabledComponents;
private final int mEnabledState;
@Nullable
private final String mHarmfulAppWarning;
@@ -450,7 +461,8 @@
}
@DataClass.Generated.Member
- public @NonNull Set<String> getDisabledComponents() {
+ public @NonNull
+ ArraySet<String> getDisabledComponents() {
return mDisabledComponents;
}
@@ -460,7 +472,7 @@
}
@DataClass.Generated.Member
- public @NonNull Set<String> getEnabledComponents() {
+ public @NonNull ArraySet<String> getEnabledComponents() {
return mEnabledComponents;
}
@@ -516,7 +528,7 @@
}
@DataClass.Generated(
- time = 1640209608883L,
+ time = 1644270981508L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java",
inputSignatures = "private int mBooleans\nprivate final long mCeDataInode\nprivate final @android.annotation.NonNull java.util.Set<java.lang.String> mDisabledComponents\nprivate final @android.content.pm.PackageManager.DistractionRestriction int mDistractionFlags\nprivate final @android.annotation.NonNull java.util.Set<java.lang.String> mEnabledComponents\nprivate final int mEnabledState\nprivate final @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate final @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate final @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprivate final @android.annotation.NonNull android.content.pm.overlay.OverlayPaths mOverlayPaths\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate final @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate final @android.annotation.Nullable java.lang.String mSplashScreenTheme\nprivate final long mFirstInstallTime\npublic static com.android.server.pm.pkg.PackageUserState copy(com.android.server.pm.pkg.PackageUserState)\nprivate void setBoolean(int,boolean)\nprivate boolean getBoolean(int)\npublic @java.lang.Override boolean isHidden()\npublic @java.lang.Override boolean isInstalled()\npublic @java.lang.Override boolean isInstantApp()\npublic @java.lang.Override boolean isNotLaunched()\npublic @java.lang.Override boolean isStopped()\npublic @java.lang.Override boolean isSuspended()\npublic @java.lang.Override boolean isVirtualPreload()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\nclass UserStateImpl extends java.lang.Object implements [com.android.server.pm.pkg.PackageUserState]\nprivate static final int HIDDEN\nprivate static final int INSTALLED\nprivate static final int INSTANT_APP\nprivate static final int NOT_LAUNCHED\nprivate static final int STOPPED\nprivate static final int SUSPENDED\nprivate static final int VIRTUAL_PRELOAD\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false)")
@@ -615,8 +627,8 @@
}
@DataClass.Generated.Member
- public @Nullable int getSharedUserId() {
- return mSharedUserId;
+ public boolean isHasSharedUser() {
+ return mHasSharedUser;
}
@DataClass.Generated.Member
@@ -671,10 +683,10 @@
}
@DataClass.Generated(
- time = 1640209608912L,
+ time = 1644270981543L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java",
- inputSignatures = "private int mBooleans\nprivate final @android.annotation.Nullable com.android.server.pm.pkg.AndroidPackageApi mAndroidPackage\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mVolumeUuid\nprivate final int mAppId\nprivate final int mCategoryOverride\nprivate final @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate final long mLastModifiedTime\nprivate final long mLastUpdateTime\nprivate final long mLongVersionCode\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mMimeGroups\nprivate final @android.annotation.NonNull java.io.File mPath\nprivate final @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate final @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate final @android.annotation.Nullable java.lang.Integer mSharedUserId\nprivate final @android.annotation.NonNull java.lang.String[] mUsesSdkLibraries\nprivate final @android.annotation.NonNull long[] mUsesSdkLibrariesVersionsMajor\nprivate final @android.annotation.NonNull java.lang.String[] mUsesStaticLibraries\nprivate final @android.annotation.NonNull long[] mUsesStaticLibrariesVersions\nprivate final @android.annotation.NonNull java.util.List<android.content.pm.SharedLibraryInfo> mUsesLibraryInfos\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mUsesLibraryFiles\nprivate final @android.annotation.NonNull long[] mLastPackageUsageTime\nprivate final @android.annotation.NonNull android.content.pm.SigningInfo mSigningInfo\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserState> mUserStates\npublic static com.android.server.pm.pkg.PackageState copy(com.android.server.pm.pkg.PackageStateInternal)\nprivate void setBoolean(int,boolean)\nprivate boolean getBoolean(int)\npublic @java.lang.Override boolean isExternalStorage()\npublic @java.lang.Override boolean isForceQueryableOverride()\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @java.lang.Override boolean isInstallPermissionsFixed()\npublic @java.lang.Override boolean isOdm()\npublic @java.lang.Override boolean isOem()\npublic @java.lang.Override boolean isPrivileged()\npublic @java.lang.Override boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic @java.lang.Override boolean isSystem()\npublic @java.lang.Override boolean isSystemExt()\npublic @java.lang.Override boolean isUpdateAvailable()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic @java.lang.Override boolean isVendor()\npublic @java.lang.Override long getVersionCode()\nclass PackageStateImpl extends java.lang.Object implements [com.android.server.pm.pkg.PackageState]\nprivate static final int SYSTEM\nprivate static final int EXTERNAL_STORAGE\nprivate static final int PRIVILEGED\nprivate static final int OEM\nprivate static final int VENDOR\nprivate static final int PRODUCT\nprivate static final int SYSTEM_EXT\nprivate static final int REQUIRED_FOR_SYSTEM_USER\nprivate static final int ODM\nprivate static final int FORCE_QUERYABLE_OVERRIDE\nprivate static final int HIDDEN_UNTIL_INSTALLED\nprivate static final int INSTALL_PERMISSIONS_FIXED\nprivate static final int UPDATE_AVAILABLE\nprivate static final int UPDATED_SYSTEM_APP\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false)")
+ inputSignatures = "private int mBooleans\nprivate final @android.annotation.Nullable com.android.server.pm.pkg.AndroidPackageApi mAndroidPackage\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mVolumeUuid\nprivate final int mAppId\nprivate final int mCategoryOverride\nprivate final @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate final long mLastModifiedTime\nprivate final long mLastUpdateTime\nprivate final long mLongVersionCode\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mMimeGroups\nprivate final @android.annotation.NonNull java.io.File mPath\nprivate final @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate final @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate final boolean mHasSharedUser\nprivate final int mSharedUserAppId\nprivate final @android.annotation.NonNull java.lang.String[] mUsesSdkLibraries\nprivate final @android.annotation.NonNull long[] mUsesSdkLibrariesVersionsMajor\nprivate final @android.annotation.NonNull java.lang.String[] mUsesStaticLibraries\nprivate final @android.annotation.NonNull long[] mUsesStaticLibrariesVersions\nprivate final @android.annotation.NonNull java.util.List<android.content.pm.SharedLibraryInfo> mUsesLibraryInfos\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mUsesLibraryFiles\nprivate final @android.annotation.NonNull long[] mLastPackageUsageTime\nprivate final @android.annotation.NonNull android.content.pm.SigningInfo mSigningInfo\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserState> mUserStates\npublic static com.android.server.pm.pkg.PackageState copy(com.android.server.pm.pkg.PackageStateInternal)\nprivate void setBoolean(int,boolean)\nprivate boolean getBoolean(int)\npublic @java.lang.Override boolean isExternalStorage()\npublic @java.lang.Override boolean isForceQueryableOverride()\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @java.lang.Override boolean isInstallPermissionsFixed()\npublic @java.lang.Override boolean isOdm()\npublic @java.lang.Override boolean isOem()\npublic @java.lang.Override boolean isPrivileged()\npublic @java.lang.Override boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic @java.lang.Override boolean isSystem()\npublic @java.lang.Override boolean isSystemExt()\npublic @java.lang.Override boolean isUpdateAvailable()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic @java.lang.Override boolean isVendor()\npublic @java.lang.Override long getVersionCode()\npublic @java.lang.Override boolean hasSharedUser()\npublic @java.lang.Override int getSharedUserAppId()\nclass PackageStateImpl extends java.lang.Object implements [com.android.server.pm.pkg.PackageState]\nprivate static final int SYSTEM\nprivate static final int EXTERNAL_STORAGE\nprivate static final int PRIVILEGED\nprivate static final int OEM\nprivate static final int VENDOR\nprivate static final int PRODUCT\nprivate static final int SYSTEM_EXT\nprivate static final int REQUIRED_FOR_SYSTEM_USER\nprivate static final int ODM\nprivate static final int FORCE_QUERYABLE_OVERRIDE\nprivate static final int HIDDEN_UNTIL_INSTALLED\nprivate static final int INSTALL_PERMISSIONS_FIXED\nprivate static final int UPDATE_AVAILABLE\nprivate static final int UPDATED_SYSTEM_APP\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java b/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java
index fb2fe1f..68a00a9 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java
@@ -50,9 +50,6 @@
@NonNull
InstallSource getInstallSource();
- @Nullable
- SharedUserApi getSharedUser();
-
// TODO: Remove this in favor of boolean APIs
int getFlags();
int getPrivateFlags();
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserState.java b/services/core/java/com/android/server/pm/pkg/PackageUserState.java
index bed1401..e19e555 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserState.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserState.java
@@ -18,14 +18,12 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
import android.content.pm.PackageManager;
import android.content.pm.overlay.OverlayPaths;
import android.os.UserHandle;
+import android.util.ArraySet;
import java.util.Map;
-import java.util.Set;
/**
* The API surface for {@link PackageUserStateInternal}, for use by in-process mainline consumers.
@@ -59,7 +57,7 @@
* Fully qualified class names of components explicitly disabled.
*/
@NonNull
- Set<String> getDisabledComponents();
+ ArraySet<String> getDisabledComponents();
@PackageManager.DistractionRestriction
int getDistractionFlags();
@@ -68,7 +66,7 @@
* Fully qualified class names of components explicitly enabled.
*/
@NonNull
- Set<String> getEnabledComponents();
+ ArraySet<String> getEnabledComponents();
/**
* Retrieve the effective enabled state of the package itself.
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
index 73c86c7..daa4545 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
@@ -21,13 +21,14 @@
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.content.pm.overlay.OverlayPaths;
-import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Pair;
+import com.android.server.utils.WatchedArrayMap;
+import com.android.server.utils.WatchedArraySet;
+
import java.util.Collections;
import java.util.Map;
-import java.util.Set;
class PackageUserStateDefault implements PackageUserStateInternal {
@@ -59,14 +60,14 @@
@NonNull
@Override
- public Set<String> getDisabledComponents() {
- return Collections.emptySet();
+ public ArraySet<String> getDisabledComponents() {
+ return new ArraySet<>();
}
@NonNull
@Override
- public Set<String> getEnabledComponents() {
- return Collections.emptySet();
+ public ArraySet<String> getEnabledComponents() {
+ return new ArraySet<>();
}
@Override
@@ -156,19 +157,19 @@
@Nullable
@Override
- public ArrayMap<String, SuspendParams> getSuspendParams() {
+ public WatchedArrayMap<String, SuspendParams> getSuspendParams() {
return null;
}
@Nullable
@Override
- public ArraySet<String> getDisabledComponentsNoCopy() {
+ public WatchedArraySet<String> getDisabledComponentsNoCopy() {
return null;
}
@Nullable
@Override
- public ArraySet<String> getEnabledComponentsNoCopy() {
+ public WatchedArraySet<String> getEnabledComponentsNoCopy() {
return null;
}
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
index efb6144..410fa97 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
@@ -30,19 +30,25 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DataClass;
+import com.android.server.utils.Snappable;
+import com.android.server.utils.SnapshotCache;
import com.android.server.utils.Watchable;
+import com.android.server.utils.WatchableImpl;
+import com.android.server.utils.WatchedArrayMap;
+import com.android.server.utils.WatchedArraySet;
import java.util.Objects;
@DataClass(genConstructor = false, genBuilder = false, genEqualsHashCode = true)
@DataClass.Suppress({"mOverlayPathsLock", "mOverlayPaths", "mSharedLibraryOverlayPathsLock",
"mSharedLibraryOverlayPaths", "setOverlayPaths", "setCachedOverlayPaths"})
-public class PackageUserStateImpl implements PackageUserStateInternal {
+public class PackageUserStateImpl extends WatchableImpl implements PackageUserStateInternal,
+ Snappable {
@Nullable
- protected ArraySet<String> mDisabledComponents;
+ protected WatchedArraySet<String> mDisabledComponentsWatched;
@Nullable
- protected ArraySet<String> mEnabledComponents;
+ protected WatchedArraySet<String> mEnabledComponentsWatched;
private long mCeDataInode;
private boolean mInstalled = true;
@@ -63,11 +69,11 @@
private String mLastDisableAppCaller;
@Nullable
- protected OverlayPaths mOverlayPaths;
+ private OverlayPaths mOverlayPaths;
// Lib name to overlay paths
@Nullable
- protected ArrayMap<String, OverlayPaths> mSharedLibraryOverlayPaths;
+ protected WatchedArrayMap<String, OverlayPaths> mSharedLibraryOverlayPaths;
@Nullable
private String mSplashScreenTheme;
@@ -76,33 +82,50 @@
* Suspending package to suspend params
*/
@Nullable
- private ArrayMap<String, SuspendParams> mSuspendParams;
+ private WatchedArrayMap<String, SuspendParams> mSuspendParams;
@Nullable
- private ArrayMap<ComponentName, Pair<String, Integer>> mComponentLabelIconOverrideMap;
+ private WatchedArrayMap<ComponentName, Pair<String, Integer>> mComponentLabelIconOverrideMap;
private long mFirstInstallTime;
@Nullable
private final Watchable mWatchable;
+ @NonNull
+ final SnapshotCache<PackageUserStateImpl> mSnapshot;
+
+ private SnapshotCache<PackageUserStateImpl> makeCache() {
+ return new SnapshotCache<PackageUserStateImpl>(this, this) {
+ @Override
+ public PackageUserStateImpl createSnapshot() {
+ return new PackageUserStateImpl(mWatchable, mSource);
+ }};
+ }
+
+ /**
+ * Only used for tests
+ */
public PackageUserStateImpl() {
super();
mWatchable = null;
+ mSnapshot = makeCache();
}
public PackageUserStateImpl(@NonNull Watchable watchable) {
mWatchable = watchable;
+ mSnapshot = makeCache();
}
public PackageUserStateImpl(@NonNull Watchable watchable, PackageUserStateImpl other) {
mWatchable = watchable;
- mDisabledComponents = ArrayUtils.cloneOrNull(other.mDisabledComponents);
- mEnabledComponents = ArrayUtils.cloneOrNull(other.mEnabledComponents);
+ mDisabledComponentsWatched = other.mDisabledComponentsWatched == null
+ ? null : other.mDisabledComponentsWatched.snapshot();
+ mEnabledComponentsWatched = other.mEnabledComponentsWatched == null
+ ? null : other.mEnabledComponentsWatched.snapshot();
mOverlayPaths = other.mOverlayPaths;
- if (other.mSharedLibraryOverlayPaths != null) {
- mSharedLibraryOverlayPaths = new ArrayMap<>(other.mSharedLibraryOverlayPaths);
- }
+ mSharedLibraryOverlayPaths = other.mSharedLibraryOverlayPaths == null
+ ? null : other.mSharedLibraryOverlayPaths.snapshot();
mCeDataInode = other.mCeDataInode;
mInstalled = other.mInstalled;
mStopped = other.mStopped;
@@ -117,16 +140,24 @@
mHarmfulAppWarning = other.mHarmfulAppWarning;
mLastDisableAppCaller = other.mLastDisableAppCaller;
mSplashScreenTheme = other.mSplashScreenTheme;
- mSuspendParams = other.mSuspendParams == null ? null : new ArrayMap<>(other.mSuspendParams);
- mComponentLabelIconOverrideMap = other.mComponentLabelIconOverrideMap == null ? null
- : new ArrayMap<>(other.mComponentLabelIconOverrideMap);
+ mSuspendParams = other.mSuspendParams == null ? null : other.mSuspendParams.snapshot();
+ mComponentLabelIconOverrideMap = other.mComponentLabelIconOverrideMap == null
+ ? null : other.mComponentLabelIconOverrideMap.snapshot();
mFirstInstallTime = other.mFirstInstallTime;
+ mSnapshot = new SnapshotCache.Sealed<>();
}
private void onChanged() {
if (mWatchable != null) {
mWatchable.dispatchChange(mWatchable);
}
+ dispatchChange(this);
+ }
+
+ @NonNull
+ @Override
+ public PackageUserStateImpl snapshot() {
+ return mSnapshot.snapshot();
}
/**
@@ -156,7 +187,8 @@
public boolean setSharedLibraryOverlayPaths(@NonNull String library,
@Nullable OverlayPaths paths) {
if (mSharedLibraryOverlayPaths == null) {
- mSharedLibraryOverlayPaths = new ArrayMap<>();
+ mSharedLibraryOverlayPaths = new WatchedArrayMap<>();
+ mSharedLibraryOverlayPaths.registerObserver(mSnapshot);
}
final OverlayPaths currentPaths = mSharedLibraryOverlayPaths.get(library);
if (Objects.equals(paths, currentPaths)) {
@@ -175,26 +207,41 @@
@Nullable
@Override
- public ArraySet<String> getDisabledComponentsNoCopy() {
- return mDisabledComponents;
+ public WatchedArraySet<String> getDisabledComponentsNoCopy() {
+ return mDisabledComponentsWatched;
}
@Nullable
@Override
- public ArraySet<String> getEnabledComponentsNoCopy() {
- return mEnabledComponents;
+ public WatchedArraySet<String> getEnabledComponentsNoCopy() {
+ return mEnabledComponentsWatched;
}
+ @NonNull
+ @Override
+ public ArraySet<String> getDisabledComponents() {
+ return mDisabledComponentsWatched == null
+ ? new ArraySet<>() : mDisabledComponentsWatched.untrackedStorage();
+ }
+
+ @NonNull
+ @Override
+ public ArraySet<String> getEnabledComponents() {
+ return mEnabledComponentsWatched == null
+ ? new ArraySet<>() : mEnabledComponentsWatched.untrackedStorage();
+ }
+
+
@Override
public boolean isComponentEnabled(String componentName) {
- // TODO: Not locked
- return ArrayUtils.contains(mEnabledComponents, componentName);
+ return mEnabledComponentsWatched != null
+ && mEnabledComponentsWatched.contains(componentName);
}
@Override
public boolean isComponentDisabled(String componentName) {
- // TODO: Not locked
- return ArrayUtils.contains(mDisabledComponents, componentName);
+ return mDisabledComponentsWatched != null
+ && mDisabledComponentsWatched.contains(componentName);
}
@Override
@@ -242,7 +289,8 @@
}
} else {
if (mComponentLabelIconOverrideMap == null) {
- mComponentLabelIconOverrideMap = new ArrayMap<>(1);
+ mComponentLabelIconOverrideMap = new WatchedArrayMap<>(1);
+ mComponentLabelIconOverrideMap.registerObserver(mSnapshot);
}
mComponentLabelIconOverrideMap.put(component, Pair.create(nonLocalizedLabel, icon));
@@ -281,7 +329,8 @@
public PackageUserStateImpl putSuspendParams(@NonNull String suspendingPackage,
@Nullable SuspendParams suspendParams) {
if (mSuspendParams == null) {
- mSuspendParams = new ArrayMap<>();
+ mSuspendParams = new WatchedArrayMap<>();
+ mSuspendParams.registerObserver(mSnapshot);
}
if (!mSuspendParams.containsKey(suspendingPackage)
|| !Objects.equals(mSuspendParams.get(suspendingPackage), suspendParams)) {
@@ -300,14 +349,50 @@
return this;
}
- public @NonNull PackageUserStateImpl setDisabledComponents(@NonNull ArraySet<String> value) {
- mDisabledComponents = value;
+ public @NonNull PackageUserStateImpl setDisabledComponents(@Nullable ArraySet<String> value) {
+ if (value == null) {
+ return this;
+ }
+ if (mDisabledComponentsWatched == null) {
+ mDisabledComponentsWatched = new WatchedArraySet<>();
+ mDisabledComponentsWatched.registerObserver(mSnapshot);
+ }
+ mDisabledComponentsWatched.clear();
+ mDisabledComponentsWatched.addAll(value);
onChanged();
return this;
}
- public @NonNull PackageUserStateImpl setEnabledComponents(@NonNull ArraySet<String> value) {
- mEnabledComponents = value;
+ public @NonNull PackageUserStateImpl setEnabledComponents(@Nullable ArraySet<String> value) {
+ if (value == null) {
+ return this;
+ }
+ if (mEnabledComponentsWatched == null) {
+ mEnabledComponentsWatched = new WatchedArraySet<>();
+ mEnabledComponentsWatched.registerObserver(mSnapshot);
+ }
+ mEnabledComponentsWatched.clear();
+ mEnabledComponentsWatched.addAll(value);
+ onChanged();
+ return this;
+ }
+
+ public @NonNull PackageUserStateImpl setEnabledComponents(
+ @Nullable WatchedArraySet<String> value) {
+ mEnabledComponentsWatched = value;
+ if (mEnabledComponentsWatched != null) {
+ mEnabledComponentsWatched.registerObserver(mSnapshot);
+ }
+ onChanged();
+ return this;
+ }
+
+ public @NonNull PackageUserStateImpl setDisabledComponents(
+ @Nullable WatchedArraySet<String> value) {
+ mDisabledComponentsWatched = value;
+ if (mDisabledComponentsWatched != null) {
+ mDisabledComponentsWatched.registerObserver(mSnapshot);
+ }
onChanged();
return this;
}
@@ -397,7 +482,15 @@
public @NonNull PackageUserStateImpl setSharedLibraryOverlayPaths(
@NonNull ArrayMap<String, OverlayPaths> value) {
- mSharedLibraryOverlayPaths = value;
+ if (value == null) {
+ return this;
+ }
+ if (mSharedLibraryOverlayPaths == null) {
+ mSharedLibraryOverlayPaths = new WatchedArrayMap<>();
+ registerObserver(mSnapshot);
+ }
+ mSharedLibraryOverlayPaths.clear();
+ mSharedLibraryOverlayPaths.putAll(value);
onChanged();
return this;
}
@@ -413,14 +506,30 @@
*/
public @NonNull PackageUserStateImpl setSuspendParams(
@NonNull ArrayMap<String, SuspendParams> value) {
- mSuspendParams = value;
+ if (value == null) {
+ return this;
+ }
+ if (mSuspendParams == null) {
+ mSuspendParams = new WatchedArrayMap<>();
+ registerObserver(mSnapshot);
+ }
+ mSuspendParams.clear();
+ mSuspendParams.putAll(value);
onChanged();
return this;
}
public @NonNull PackageUserStateImpl setComponentLabelIconOverrideMap(
@NonNull ArrayMap<ComponentName, Pair<String, Integer>> value) {
- mComponentLabelIconOverrideMap = value;
+ if (value == null) {
+ return this;
+ }
+ if (mComponentLabelIconOverrideMap == null) {
+ mComponentLabelIconOverrideMap = new WatchedArrayMap<>();
+ registerObserver(mSnapshot);
+ }
+ mComponentLabelIconOverrideMap.clear();
+ mComponentLabelIconOverrideMap.putAll(value);
onChanged();
return this;
}
@@ -431,6 +540,73 @@
return this;
}
+ @Override
+ public boolean equals(@Nullable Object o) {
+ // You can override field equality logic by defining either of the methods like:
+ // boolean fieldNameEquals(PackageUserStateImpl other) { ... }
+ // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ @SuppressWarnings("unchecked")
+ PackageUserStateImpl that = (PackageUserStateImpl) o;
+ //noinspection PointlessBooleanExpression
+ return Objects.equals(mDisabledComponentsWatched, that.mDisabledComponentsWatched)
+ && Objects.equals(mEnabledComponentsWatched, that.mEnabledComponentsWatched)
+ && mCeDataInode == that.mCeDataInode
+ && mInstalled == that.mInstalled
+ && mStopped == that.mStopped
+ && mNotLaunched == that.mNotLaunched
+ && mHidden == that.mHidden
+ && mDistractionFlags == that.mDistractionFlags
+ && mInstantApp == that.mInstantApp
+ && mVirtualPreload == that.mVirtualPreload
+ && mEnabledState == that.mEnabledState
+ && mInstallReason == that.mInstallReason
+ && mUninstallReason == that.mUninstallReason
+ && Objects.equals(mHarmfulAppWarning, that.mHarmfulAppWarning)
+ && Objects.equals(mLastDisableAppCaller, that.mLastDisableAppCaller)
+ && Objects.equals(mOverlayPaths, that.mOverlayPaths)
+ && Objects.equals(mSharedLibraryOverlayPaths, that.mSharedLibraryOverlayPaths)
+ && Objects.equals(mSplashScreenTheme, that.mSplashScreenTheme)
+ && Objects.equals(mSuspendParams, that.mSuspendParams)
+ && Objects.equals(mComponentLabelIconOverrideMap,
+ that.mComponentLabelIconOverrideMap)
+ && mFirstInstallTime == that.mFirstInstallTime
+ && Objects.equals(mWatchable, that.mWatchable);
+ }
+
+ @Override
+ public int hashCode() {
+ // You can override field hashCode logic by defining methods like:
+ // int fieldNameHashCode() { ... }
+
+ int _hash = 1;
+ _hash = 31 * _hash + Objects.hashCode(mDisabledComponentsWatched);
+ _hash = 31 * _hash + Objects.hashCode(mEnabledComponentsWatched);
+ _hash = 31 * _hash + Long.hashCode(mCeDataInode);
+ _hash = 31 * _hash + Boolean.hashCode(mInstalled);
+ _hash = 31 * _hash + Boolean.hashCode(mStopped);
+ _hash = 31 * _hash + Boolean.hashCode(mNotLaunched);
+ _hash = 31 * _hash + Boolean.hashCode(mHidden);
+ _hash = 31 * _hash + mDistractionFlags;
+ _hash = 31 * _hash + Boolean.hashCode(mInstantApp);
+ _hash = 31 * _hash + Boolean.hashCode(mVirtualPreload);
+ _hash = 31 * _hash + mEnabledState;
+ _hash = 31 * _hash + mInstallReason;
+ _hash = 31 * _hash + mUninstallReason;
+ _hash = 31 * _hash + Objects.hashCode(mHarmfulAppWarning);
+ _hash = 31 * _hash + Objects.hashCode(mLastDisableAppCaller);
+ _hash = 31 * _hash + Objects.hashCode(mOverlayPaths);
+ _hash = 31 * _hash + Objects.hashCode(mSharedLibraryOverlayPaths);
+ _hash = 31 * _hash + Objects.hashCode(mSplashScreenTheme);
+ _hash = 31 * _hash + Objects.hashCode(mSuspendParams);
+ _hash = 31 * _hash + Objects.hashCode(mComponentLabelIconOverrideMap);
+ _hash = 31 * _hash + Long.hashCode(mFirstInstallTime);
+ _hash = 31 * _hash + Objects.hashCode(mWatchable);
+ return _hash;
+ }
+
// Code below generated by codegen v1.0.23.
@@ -447,13 +623,13 @@
@DataClass.Generated.Member
- public @Nullable ArraySet<String> getDisabledComponents() {
- return mDisabledComponents;
+ public @Nullable WatchedArraySet<String> getDisabledComponentsWatched() {
+ return mDisabledComponentsWatched;
}
@DataClass.Generated.Member
- public @Nullable ArraySet<String> getEnabledComponents() {
- return mEnabledComponents;
+ public @Nullable WatchedArraySet<String> getEnabledComponentsWatched() {
+ return mEnabledComponentsWatched;
}
@DataClass.Generated.Member
@@ -527,7 +703,7 @@
}
@DataClass.Generated.Member
- public @Nullable ArrayMap<String,OverlayPaths> getSharedLibraryOverlayPaths() {
+ public @Nullable WatchedArrayMap<String,OverlayPaths> getSharedLibraryOverlayPaths() {
return mSharedLibraryOverlayPaths;
}
@@ -540,12 +716,12 @@
* Suspending package to suspend params
*/
@DataClass.Generated.Member
- public @Nullable ArrayMap<String,SuspendParams> getSuspendParams() {
+ public @Nullable WatchedArrayMap<String,SuspendParams> getSuspendParams() {
return mSuspendParams;
}
@DataClass.Generated.Member
- public @Nullable ArrayMap<ComponentName,Pair<String,Integer>> getComponentLabelIconOverrideMap() {
+ public @Nullable WatchedArrayMap<ComponentName,Pair<String,Integer>> getComponentLabelIconOverrideMap() {
return mComponentLabelIconOverrideMap;
}
@@ -559,80 +735,49 @@
return mWatchable;
}
- @Override
@DataClass.Generated.Member
- public boolean equals(@Nullable Object o) {
- // You can override field equality logic by defining either of the methods like:
- // boolean fieldNameEquals(PackageUserStateImpl other) { ... }
- // boolean fieldNameEquals(FieldType otherValue) { ... }
-
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- @SuppressWarnings("unchecked")
- PackageUserStateImpl that = (PackageUserStateImpl) o;
- //noinspection PointlessBooleanExpression
- return true
- && Objects.equals(mDisabledComponents, that.mDisabledComponents)
- && Objects.equals(mEnabledComponents, that.mEnabledComponents)
- && mCeDataInode == that.mCeDataInode
- && mInstalled == that.mInstalled
- && mStopped == that.mStopped
- && mNotLaunched == that.mNotLaunched
- && mHidden == that.mHidden
- && mDistractionFlags == that.mDistractionFlags
- && mInstantApp == that.mInstantApp
- && mVirtualPreload == that.mVirtualPreload
- && mEnabledState == that.mEnabledState
- && mInstallReason == that.mInstallReason
- && mUninstallReason == that.mUninstallReason
- && Objects.equals(mHarmfulAppWarning, that.mHarmfulAppWarning)
- && Objects.equals(mLastDisableAppCaller, that.mLastDisableAppCaller)
- && Objects.equals(mOverlayPaths, that.mOverlayPaths)
- && Objects.equals(mSharedLibraryOverlayPaths, that.mSharedLibraryOverlayPaths)
- && Objects.equals(mSplashScreenTheme, that.mSplashScreenTheme)
- && Objects.equals(mSuspendParams, that.mSuspendParams)
- && Objects.equals(mComponentLabelIconOverrideMap, that.mComponentLabelIconOverrideMap)
- && mFirstInstallTime == that.mFirstInstallTime
- && Objects.equals(mWatchable, that.mWatchable);
+ public @NonNull SnapshotCache<PackageUserStateImpl> getSnapshot() {
+ return mSnapshot;
}
- @Override
@DataClass.Generated.Member
- public int hashCode() {
- // You can override field hashCode logic by defining methods like:
- // int fieldNameHashCode() { ... }
+ public @NonNull PackageUserStateImpl setDisabledComponentsWatched(@NonNull WatchedArraySet<String> value) {
+ mDisabledComponentsWatched = value;
+ return this;
+ }
- int _hash = 1;
- _hash = 31 * _hash + Objects.hashCode(mDisabledComponents);
- _hash = 31 * _hash + Objects.hashCode(mEnabledComponents);
- _hash = 31 * _hash + Long.hashCode(mCeDataInode);
- _hash = 31 * _hash + Boolean.hashCode(mInstalled);
- _hash = 31 * _hash + Boolean.hashCode(mStopped);
- _hash = 31 * _hash + Boolean.hashCode(mNotLaunched);
- _hash = 31 * _hash + Boolean.hashCode(mHidden);
- _hash = 31 * _hash + mDistractionFlags;
- _hash = 31 * _hash + Boolean.hashCode(mInstantApp);
- _hash = 31 * _hash + Boolean.hashCode(mVirtualPreload);
- _hash = 31 * _hash + mEnabledState;
- _hash = 31 * _hash + mInstallReason;
- _hash = 31 * _hash + mUninstallReason;
- _hash = 31 * _hash + Objects.hashCode(mHarmfulAppWarning);
- _hash = 31 * _hash + Objects.hashCode(mLastDisableAppCaller);
- _hash = 31 * _hash + Objects.hashCode(mOverlayPaths);
- _hash = 31 * _hash + Objects.hashCode(mSharedLibraryOverlayPaths);
- _hash = 31 * _hash + Objects.hashCode(mSplashScreenTheme);
- _hash = 31 * _hash + Objects.hashCode(mSuspendParams);
- _hash = 31 * _hash + Objects.hashCode(mComponentLabelIconOverrideMap);
- _hash = 31 * _hash + Long.hashCode(mFirstInstallTime);
- _hash = 31 * _hash + Objects.hashCode(mWatchable);
- return _hash;
+ @DataClass.Generated.Member
+ public @NonNull PackageUserStateImpl setEnabledComponentsWatched(@NonNull WatchedArraySet<String> value) {
+ mEnabledComponentsWatched = value;
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull PackageUserStateImpl setSharedLibraryOverlayPaths(@NonNull WatchedArrayMap<String,OverlayPaths> value) {
+ mSharedLibraryOverlayPaths = value;
+ return this;
+ }
+
+ /**
+ * Suspending package to suspend params
+ */
+ @DataClass.Generated.Member
+ public @NonNull PackageUserStateImpl setSuspendParams(@NonNull WatchedArrayMap<String,SuspendParams> value) {
+ mSuspendParams = value;
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull PackageUserStateImpl setComponentLabelIconOverrideMap(@NonNull WatchedArrayMap<ComponentName,Pair<String,Integer>> value) {
+ mComponentLabelIconOverrideMap = value;
+ return this;
}
@DataClass.Generated(
- time = 1643854846064L,
+ time = 1644638242940L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java",
- inputSignatures = "protected @android.annotation.Nullable android.util.ArraySet<java.lang.String> mDisabledComponents\nprotected @android.annotation.Nullable android.util.ArraySet<java.lang.String> mEnabledComponents\nprivate long mCeDataInode\nprivate boolean mInstalled\nprivate boolean mStopped\nprivate boolean mNotLaunched\nprivate boolean mHidden\nprivate int mDistractionFlags\nprivate boolean mInstantApp\nprivate boolean mVirtualPreload\nprivate int mEnabledState\nprivate @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprotected @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mOverlayPaths\nprotected @android.annotation.Nullable android.util.ArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate @android.annotation.Nullable java.lang.String mSplashScreenTheme\nprivate @android.annotation.Nullable android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams> mSuspendParams\nprivate @android.annotation.Nullable android.util.ArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>> mComponentLabelIconOverrideMap\nprivate long mFirstInstallTime\nprivate final @android.annotation.Nullable com.android.server.utils.Watchable mWatchable\nprivate void onChanged()\npublic @android.annotation.Nullable boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths)\npublic boolean setSharedLibraryOverlayPaths(java.lang.String,android.content.pm.overlay.OverlayPaths)\npublic @android.annotation.Nullable @java.lang.Override android.util.ArraySet<java.lang.String> getDisabledComponentsNoCopy()\npublic @android.annotation.Nullable @java.lang.Override android.util.ArraySet<java.lang.String> getEnabledComponentsNoCopy()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer)\npublic void resetOverrideComponentLabelIcon()\npublic @android.annotation.Nullable android.util.Pair<java.lang.String,java.lang.Integer> getOverrideLabelIconForComponent(android.content.ComponentName)\npublic @java.lang.Override boolean isSuspended()\npublic com.android.server.pm.pkg.PackageUserStateImpl putSuspendParams(java.lang.String,com.android.server.pm.pkg.SuspendParams)\npublic com.android.server.pm.pkg.PackageUserStateImpl removeSuspension(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setCeDataInode(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstalled(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setStopped(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setNotLaunched(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHidden(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDistractionFlags(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstantApp(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setVirtualPreload(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setUninstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHarmfulAppWarning(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setLastDisableAppCaller(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSharedLibraryOverlayPaths(android.util.ArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSplashScreenTheme(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSuspendParams(android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setComponentLabelIconOverrideMap(android.util.ArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setFirstInstallTime(long)\nclass PackageUserStateImpl extends java.lang.Object implements [com.android.server.pm.pkg.PackageUserStateInternal]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false, genEqualsHashCode=true)")
+ inputSignatures = "protected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mDisabledComponentsWatched\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mEnabledComponentsWatched\nprivate long mCeDataInode\nprivate boolean mInstalled\nprivate boolean mStopped\nprivate boolean mNotLaunched\nprivate boolean mHidden\nprivate int mDistractionFlags\nprivate boolean mInstantApp\nprivate boolean mVirtualPreload\nprivate int mEnabledState\nprivate @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprivate @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mOverlayPaths\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate @android.annotation.Nullable java.lang.String mSplashScreenTheme\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams> mSuspendParams\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>> mComponentLabelIconOverrideMap\nprivate long mFirstInstallTime\nprivate final @android.annotation.Nullable com.android.server.utils.Watchable mWatchable\nfinal @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> mSnapshot\nprivate com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> makeCache()\nprivate void onChanged()\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserStateImpl snapshot()\npublic @android.annotation.Nullable boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths)\npublic boolean setSharedLibraryOverlayPaths(java.lang.String,android.content.pm.overlay.OverlayPaths)\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getDisabledComponentsNoCopy()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getEnabledComponentsNoCopy()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getDisabledComponents()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getEnabledComponents()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer)\npublic void resetOverrideComponentLabelIcon()\npublic @android.annotation.Nullable android.util.Pair<java.lang.String,java.lang.Integer> getOverrideLabelIconForComponent(android.content.ComponentName)\npublic @java.lang.Override boolean isSuspended()\npublic com.android.server.pm.pkg.PackageUserStateImpl putSuspendParams(java.lang.String,com.android.server.pm.pkg.SuspendParams)\npublic com.android.server.pm.pkg.PackageUserStateImpl removeSuspension(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setCeDataInode(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstalled(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setStopped(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setNotLaunched(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHidden(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDistractionFlags(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstantApp(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setVirtualPreload(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setUninstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHarmfulAppWarning(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setLastDisableAppCaller(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSharedLibraryOverlayPaths(android.util.ArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSplashScreenTheme(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSuspendParams(android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setComponentLabelIconOverrideMap(android.util.ArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setFirstInstallTime(long)\npublic @java.lang.Override boolean equals(java.lang.Object)\npublic @java.lang.Override int hashCode()\nclass PackageUserStateImpl extends com.android.server.utils.WatchableImpl implements [com.android.server.pm.pkg.PackageUserStateInternal, com.android.server.utils.Snappable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false, genEqualsHashCode=true)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java
index bc521ce..96225c0 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java
@@ -20,10 +20,11 @@
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.pm.pkg.FrameworkPackageUserState;
-import android.util.ArrayMap;
-import android.util.ArraySet;
import android.util.Pair;
+import com.android.server.utils.WatchedArrayMap;
+import com.android.server.utils.WatchedArraySet;
+
/**
* Internal variant of {@link PackageUserState} that includes data not exposed as API. This is
* still read-only and should be used inside system server code when possible over the
@@ -35,13 +36,13 @@
// TODO: Make non-null with emptyMap()
@Nullable
- ArrayMap<String, SuspendParams> getSuspendParams();
+ WatchedArrayMap<String, SuspendParams> getSuspendParams();
@Nullable
- ArraySet<String> getDisabledComponentsNoCopy();
+ WatchedArraySet<String> getDisabledComponentsNoCopy();
@Nullable
- ArraySet<String> getEnabledComponentsNoCopy();
+ WatchedArraySet<String> getEnabledComponentsNoCopy();
@Nullable
Pair<String, Integer> getOverrideLabelIconForComponent(@NonNull ComponentName componentName);
diff --git a/services/core/java/com/android/server/pm/pkg/SharedUserApi.java b/services/core/java/com/android/server/pm/pkg/SharedUserApi.java
index 43eac53..94a87f3 100644
--- a/services/core/java/com/android/server/pm/pkg/SharedUserApi.java
+++ b/services/core/java/com/android/server/pm/pkg/SharedUserApi.java
@@ -23,6 +23,7 @@
import android.util.ArraySet;
import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.permission.LegacyPermissionState;
import com.android.server.pm.pkg.component.ParsedProcess;
import java.util.List;
@@ -33,7 +34,7 @@
String getName();
@UserIdInt
- int getUserId();
+ int getAppId();
// flags that are associated with this uid, regardless of any package flags
int getUidFlags();
@@ -65,4 +66,7 @@
ArrayMap<String, ParsedProcess> getProcesses();
boolean isPrivileged();
+
+ @NonNull
+ LegacyPermissionState getSharedUserLegacyPermissionState();
}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedActivity.java b/services/core/java/com/android/server/pm/pkg/component/ParsedActivity.java
index c2b3cbc..0320818 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedActivity.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedActivity.java
@@ -20,6 +20,8 @@
import android.annotation.Nullable;
import android.content.pm.ActivityInfo;
+import java.util.Set;
+
/** @hide **/
//@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
public interface ParsedActivity extends ParsedMainComponent {
@@ -59,6 +61,12 @@
@Nullable
String getPermission();
+ /**
+ * Gets the trusted host certificates of apps that are allowed to embed this activity.
+ */
+ @NonNull
+ Set<String> getKnownActivityEmbeddingCerts();
+
int getPersistableMode();
int getPrivateFlags();
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java
index 91c0b07..acd5a81 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java
@@ -23,6 +23,7 @@
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
import static com.android.server.pm.pkg.parsing.ParsingPackageImpl.sForInternedString;
+import static com.android.server.pm.pkg.parsing.ParsingPackageImpl.sForStringSet;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -33,12 +34,17 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import android.util.ArraySet;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
import com.android.server.pm.pkg.parsing.ParsingUtils;
+import java.util.Collections;
+import java.util.Locale;
+import java.util.Set;
+
/**
* @hide
**/
@@ -63,6 +69,8 @@
@Nullable
@DataClass.ParcelWith(ForInternedString.class)
private String permission;
+ @Nullable
+ private Set<String> mKnownActivityEmbeddingCerts;
private int launchMode;
private int documentLaunchMode;
@@ -113,6 +121,7 @@
this.rotationAnimation = other.rotationAnimation;
this.colorMode = other.colorMode;
this.windowLayout = other.windowLayout;
+ this.mKnownActivityEmbeddingCerts = other.mKnownActivityEmbeddingCerts;
}
/**
@@ -239,6 +248,25 @@
return this;
}
+ @NonNull
+ @Override
+ public Set<String> getKnownActivityEmbeddingCerts() {
+ return mKnownActivityEmbeddingCerts == null ? Collections.emptySet()
+ : mKnownActivityEmbeddingCerts;
+ }
+
+ /**
+ * Sets the trusted host certificates of apps that are allowed to embed this activity.
+ */
+ public void setKnownActivityEmbeddingCerts(@NonNull Set<String> knownActivityEmbeddingCerts) {
+ // Convert the provided digest to upper case for consistent Set membership
+ // checks when verifying the signing certificate digests of requesting apps.
+ this.mKnownActivityEmbeddingCerts = new ArraySet<>();
+ for (String knownCert : knownActivityEmbeddingCerts) {
+ this.mKnownActivityEmbeddingCerts.add(knownCert.toUpperCase(Locale.US));
+ }
+ }
+
public String toString() {
StringBuilder sb = new StringBuilder(128);
sb.append("Activity{");
@@ -287,6 +315,7 @@
} else {
dest.writeBoolean(false);
}
+ sForStringSet.parcel(this.mKnownActivityEmbeddingCerts, dest, flags);
}
public ParsedActivityImpl() {
@@ -320,6 +349,7 @@
if (in.readBoolean()) {
windowLayout = new ActivityInfo.WindowLayout(in);
}
+ this.mKnownActivityEmbeddingCerts = sForStringSet.unparcel(in);
}
@NonNull
@@ -344,7 +374,7 @@
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedActivityImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -360,6 +390,7 @@
@Nullable String taskAffinity,
int privateFlags,
@Nullable String permission,
+ @Nullable Set<String> knownActivityEmbeddingCerts,
int launchMode,
int documentLaunchMode,
int maxRecents,
@@ -383,6 +414,7 @@
this.taskAffinity = taskAffinity;
this.privateFlags = privateFlags;
this.permission = permission;
+ this.mKnownActivityEmbeddingCerts = knownActivityEmbeddingCerts;
this.launchMode = launchMode;
this.documentLaunchMode = documentLaunchMode;
this.maxRecents = maxRecents;
@@ -645,10 +677,10 @@
}
@DataClass.Generated(
- time = 1641431949361L,
+ time = 1644372875433L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedActivityImpl.java",
- inputSignatures = "private int theme\nprivate int uiOptions\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetActivity\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String parentActivityName\nprivate @android.annotation.Nullable java.lang.String taskAffinity\nprivate int privateFlags\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String permission\nprivate int launchMode\nprivate int documentLaunchMode\nprivate int maxRecents\nprivate int configChanges\nprivate int softInputMode\nprivate int persistableMode\nprivate int lockTaskLaunchMode\nprivate int screenOrientation\nprivate int resizeMode\nprivate float maxAspectRatio\nprivate float minAspectRatio\nprivate boolean supportsSizeChanges\nprivate @android.annotation.Nullable java.lang.String requestedVrComponent\nprivate int rotationAnimation\nprivate int colorMode\nprivate @android.annotation.Nullable android.content.pm.ActivityInfo.WindowLayout windowLayout\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<android.content.pm.parsing.component.ParsedActivityImpl> CREATOR\nstatic @android.annotation.NonNull android.content.pm.parsing.component.ParsedActivityImpl makeAppDetailsActivity(java.lang.String,java.lang.String,int,java.lang.String,boolean)\nstatic @android.annotation.NonNull android.content.pm.parsing.component.ParsedActivityImpl makeAlias(java.lang.String,android.content.pm.parsing.component.ParsedActivity)\npublic android.content.pm.parsing.component.ParsedActivityImpl setMaxAspectRatio(int,float)\npublic android.content.pm.parsing.component.ParsedActivityImpl setMinAspectRatio(int,float)\npublic android.content.pm.parsing.component.ParsedActivityImpl setTargetActivity(java.lang.String)\npublic android.content.pm.parsing.component.ParsedActivityImpl setPermission(java.lang.String)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedActivityImpl extends android.content.pm.parsing.component.ParsedMainComponentImpl implements [android.content.pm.parsing.component.ParsedActivity, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
+ sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java",
+ inputSignatures = "private int theme\nprivate int uiOptions\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetActivity\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String parentActivityName\nprivate @android.annotation.Nullable java.lang.String taskAffinity\nprivate int privateFlags\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String permission\nprivate @android.annotation.Nullable java.util.Set<java.lang.String> mKnownActivityEmbeddingCerts\nprivate int launchMode\nprivate int documentLaunchMode\nprivate int maxRecents\nprivate int configChanges\nprivate int softInputMode\nprivate int persistableMode\nprivate int lockTaskLaunchMode\nprivate int screenOrientation\nprivate int resizeMode\nprivate float maxAspectRatio\nprivate float minAspectRatio\nprivate boolean supportsSizeChanges\nprivate @android.annotation.Nullable java.lang.String requestedVrComponent\nprivate int rotationAnimation\nprivate int colorMode\nprivate @android.annotation.Nullable android.content.pm.ActivityInfo.WindowLayout windowLayout\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<com.android.server.pm.pkg.component.ParsedActivityImpl> CREATOR\nstatic @android.annotation.NonNull com.android.server.pm.pkg.component.ParsedActivityImpl makeAppDetailsActivity(java.lang.String,java.lang.String,int,java.lang.String,boolean)\nstatic @android.annotation.NonNull com.android.server.pm.pkg.component.ParsedActivityImpl makeAlias(java.lang.String,com.android.server.pm.pkg.component.ParsedActivity)\npublic com.android.server.pm.pkg.component.ParsedActivityImpl setMaxAspectRatio(int,float)\npublic com.android.server.pm.pkg.component.ParsedActivityImpl setMinAspectRatio(int,float)\npublic com.android.server.pm.pkg.component.ParsedActivityImpl setTargetActivity(java.lang.String)\npublic com.android.server.pm.pkg.component.ParsedActivityImpl setPermission(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override java.util.Set<java.lang.String> getKnownActivityEmbeddingCerts()\npublic void setKnownActivityEmbeddingCerts(java.util.Set<java.lang.String>)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedActivityImpl extends com.android.server.pm.pkg.component.ParsedMainComponentImpl implements [com.android.server.pm.pkg.component.ParsedActivity, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java
index a6c22a18..bbbf598 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java
@@ -21,6 +21,7 @@
import static com.android.server.pm.pkg.component.ComponentParseUtils.flag;
import static com.android.server.pm.pkg.parsing.ParsingUtils.NOT_SET;
+import static com.android.server.pm.pkg.parsing.ParsingUtils.parseKnownActivityEmbeddingCerts;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -151,7 +152,8 @@
| flag(ActivityInfo.FLAG_SHOW_WHEN_LOCKED, R.styleable.AndroidManifestActivity_showWhenLocked, sa)
| flag(ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE, R.styleable.AndroidManifestActivity_supportsPictureInPicture, sa)
| flag(ActivityInfo.FLAG_TURN_SCREEN_ON, R.styleable.AndroidManifestActivity_turnScreenOn, sa)
- | flag(ActivityInfo.FLAG_PREFER_MINIMAL_POST_PROCESSING, R.styleable.AndroidManifestActivity_preferMinimalPostProcessing, sa)));
+ | flag(ActivityInfo.FLAG_PREFER_MINIMAL_POST_PROCESSING, R.styleable.AndroidManifestActivity_preferMinimalPostProcessing, sa))
+ | flag(ActivityInfo.FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING, R.styleable.AndroidManifestActivity_allowUntrustedActivityEmbedding, sa));
activity.setPrivateFlags(activity.getPrivateFlags() | (flag(ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED,
R.styleable.AndroidManifestActivity_inheritShowWhenLocked, sa)
@@ -338,6 +340,20 @@
activity.setPermission(permission != null ? permission : pkg.getPermission());
}
+ final ParseResult<Set<String>> knownActivityEmbeddingCertsResult =
+ parseKnownActivityEmbeddingCerts(array, resources, isAlias
+ ? R.styleable.AndroidManifestActivityAlias_knownActivityEmbeddingCerts
+ : R.styleable.AndroidManifestActivity_knownActivityEmbeddingCerts, input);
+ if (knownActivityEmbeddingCertsResult.isError()) {
+ return input.error(knownActivityEmbeddingCertsResult);
+ } else {
+ final Set<String> knownActivityEmbeddingCerts = knownActivityEmbeddingCertsResult
+ .getResult();
+ if (knownActivityEmbeddingCerts != null) {
+ activity.setKnownActivityEmbeddingCerts(knownActivityEmbeddingCerts);
+ }
+ }
+
final boolean setExported = array.hasValue(exportedAttr);
if (setExported) {
activity.setExported(array.getBoolean(exportedAttr, false));
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/PackageInfoWithoutStateUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/PackageInfoWithoutStateUtils.java
index b92b845..f199841 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/PackageInfoWithoutStateUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/PackageInfoWithoutStateUtils.java
@@ -549,6 +549,7 @@
ai.metaData = a.getMetaData();
}
ai.applicationInfo = applicationInfo;
+ ai.setKnownActivityEmbeddingCerts(a.getKnownActivityEmbeddingCerts());
return ai;
}
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
index 52d9b7a..1754877 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
@@ -381,6 +381,12 @@
ParsingPackage setLocaleConfigRes(int localeConfigRes);
+ /**
+ * Sets the trusted host certificates of apps that are allowed to embed activities of this
+ * application.
+ */
+ ParsingPackage setKnownActivityEmbeddingCerts(Set<String> knownActivityEmbeddingCerts);
+
// TODO(b/135203078): This class no longer has access to ParsedPackage, find a replacement
// for moving to the next step
@CallSuper
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
index 84422cd..c4b1275 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
@@ -563,6 +563,9 @@
return (mBooleans & flag) != 0;
}
+ @Nullable
+ private Set<String> mKnownActivityEmbeddingCerts;
+
// Derived fields
@NonNull
private UUID mStorageUuid;
@@ -1150,6 +1153,9 @@
appInfo.setVersionCode(mLongVersionCode);
appInfo.setAppClassNamesByProcess(buildAppClassNamesByProcess());
appInfo.setLocaleConfigRes(mLocaleConfigRes);
+ if (mKnownActivityEmbeddingCerts != null) {
+ appInfo.setKnownActivityEmbeddingCerts(mKnownActivityEmbeddingCerts);
+ }
return appInfo;
}
@@ -1329,6 +1335,7 @@
dest.writeInt(this.nativeHeapZeroInitialized);
sForBoolean.parcel(this.requestRawExternalStorageAccess, dest, flags);
dest.writeInt(this.mLocaleConfigRes);
+ sForStringSet.parcel(mKnownActivityEmbeddingCerts, dest, flags);
}
public ParsingPackageImpl(Parcel in) {
@@ -1477,6 +1484,7 @@
this.nativeHeapZeroInitialized = in.readInt();
this.requestRawExternalStorageAccess = sForBoolean.unparcel(in);
this.mLocaleConfigRes = in.readInt();
+ this.mKnownActivityEmbeddingCerts = sForStringSet.unparcel(in);
assignDerivedFields();
}
@@ -2376,6 +2384,13 @@
return getBoolean(Booleans.RESET_ENABLED_SETTINGS_ON_APP_DATA_CLEARED);
}
+ @NonNull
+ @Override
+ public Set<String> getKnownActivityEmbeddingCerts() {
+ return mKnownActivityEmbeddingCerts == null ? Collections.emptySet()
+ : mKnownActivityEmbeddingCerts;
+ }
+
@Override
public boolean shouldInheritKeyStoreKeys() {
return getBoolean(Booleans.INHERIT_KEYSTORE_KEYS);
@@ -2973,4 +2988,11 @@
mLocaleConfigRes = value;
return this;
}
+
+ @Override
+ public ParsingPackage setKnownActivityEmbeddingCerts(
+ @Nullable Set<String> knownEmbeddingCerts) {
+ mKnownActivityEmbeddingCerts = knownEmbeddingCerts;
+ return this;
+ }
}
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index e8f03ff..a891980 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -30,6 +30,8 @@
import static android.os.Build.VERSION_CODES.O;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+import static com.android.server.pm.pkg.parsing.ParsingUtils.parseKnownActivityEmbeddingCerts;
+
import android.annotation.AnyRes;
import android.annotation.CheckResult;
import android.annotation.IntDef;
@@ -2009,6 +2011,19 @@
.AndroidManifestApplication_requestForegroundServiceExemption,
false));
}
+ final ParseResult<Set<String>> knownActivityEmbeddingCertsResult =
+ parseKnownActivityEmbeddingCerts(sa, res,
+ R.styleable.AndroidManifestApplication_knownActivityEmbeddingCerts,
+ input);
+ if (knownActivityEmbeddingCertsResult.isError()) {
+ return input.error(knownActivityEmbeddingCertsResult);
+ } else {
+ final Set<String> knownActivityEmbeddingCerts = knownActivityEmbeddingCertsResult
+ .getResult();
+ if (knownActivityEmbeddingCerts != null) {
+ pkg.setKnownActivityEmbeddingCerts(knownActivityEmbeddingCerts);
+ }
+ }
} finally {
sa.recycle();
}
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java
index 9430e98..cb474df 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java
@@ -22,6 +22,8 @@
import android.annotation.Nullable;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseResult;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.os.Parcel;
import android.os.Parcelable;
@@ -38,6 +40,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
/** @hide **/
public class ParsingUtils {
@@ -168,4 +171,50 @@
return list;
}
}
+
+ /**
+ * Parse the {@link android.R.attr#knownActivityEmbeddingCerts} attribute, if available.
+ */
+ @NonNull
+ public static ParseResult<Set<String>> parseKnownActivityEmbeddingCerts(@NonNull TypedArray sa,
+ @NonNull Resources res, int resourceId, @NonNull ParseInput input) {
+ if (!sa.hasValue(resourceId)) {
+ return input.success(null);
+ }
+
+ final int knownActivityEmbeddingCertsResource = sa.getResourceId(resourceId, 0);
+ if (knownActivityEmbeddingCertsResource != 0) {
+ // The knownCerts attribute supports both a string array resource as well as a
+ // string resource for the case where the permission should only be granted to a
+ // single known signer.
+ Set<String> knownEmbeddingCertificates = null;
+ final String resourceType = res.getResourceTypeName(
+ knownActivityEmbeddingCertsResource);
+ if (resourceType.equals("array")) {
+ final String[] knownCerts = res.getStringArray(knownActivityEmbeddingCertsResource);
+ if (knownCerts != null) {
+ knownEmbeddingCertificates = Set.of(knownCerts);
+ }
+ } else {
+ final String knownCert = res.getString(knownActivityEmbeddingCertsResource);
+ if (knownCert != null) {
+ knownEmbeddingCertificates = Set.of(knownCert);
+ }
+ }
+ if (knownEmbeddingCertificates == null || knownEmbeddingCertificates.isEmpty()) {
+ return input.error("Defined a knownActivityEmbeddingCerts attribute but the "
+ + "provided resource is null");
+ }
+ return input.success(knownEmbeddingCertificates);
+ }
+
+ // If the knownCerts resource ID is null - the app specified a string value for the
+ // attribute representing a single trusted signer.
+ final String knownCert = sa.getString(resourceId);
+ if (knownCert == null || knownCert.isEmpty()) {
+ return input.error("Defined a knownActivityEmbeddingCerts attribute but the provided "
+ + "string is empty");
+ }
+ return input.success(Set.of(knownCert));
+ }
}
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/PkgWithoutStateAppInfo.java b/services/core/java/com/android/server/pm/pkg/parsing/PkgWithoutStateAppInfo.java
index 2ef90ac..3205b76 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/PkgWithoutStateAppInfo.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/PkgWithoutStateAppInfo.java
@@ -21,6 +21,8 @@
import android.content.pm.ApplicationInfo;
import android.util.SparseArray;
+import java.util.Set;
+
/**
* Container for fields that are eventually exposed through {@link ApplicationInfo}.
* <p>
@@ -285,6 +287,13 @@
String getPermission();
/**
+ * @see ApplicationInfo#knownActivityEmbeddingCerts
+ * @see R.styleable#AndroidManifestApplication_knownActivityEmbeddingCerts
+ */
+ @NonNull
+ Set<String> getKnownActivityEmbeddingCerts();
+
+ /**
* @see ApplicationInfo#processName
* @see R.styleable#AndroidManifestApplication_process
*/
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index c9a8701..c637c67 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -37,7 +37,7 @@
import android.app.TaskInfo;
import android.app.compat.CompatChanges;
import android.compat.annotation.ChangeId;
-import android.compat.annotation.EnabledSince;
+import android.compat.annotation.EnabledAfter;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -58,6 +58,7 @@
import android.os.ServiceManager;
import android.os.UserHandle;
import android.permission.PermissionControllerManager;
+import android.permission.PermissionManager;
import android.provider.Settings;
import android.provider.Telephony;
import android.telecom.TelecomManager;
@@ -141,7 +142,7 @@
* This change reflects the presence of the new Notification Permission
*/
@ChangeId
- @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2)
private static final long NOTIFICATION_PERM_CHANGE_ID = 194833441L;
private List<String> mAppOpPermissions;
@@ -149,7 +150,6 @@
private Context mContext;
private PackageManagerInternal mPackageManagerInternal;
private NotificationManagerInternal mNotificationManager;
- private PermissionManagerServiceInternal mPermissionManagerService;
private final PackageManager mPackageManager;
public PermissionPolicyService(@NonNull Context context) {
@@ -1001,13 +1001,48 @@
private class Internal extends PermissionPolicyInternal {
- private ActivityInterceptorCallback mActivityInterceptorCallback =
+ // UIDs that, if a grant dialog is shown for POST_NOTIFICATIONS before next reboot,
+ // should display a "continue allowing" message, rather than an "allow" message
+ private final ArraySet<Integer> mContinueNotifGrantMessageUids = new ArraySet<>();
+
+ private final ActivityInterceptorCallback mActivityInterceptorCallback =
new ActivityInterceptorCallback() {
@Nullable
@Override
public ActivityInterceptorCallback.ActivityInterceptResult intercept(
ActivityInterceptorInfo info) {
- return null;
+ String action = info.intent.getAction();
+ ActivityInterceptResult result = null;
+ if (!PackageManager.ACTION_REQUEST_PERMISSIONS_FOR_OTHER.equals(action)
+ && !PackageManager.ACTION_REQUEST_PERMISSIONS.equals(action)) {
+ return null;
+ }
+ // Only this interceptor can add LEGACY_ACCESS_PERMISSION_NAMES
+ if (info.intent.getStringArrayExtra(PackageManager
+ .EXTRA_REQUEST_PERMISSIONS_LEGACY_ACCESS_PERMISSION_NAMES)
+ != null) {
+ result = new ActivityInterceptResult(
+ new Intent(info.intent), info.checkedOptions);
+ result.intent.removeExtra(PackageManager
+ .EXTRA_REQUEST_PERMISSIONS_LEGACY_ACCESS_PERMISSION_NAMES);
+ }
+ if (PackageManager.ACTION_REQUEST_PERMISSIONS.equals(action)
+ && !mContinueNotifGrantMessageUids.contains(info.realCallingUid)) {
+ return result;
+ }
+ if (PackageManager.ACTION_REQUEST_PERMISSIONS_FOR_OTHER.equals(action)) {
+ String otherPkg = info.intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
+ if (otherPkg == null || (mPackageManager.getPermissionFlags(
+ POST_NOTIFICATIONS, otherPkg, UserHandle.of(info.userId))
+ & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
+ return result;
+ }
+ }
+
+ mContinueNotifGrantMessageUids.remove(info.realCallingUid);
+ return new ActivityInterceptResult(info.intent.putExtra(PackageManager
+ .EXTRA_REQUEST_PERMISSIONS_LEGACY_ACCESS_PERMISSION_NAMES,
+ new String[] { POST_NOTIFICATIONS }), info.checkedOptions);
}
@Override
@@ -1057,12 +1092,21 @@
launchNotificationPermissionRequestDialog(packageName, user, taskId);
}
- private void clearNotificationReviewFlagsIfNeeded(String packageName, UserHandle userId) {
- if (!CompatChanges.isChangeEnabled(NOTIFICATION_PERM_CHANGE_ID, packageName, userId)) {
+ private void clearNotificationReviewFlagsIfNeeded(String packageName, UserHandle user) {
+ if (!CompatChanges.isChangeEnabled(NOTIFICATION_PERM_CHANGE_ID, packageName, user)
+ || ((mPackageManager.getPermissionFlags(POST_NOTIFICATIONS, packageName, user)
+ & FLAG_PERMISSION_REVIEW_REQUIRED) == 0)) {
return;
}
- mPackageManager.updatePermissionFlags(POST_NOTIFICATIONS, packageName,
- FLAG_PERMISSION_REVIEW_REQUIRED, 0, userId);
+ try {
+ int uid = mPackageManager.getPackageUidAsUser(packageName, 0,
+ user.getIdentifier());
+ mContinueNotifGrantMessageUids.add(uid);
+ mPackageManager.updatePermissionFlags(POST_NOTIFICATIONS, packageName,
+ FLAG_PERMISSION_REVIEW_REQUIRED, 0, user);
+ } catch (PackageManager.NameNotFoundException e) {
+ // Do nothing
+ }
}
private void launchNotificationPermissionRequestDialog(String pkgName, UserHandle user,
@@ -1142,8 +1186,10 @@
if (pkg == null || pkg.getPackageName() == null
|| Objects.equals(pkgName, mPackageManager.getPermissionControllerPackageName())
|| pkg.getTargetSdkVersion() < Build.VERSION_CODES.M) {
- Slog.w(LOG_TAG, "Cannot check for Notification prompt, no package for "
- + pkgName + " or pkg is Permission Controller");
+ if (pkg == null) {
+ Slog.w(LOG_TAG, "Cannot check for Notification prompt, no package for "
+ + pkgName);
+ }
return false;
}
@@ -1175,9 +1221,10 @@
}
boolean hasCreatedNotificationChannels = mNotificationManager
.getNumNotificationChannelsForPackage(pkg.getPackageName(), uid, true) > 0;
- boolean needsReview = (mPackageManager.getPermissionFlags(POST_NOTIFICATIONS, pkgName,
- user) & FLAG_PERMISSION_REVIEW_REQUIRED) != 0;
- return hasCreatedNotificationChannels && needsReview;
+ int flags = mPackageManager.getPermissionFlags(POST_NOTIFICATIONS, pkgName, user);
+ boolean explicitlySet = (flags & PermissionManager.EXPLICIT_SET_FLAGS) != 0;
+ boolean needsReview = (flags & FLAG_PERMISSION_REVIEW_REQUIRED) != 0;
+ return hasCreatedNotificationChannels && (needsReview || !explicitlySet);
}
}
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 7e36290..4b61970 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -298,6 +298,7 @@
// must match: config_doubleTapOnHomeBehavior in config.xml
static final int DOUBLE_TAP_HOME_NOTHING = 0;
static final int DOUBLE_TAP_HOME_RECENT_SYSTEM_UI = 1;
+ static final int DOUBLE_TAP_HOME_PIP_MENU = 2;
static final int SHORT_PRESS_WINDOW_NOTHING = 0;
static final int SHORT_PRESS_WINDOW_PICTURE_IN_PICTURE = 1;
@@ -635,6 +636,7 @@
private static final int MSG_HIDE_BOOT_MESSAGE = 11;
private static final int MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK = 12;
private static final int MSG_SHOW_PICTURE_IN_PICTURE_MENU = 15;
+ private static final int MSG_SCREENSHOT_CHORD = 16;
private static final int MSG_ACCESSIBILITY_SHORTCUT = 17;
private static final int MSG_BUGREPORT_TV = 18;
private static final int MSG_ACCESSIBILITY_TV = 19;
@@ -710,6 +712,9 @@
case MSG_RINGER_TOGGLE_CHORD:
handleRingerChordGesture();
break;
+ case MSG_SCREENSHOT_CHORD:
+ handleScreenShot(msg.arg1, msg.arg2);
+ break;
}
}
}
@@ -1465,11 +1470,10 @@
|| mShortPressOnStemPrimaryBehavior != SHORT_PRESS_PRIMARY_NOTHING;
}
- private void interceptScreenshotChord() {
- mHandler.removeCallbacks(mScreenshotRunnable);
- mScreenshotRunnable.setScreenshotType(TAKE_SCREENSHOT_FULLSCREEN);
- mScreenshotRunnable.setScreenshotSource(SCREENSHOT_KEY_CHORD);
- mHandler.postDelayed(mScreenshotRunnable, getScreenshotChordLongPressDelay());
+ private void interceptScreenshotChord(int type, int source, long pressDelay) {
+ mHandler.removeMessages(MSG_SCREENSHOT_CHORD);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SCREENSHOT_CHORD, type, source),
+ pressDelay);
}
private void interceptAccessibilityShortcutChord() {
@@ -1509,7 +1513,7 @@
}
private void cancelPendingScreenshotChordAction() {
- mHandler.removeCallbacks(mScreenshotRunnable);
+ mHandler.removeMessages(MSG_SCREENSHOT_CHORD);
}
private void cancelPendingAccessibilityShortcutAction() {
@@ -1530,26 +1534,11 @@
}
};
- private class ScreenshotRunnable implements Runnable {
- private int mScreenshotType = TAKE_SCREENSHOT_FULLSCREEN;
- private int mScreenshotSource = SCREENSHOT_KEY_OTHER;
-
- public void setScreenshotType(int screenshotType) {
- mScreenshotType = screenshotType;
- }
-
- public void setScreenshotSource(int screenshotSource) {
- mScreenshotSource = screenshotSource;
- }
-
- @Override
- public void run() {
- mDefaultDisplayPolicy.takeScreenshot(mScreenshotType, mScreenshotSource);
- }
+ private void handleScreenShot(@WindowManager.ScreenshotType int type,
+ @WindowManager.ScreenshotSource int source) {
+ mDefaultDisplayPolicy.takeScreenshot(type, source);
}
- private final ScreenshotRunnable mScreenshotRunnable = new ScreenshotRunnable();
-
@Override
public void showGlobalActions() {
mHandler.removeMessages(MSG_DISPATCH_SHOW_GLOBAL_ACTIONS);
@@ -1755,11 +1744,15 @@
// Delay handling home if a double-tap is possible.
if (mDoubleTapOnHomeBehavior != DOUBLE_TAP_HOME_NOTHING) {
- mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable); // just in case
- mHomeDoubleTapPending = true;
- mHandler.postDelayed(mHomeDoubleTapTimeoutRunnable,
- ViewConfiguration.getDoubleTapTimeout());
- return -1;
+ // For the picture-in-picture menu, only add the delay if a pip is there.
+ if (mDoubleTapOnHomeBehavior != DOUBLE_TAP_HOME_PIP_MENU
+ || mPictureInPictureVisible) {
+ mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable); // just in case
+ mHomeDoubleTapPending = true;
+ mHandler.postDelayed(mHomeDoubleTapTimeoutRunnable,
+ ViewConfiguration.getDoubleTapTimeout());
+ return -1;
+ }
}
// Post to main thread to avoid blocking input pipeline.
@@ -1792,7 +1785,7 @@
if (mHomeDoubleTapPending) {
mHomeDoubleTapPending = false;
mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable);
- handleDoubleTapOnHome();
+ mHandler.post(this::handleDoubleTapOnHome);
// TODO(multi-display): Remove display id check once we support recents on
// multi-display
} else if (mDoubleTapOnHomeBehavior == DOUBLE_TAP_HOME_RECENT_SYSTEM_UI
@@ -1810,13 +1803,29 @@
}
private void handleDoubleTapOnHome() {
- if (mDoubleTapOnHomeBehavior == DOUBLE_TAP_HOME_RECENT_SYSTEM_UI) {
- mHomeConsumed = true;
- toggleRecentApps();
+ if (mHomeConsumed) {
+ return;
+ }
+ switch (mDoubleTapOnHomeBehavior) {
+ case DOUBLE_TAP_HOME_RECENT_SYSTEM_UI:
+ mHomeConsumed = true;
+ toggleRecentApps();
+ break;
+ case DOUBLE_TAP_HOME_PIP_MENU:
+ mHomeConsumed = true;
+ showPictureInPictureMenuInternal();
+ break;
+ default:
+ Log.w(TAG, "No action or undefined behavior for double tap home: "
+ + mDoubleTapOnHomeBehavior);
+ break;
}
}
private void handleLongPressOnHome(int deviceId, long eventTime) {
+ if (mHomeConsumed) {
+ return;
+ }
if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_NOTHING) {
return;
}
@@ -2124,7 +2133,8 @@
@Override
void execute() {
mPowerKeyHandled = true;
- interceptScreenshotChord();
+ interceptScreenshotChord(TAKE_SCREENSHOT_FULLSCREEN,
+ SCREENSHOT_KEY_CHORD, getScreenshotChordLongPressDelay());
}
@Override
void cancel() {
@@ -2232,7 +2242,7 @@
*/
private final class PowerKeyRule extends SingleKeyGestureDetector.SingleKeyRule {
PowerKeyRule(int gestures) {
- super(mContext, KEYCODE_POWER, gestures);
+ super(KEYCODE_POWER, gestures);
}
@Override
@@ -2283,7 +2293,7 @@
*/
private final class BackKeyRule extends SingleKeyGestureDetector.SingleKeyRule {
BackKeyRule(int gestures) {
- super(mContext, KEYCODE_BACK, gestures);
+ super(KEYCODE_BACK, gestures);
}
@Override
@@ -2307,7 +2317,7 @@
*/
private final class StemPrimaryKeyRule extends SingleKeyGestureDetector.SingleKeyRule {
StemPrimaryKeyRule(int gestures) {
- super(mContext, KeyEvent.KEYCODE_STEM_PRIMARY, gestures);
+ super(KeyEvent.KEYCODE_STEM_PRIMARY, gestures);
}
@Override
@@ -2332,7 +2342,7 @@
}
private void initSingleKeyGestureRules() {
- mSingleKeyGestureDetector = new SingleKeyGestureDetector();
+ mSingleKeyGestureDetector = SingleKeyGestureDetector.get(mContext);
int powerKeyGestures = 0;
if (hasVeryLongPressOnPowerBehavior()) {
@@ -2373,8 +2383,8 @@
mDoubleTapOnHomeBehavior = res.getInteger(
com.android.internal.R.integer.config_doubleTapOnHomeBehavior);
if (mDoubleTapOnHomeBehavior < DOUBLE_TAP_HOME_NOTHING ||
- mDoubleTapOnHomeBehavior > DOUBLE_TAP_HOME_RECENT_SYSTEM_UI) {
- mDoubleTapOnHomeBehavior = LONG_PRESS_HOME_NOTHING;
+ mDoubleTapOnHomeBehavior > DOUBLE_TAP_HOME_PIP_MENU) {
+ mDoubleTapOnHomeBehavior = DOUBLE_TAP_HOME_NOTHING;
}
mShortPressOnWindowBehavior = SHORT_PRESS_WINDOW_NOTHING;
@@ -2798,9 +2808,7 @@
if (down && event.isMetaPressed() && event.isCtrlPressed() && repeatCount == 0) {
int type = event.isShiftPressed() ? TAKE_SCREENSHOT_SELECTED_REGION
: TAKE_SCREENSHOT_FULLSCREEN;
- mScreenshotRunnable.setScreenshotType(type);
- mScreenshotRunnable.setScreenshotSource(SCREENSHOT_KEY_OTHER);
- mHandler.post(mScreenshotRunnable);
+ interceptScreenshotChord(type, SCREENSHOT_KEY_OTHER, 0 /*pressDelay*/);
return key_consumed;
}
break;
@@ -2835,13 +2843,6 @@
case KeyEvent.KEYCODE_DEMO_APP_4:
Slog.wtf(TAG, "KEYCODE_APP_X should be handled in interceptKeyBeforeQueueing");
return key_consumed;
- case KeyEvent.KEYCODE_SYSRQ:
- if (down && repeatCount == 0) {
- mScreenshotRunnable.setScreenshotType(TAKE_SCREENSHOT_FULLSCREEN);
- mScreenshotRunnable.setScreenshotSource(SCREENSHOT_KEY_OTHER);
- mHandler.post(mScreenshotRunnable);
- }
- return key_consumed;
case KeyEvent.KEYCODE_BRIGHTNESS_UP:
case KeyEvent.KEYCODE_BRIGHTNESS_DOWN:
if (down) {
@@ -3158,6 +3159,12 @@
}
}
break;
+ case KeyEvent.KEYCODE_SYSRQ:
+ if (down && repeatCount == 0) {
+ interceptScreenshotChord(
+ TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_OTHER, 0 /*pressDelay*/);
+ }
+ return true;
}
return false;
@@ -5755,6 +5762,8 @@
return "DOUBLE_TAP_HOME_NOTHING";
case DOUBLE_TAP_HOME_RECENT_SYSTEM_UI:
return "DOUBLE_TAP_HOME_RECENT_SYSTEM_UI";
+ case DOUBLE_TAP_HOME_PIP_MENU:
+ return "DOUBLE_TAP_HOME_PIP_MENU";
default:
return Integer.toString(behavior);
}
diff --git a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
index 0276b37..7efa897 100644
--- a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
+++ b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
@@ -55,12 +55,15 @@
private volatile boolean mHandledByLongPress = false;
private final Handler mHandler;
private long mLastDownTime = 0;
- private static final long MULTI_PRESS_TIMEOUT = ViewConfiguration.getMultiPressTimeout();
/** Supported gesture flags */
public static final int KEY_LONGPRESS = 1 << 1;
public static final int KEY_VERYLONGPRESS = 1 << 2;
+ static final long MULTI_PRESS_TIMEOUT = ViewConfiguration.getMultiPressTimeout();
+ static long sDefaultLongPressTimeout;
+ static long sDefaultVeryLongPressTimeout;
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = { "KEY_" }, value = {
@@ -86,16 +89,10 @@
abstract static class SingleKeyRule {
private final int mKeyCode;
private final int mSupportedGestures;
- private final long mDefaultLongPressTimeout;
- private final long mDefaultVeryLongPressTimeout;
- SingleKeyRule(Context context, int keyCode, @KeyGestureFlag int supportedGestures) {
+ SingleKeyRule(int keyCode, @KeyGestureFlag int supportedGestures) {
mKeyCode = keyCode;
mSupportedGestures = supportedGestures;
- mDefaultLongPressTimeout =
- ViewConfiguration.get(context).getDeviceGlobalActionKeyTimeout();
- mDefaultVeryLongPressTimeout = context.getResources().getInteger(
- com.android.internal.R.integer.config_veryLongPressTimeout);
}
/**
@@ -145,7 +142,7 @@
* press timeout.
*/
long getLongPressTimeoutMs() {
- return mDefaultLongPressTimeout;
+ return sDefaultLongPressTimeout;
}
/**
* Callback when long press has been detected.
@@ -157,7 +154,7 @@
* If long press is supported, this should always be longer than the long press timeout.
*/
long getVeryLongPressTimeoutMs() {
- return mDefaultVeryLongPressTimeout;
+ return sDefaultVeryLongPressTimeout;
}
/**
* Callback when very long press has been detected.
@@ -173,7 +170,16 @@
}
}
- public SingleKeyGestureDetector() {
+ static SingleKeyGestureDetector get(Context context) {
+ SingleKeyGestureDetector detector = new SingleKeyGestureDetector();
+ sDefaultLongPressTimeout = context.getResources().getInteger(
+ com.android.internal.R.integer.config_globalActionsKeyTimeout);
+ sDefaultVeryLongPressTimeout = context.getResources().getInteger(
+ com.android.internal.R.integer.config_veryLongPressTimeout);
+ return detector;
+ }
+
+ private SingleKeyGestureDetector() {
mHandler = new KeyHandler();
}
diff --git a/services/core/java/com/android/server/power/LowPowerStandbyController.java b/services/core/java/com/android/server/power/LowPowerStandbyController.java
index cea84b5..2d2bad2 100644
--- a/services/core/java/com/android/server/power/LowPowerStandbyController.java
+++ b/services/core/java/com/android/server/power/LowPowerStandbyController.java
@@ -42,6 +42,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;
+import com.android.server.net.NetworkPolicyManagerInternal;
import java.io.PrintWriter;
import java.util.Arrays;
@@ -394,7 +395,11 @@
/** Notify other system components about the updated Low Power Standby active state */
private void notifyActiveChanged(boolean active) {
final PowerManagerInternal pmi = LocalServices.getService(PowerManagerInternal.class);
+ final NetworkPolicyManagerInternal npmi = LocalServices.getService(
+ NetworkPolicyManagerInternal.class);
+
pmi.setLowPowerStandbyActive(active);
+ npmi.setLowPowerStandbyActive(active);
}
@VisibleForTesting
@@ -580,7 +585,10 @@
private void notifyAllowlistChanged(int[] allowlistUids) {
final PowerManagerInternal pmi = LocalServices.getService(PowerManagerInternal.class);
+ final NetworkPolicyManagerInternal npmi = LocalServices.getService(
+ NetworkPolicyManagerInternal.class);
pmi.setLowPowerStandbyAllowlist(allowlistUids);
+ npmi.setLowPowerStandbyAllowlist(allowlistUids);
}
private final class LocalService extends LowPowerStandbyControllerInternal {
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 3857072..e523153 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -521,6 +521,9 @@
// The screen off timeout setting value in milliseconds.
private long mScreenOffTimeoutSetting;
+ // The screen off timeout setting value in milliseconds to apply while device is docked.
+ private long mScreenOffTimeoutDockedSetting;
+
// Default for attentive warning duration.
private long mAttentiveWarningDurationConfig;
@@ -1272,6 +1275,9 @@
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.SCREEN_OFF_TIMEOUT),
false, mSettingsObserver, UserHandle.USER_ALL);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.SCREEN_OFF_TIMEOUT_DOCKED),
+ false, mSettingsObserver, UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.SLEEP_TIMEOUT),
false, mSettingsObserver, UserHandle.USER_ALL);
@@ -1394,6 +1400,9 @@
mScreenOffTimeoutSetting = Settings.System.getIntForUser(resolver,
Settings.System.SCREEN_OFF_TIMEOUT, DEFAULT_SCREEN_OFF_TIMEOUT,
UserHandle.USER_CURRENT);
+ mScreenOffTimeoutDockedSetting = Settings.System.getLongForUser(resolver,
+ Settings.System.SCREEN_OFF_TIMEOUT_DOCKED, mScreenOffTimeoutSetting,
+ UserHandle.USER_CURRENT);
mSleepTimeoutSetting = Settings.Secure.getIntForUser(resolver,
Settings.Secure.SLEEP_TIMEOUT, DEFAULT_SLEEP_TIMEOUT,
UserHandle.USER_CURRENT);
@@ -2946,7 +2955,9 @@
@GuardedBy("mLock")
private long getScreenOffTimeoutLocked(long sleepTimeout, long attentiveTimeout) {
- long timeout = mScreenOffTimeoutSetting;
+ long timeout = mDockState == Intent.EXTRA_DOCK_STATE_UNDOCKED
+ ? mScreenOffTimeoutSetting
+ : mScreenOffTimeoutDockedSetting;
if (isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked()) {
timeout = Math.min(timeout, mMaximumScreenOffTimeoutFromDeviceAdmin);
}
@@ -4974,7 +4985,8 @@
}
}
- private final class DockReceiver extends BroadcastReceiver {
+ @VisibleForTesting
+ final class DockReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
synchronized (mLock) {
diff --git a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
index 040fffa8..19c8cd2 100644
--- a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
@@ -160,7 +160,7 @@
private SensorPrivacyManagerInternalImpl mSensorPrivacyManagerInternal;
- private EmergencyCallHelper mEmergencyCallHelper;
+ private CallStateHelper mCallStateHelper;
private KeyguardManager mKeyguardManager;
private int mCurrentUser = USER_NULL;
@@ -191,7 +191,7 @@
public void onBootPhase(int phase) {
if (phase == PHASE_SYSTEM_SERVICES_READY) {
mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
- mEmergencyCallHelper = new EmergencyCallHelper();
+ mCallStateHelper = new CallStateHelper();
} else if (phase == PHASE_ACTIVITY_MANAGER_READY) {
mCameraPrivacyLightController = new CameraPrivacyLightController(mContext);
}
@@ -702,7 +702,7 @@
}
private boolean canChangeIndividualSensorPrivacy(@UserIdInt int userId, int sensor) {
- if (sensor == MICROPHONE && mEmergencyCallHelper.isInEmergencyCall()) {
+ if (sensor == MICROPHONE && mCallStateHelper.isInEmergencyCall()) {
// During emergency call the microphone toggle managed automatically
Log.i(TAG, "Can't change mic toggle during an emergency call");
return false;
@@ -1523,16 +1523,16 @@
}
}
- private class EmergencyCallHelper {
+ private class CallStateHelper {
private OutgoingEmergencyStateCallback mEmergencyStateCallback;
private CallStateCallback mCallStateCallback;
private boolean mIsInEmergencyCall;
private boolean mMicUnmutedForEmergencyCall;
- private Object mEmergencyStateLock = new Object();
+ private Object mCallStateLock = new Object();
- EmergencyCallHelper() {
+ CallStateHelper() {
mEmergencyStateCallback = new OutgoingEmergencyStateCallback();
mCallStateCallback = new CallStateCallback();
@@ -1543,7 +1543,7 @@
}
boolean isInEmergencyCall() {
- synchronized (mEmergencyStateLock) {
+ synchronized (mCallStateLock) {
return mIsInEmergencyCall;
}
}
@@ -1563,12 +1563,14 @@
public void onCallStateChanged(int state) {
if (state == TelephonyManager.CALL_STATE_IDLE) {
onCallOver();
+ } else {
+ onCall();
}
}
}
private void onEmergencyCall() {
- synchronized (mEmergencyStateLock) {
+ synchronized (mCallStateLock) {
if (!mIsInEmergencyCall) {
mIsInEmergencyCall = true;
if (mSensorPrivacyServiceImpl
@@ -1583,8 +1585,19 @@
}
}
+ private void onCall() {
+ long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mCallStateLock) {
+ mSensorPrivacyServiceImpl.showSensorUseDialog(MICROPHONE);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
private void onCallOver() {
- synchronized (mEmergencyStateLock) {
+ synchronized (mCallStateLock) {
if (mIsInEmergencyCall) {
mIsInEmergencyCall = false;
if (mMicUnmutedForEmergencyCall) {
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 f6a9359..adee325 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -2392,7 +2392,8 @@
metrics.unaccountedKb,
metrics.gpuTotalUsageKb,
metrics.gpuPrivateAllocationsKb,
- metrics.dmaBufTotalExportedKb));
+ metrics.dmaBufTotalExportedKb,
+ metrics.shmemKb));
return StatsManager.PULL_SUCCESS;
}
@@ -4490,6 +4491,9 @@
}
int pullMediaCapabilitiesStats(int atomTag, List<StatsEvent> pulledData) {
+ if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
+ return StatsManager.PULL_SKIP;
+ }
AudioManager audioManager = mContext.getSystemService(AudioManager.class);
if (audioManager == null) {
return StatsManager.PULL_SKIP;
diff --git a/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java b/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java
index 30b6e68..9ebf59e 100644
--- a/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java
+++ b/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java
@@ -82,6 +82,7 @@
result.vmallocUsedKb = (int) mInfos[Debug.MEMINFO_VM_ALLOC_USED];
result.pageTablesKb = (int) mInfos[Debug.MEMINFO_PAGE_TABLES];
result.kernelStackKb = (int) mInfos[Debug.MEMINFO_KERNEL_STACK];
+ result.shmemKb = (int) mInfos[Debug.MEMINFO_SHMEM];
result.totalIonKb = totalIonKb;
result.gpuTotalUsageKb = gpuTotalUsageKb;
result.gpuPrivateAllocationsKb = gpuPrivateAllocationsKb;
@@ -95,6 +96,7 @@
public int vmallocUsedKb;
public int pageTablesKb;
public int kernelStackKb;
+ public int shmemKb;
public int totalIonKb;
public int gpuTotalUsageKb;
public int gpuPrivateAllocationsKb;
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 94f483c..2049f3d 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -2031,11 +2031,14 @@
@Override
public void updateMediaTapToTransferReceiverDisplay(
@StatusBarManager.MediaTransferReceiverState int displayState,
- MediaRoute2Info routeInfo) {
+ MediaRoute2Info routeInfo,
+ @Nullable Icon appIcon,
+ @Nullable CharSequence appName) {
enforceMediaContentControl();
if (mBar != null) {
try {
- mBar.updateMediaTapToTransferReceiverDisplay(displayState, routeInfo);
+ mBar.updateMediaTapToTransferReceiverDisplay(
+ displayState, routeInfo, appIcon, appName);
} catch (RemoteException e) {
Slog.e(TAG, "updateMediaTapToTransferReceiverDisplay", e);
}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
index e751a7b..7466001 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -70,7 +70,7 @@
* 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;
/**
@@ -205,9 +205,9 @@
@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;
}
@@ -219,9 +219,9 @@
@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;
}
@@ -233,19 +233,19 @@
@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;
}
@@ -275,11 +275,11 @@
// 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;
}
@@ -370,14 +370,14 @@
@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
@@ -386,7 +386,7 @@
}
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."
@@ -403,15 +403,15 @@
}
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
@@ -422,17 +422,17 @@
}
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;
@@ -451,12 +451,12 @@
// 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;
@@ -464,7 +464,7 @@
} 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;
@@ -472,7 +472,7 @@
} 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;
@@ -480,7 +480,7 @@
} 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;
@@ -492,8 +492,8 @@
}
// 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;
}
}
@@ -550,7 +550,7 @@
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);
@@ -584,8 +584,8 @@
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);
@@ -594,7 +594,7 @@
// 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);
@@ -616,9 +616,9 @@
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;
}
@@ -636,9 +636,9 @@
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;
}
@@ -656,9 +656,9 @@
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;
}
@@ -849,9 +849,9 @@
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
@@ -865,6 +865,6 @@
// 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/tracing/TracingServiceProxy.java b/services/core/java/com/android/server/tracing/TracingServiceProxy.java
index 27c0bee..10e868d 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.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 @@
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 @@
}
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 @@
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/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 6aafd4a..b4c54f9 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -69,6 +69,7 @@
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.Xml;
+import android.view.Display;
import android.view.IWindowManager;
import android.view.WindowManagerGlobal;
@@ -76,7 +77,9 @@
import com.android.internal.content.PackageMonitor;
import com.android.internal.util.DumpUtils;
import com.android.internal.widget.LockPatternUtils;
+import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -143,6 +146,7 @@
private final LockPatternUtils mLockPatternUtils;
private final UserManager mUserManager;
private final ActivityManager mActivityManager;
+ private VirtualDeviceManagerInternal mVirtualDeviceManager;
@GuardedBy("mUserIsTrusted")
private final SparseBooleanArray mUserIsTrusted = new SparseBooleanArray();
@@ -1293,9 +1297,57 @@
mHandler.obtainMessage(MSG_UNREGISTER_LISTENER, trustListener).sendToTarget();
}
+ /**
+ * @param uid: uid of the calling app (obtained via getCallingUid())
+ * @param displayId: the id of a Display
+ * @return Returns true if both of the following conditions hold -
+ * 1) the uid belongs to an app instead of a system core component; and
+ * 2) either the uid is running on a virtual device or the displayId
+ * is owned by a virtual device
+ */
+ private boolean isAppOrDisplayOnAnyVirtualDevice(int uid, int displayId) {
+ if (UserHandle.isCore(uid)) {
+ return false;
+ }
+
+ if (mVirtualDeviceManager == null) {
+ mVirtualDeviceManager = LocalServices.getService(
+ VirtualDeviceManagerInternal.class);
+ if (mVirtualDeviceManager == null) {
+ // VirtualDeviceManager service may not have been published
+ return false;
+ }
+ }
+
+ switch (displayId) {
+ case Display.INVALID_DISPLAY:
+ // There is no Display object associated with the Context of the calling app.
+ if (mVirtualDeviceManager.isAppRunningOnAnyVirtualDevice(uid)) {
+ return true;
+ }
+ break;
+ case Display.DEFAULT_DISPLAY:
+ // The DEFAULT_DISPLAY is by definition not virtual.
+ break;
+ default:
+ // Other display IDs can belong to logical displays created for other purposes.
+ if (mVirtualDeviceManager.isDisplayOwnedByAnyVirtualDevice(displayId)) {
+ return true;
+ }
+ break;
+ }
+ return false;
+ }
+
@Override
- public boolean isDeviceLocked(int userId) throws RemoteException {
- userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
+ public boolean isDeviceLocked(int userId, int displayId) throws RemoteException {
+ int uid = getCallingUid();
+ if (isAppOrDisplayOnAnyVirtualDevice(uid, displayId)) {
+ // Virtual displays are considered insecure because they may be used for streaming
+ // to other devices.
+ return false;
+ }
+ userId = ActivityManager.handleIncomingUser(getCallingPid(), uid, userId,
false /* allowAll */, true /* requireFull */, "isDeviceLocked", null);
final long token = Binder.clearCallingIdentity();
@@ -1310,8 +1362,15 @@
}
@Override
- public boolean isDeviceSecure(int userId) throws RemoteException {
- userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
+ public boolean isDeviceSecure(int userId, int displayId) throws RemoteException {
+ int uid = getCallingUid();
+ if (isAppOrDisplayOnAnyVirtualDevice(uid, displayId)) {
+ // Virtual displays are considered insecure because they may be used for streaming
+ // to other devices.
+ return false;
+ }
+
+ userId = ActivityManager.handleIncomingUser(getCallingPid(), uid, userId,
false /* allowAll */, true /* requireFull */, "isDeviceSecure", null);
final long token = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index f15d2bb..e02fabd 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -2543,6 +2543,7 @@
@Override
public int getClientPriority(int useCase, String sessionId) {
+ ensureTunerResourceAccessPermission();
final int callingPid = Binder.getCallingPid();
final long identity = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 56985af..87c8a79 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -429,7 +429,8 @@
if (needsExtraction) {
extractColors(wallpaper);
}
- notifyColorListeners(wallpaper.primaryColors, which, wallpaper.userId, displayId);
+ notifyColorListeners(getAdjustedWallpaperColorsOnDimming(wallpaper), which,
+ wallpaper.userId, displayId);
}
private static <T extends IInterface> boolean emptyCallbackList(RemoteCallbackList<T> list) {
@@ -1519,7 +1520,6 @@
if (mWallpaper.mWallpaperDimAmount != 0f) {
try {
connector.mEngine.applyDimming(mWallpaper.mWallpaperDimAmount);
- notifyWallpaperColorsChanged(mWallpaper, FLAG_SYSTEM);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to dim wallpaper", e);
}
@@ -2711,8 +2711,31 @@
extractColors(wallpaperData);
}
+ return getAdjustedWallpaperColorsOnDimming(wallpaperData);
+ }
+
+ /**
+ * Gets the adjusted {@link WallpaperColors} if the wallpaper colors were not extracted from
+ * bitmap (i.e. it's a live wallpaper) and the dim amount is not 0. If these conditions apply,
+ * default to using color hints that do not support dark theme and dark text.
+ *
+ * @param wallpaperData WallpaperData containing the WallpaperColors and mWallpaperDimAmount
+ */
+ WallpaperColors getAdjustedWallpaperColorsOnDimming(WallpaperData wallpaperData) {
synchronized (mLock) {
- return wallpaperData.primaryColors;
+ WallpaperColors wallpaperColors = wallpaperData.primaryColors;
+
+ if (wallpaperColors != null
+ && (wallpaperColors.getColorHints() & WallpaperColors.HINT_FROM_BITMAP) == 0
+ && wallpaperData.mWallpaperDimAmount != 0f) {
+ int adjustedColorHints = wallpaperColors.getColorHints()
+ & ~WallpaperColors.HINT_SUPPORTS_DARK_TEXT
+ & ~WallpaperColors.HINT_SUPPORTS_DARK_THEME;
+ return new WallpaperColors(
+ wallpaperColors.getPrimaryColor(), wallpaperColors.getSecondaryColor(),
+ wallpaperColors.getTertiaryColor(), adjustedColorHints);
+ }
+ return wallpaperColors;
}
}
@@ -2782,6 +2805,7 @@
wallpaper.fromForegroundApp = fromForegroundApp;
wallpaper.cropHint.set(cropHint);
wallpaper.allowBackup = allowBackup;
+ wallpaper.mWallpaperDimAmount = getWallpaperDimAmount();
}
return pfd;
} finally {
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index ff96aeb..d526845 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -1088,7 +1088,7 @@
final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token);
if (r != null && r.isState(RESUMED, PAUSING)) {
r.mDisplayContent.mAppTransition.overridePendingAppTransition(
- packageName, enterAnim, exitAnim, null, null,
+ packageName, enterAnim, exitAnim, backgroundColor, null, null,
r.mOverrideTaskTransition);
r.mTransitionController.setOverrideAnimation(
TransitionInfo.AnimationOptions.makeCustomAnimOptions(packageName,
@@ -1135,13 +1135,13 @@
}
@Override
- public void setDisablePreviewScreenshots(IBinder token, boolean disable) {
+ public void setRecentsScreenshotEnabled(IBinder token, boolean enabled) {
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token);
if (r != null) {
- r.setDisablePreviewScreenshots(disable);
+ r.setRecentsScreenshotEnabled(enabled);
}
}
} finally {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 0527c6e..8fc3a87 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -293,9 +293,7 @@
import android.os.UserHandle;
import android.service.contentcapture.ActivityEvent;
import android.service.dreams.DreamActivity;
-import android.service.dreams.DreamManagerInternal;
import android.service.voice.IVoiceInteractionSession;
-import android.text.TextUtils;
import android.util.ArraySet;
import android.util.EventLog;
import android.util.Log;
@@ -766,7 +764,7 @@
// Last visibility state we reported to the app token.
boolean reportedVisible;
- boolean mDisablePreviewScreenshots;
+ boolean mEnablePreviewScreenshots = true;
// Information about an application starting window if displayed.
// Note: these are de-referenced before the starting window animates away.
@@ -2504,10 +2502,20 @@
}
void removeStartingWindow() {
+ boolean prevEligibleForLetterboxEducation = isEligibleForLetterboxEducation();
+
if (transferSplashScreenIfNeeded()) {
return;
}
removeStartingWindowAnimation(true /* prepareAnimation */);
+
+ // TODO(b/215316431): Add tests
+ final Task task = getTask();
+ if (prevEligibleForLetterboxEducation != isEligibleForLetterboxEducation()
+ && task != null) {
+ // Trigger TaskInfoChanged to update the letterbox education.
+ task.dispatchTaskInfoChangedIfNeeded(true /* force */);
+ }
}
void removeStartingWindowAnimation(boolean prepareAnimation) {
@@ -2632,31 +2640,6 @@
return false;
}
- static boolean canLaunchDreamActivity(String packageName) {
- if (packageName == null) {
- return false;
- }
-
- if (!LocalServices.getService(ActivityTaskManagerInternal.class).isDreaming()) {
- return false;
- }
-
- final DreamManagerInternal dreamManager =
- LocalServices.getService(DreamManagerInternal.class);
-
- // Verify that the package is the current active dream or doze component. The
- // getActiveDreamComponent() call path does not acquire the DreamManager lock and thus
- // is safe to use.
- final ComponentName activeDream = dreamManager.getActiveDreamComponent(false /* doze */);
- final ComponentName activeDoze = dreamManager.getActiveDreamComponent(true /* doze */);
- return TextUtils.equals(packageName, getPackageName(activeDream))
- || TextUtils.equals(packageName, getPackageName(activeDoze));
- }
-
- private static String getPackageName(ComponentName componentName) {
- return componentName != null ? componentName.getPackageName() : null;
- }
-
private void setActivityType(boolean componentSpecified, int launchedFromUid, Intent intent,
ActivityOptions options, ActivityRecord sourceRecord) {
int activityType = ACTIVITY_TYPE_UNDEFINED;
@@ -2677,7 +2660,7 @@
&& canLaunchAssistActivity(launchedFromPackage)) {
activityType = ACTIVITY_TYPE_ASSISTANT;
} else if (options != null && options.getLaunchActivityType() == ACTIVITY_TYPE_DREAM
- && canLaunchDreamActivity(launchedFromPackage)
+ && mAtmService.canLaunchDreamActivity(launchedFromPackage)
&& DreamActivity.class.getName() == info.name) {
activityType = ACTIVITY_TYPE_DREAM;
}
@@ -4506,6 +4489,7 @@
pendingOptions.getPackageName(),
pendingOptions.getCustomEnterResId(),
pendingOptions.getCustomExitResId(),
+ pendingOptions.getCustomBackgroundColor(),
pendingOptions.getAnimationStartedListener(),
pendingOptions.getAnimationFinishedListener(),
pendingOptions.getOverrideTaskTransition());
@@ -5137,22 +5121,22 @@
}
/**
- * See {@link Activity#setDisablePreviewScreenshots}.
+ * See {@link Activity#setRecentsScreenshotEnabled}.
*/
- void setDisablePreviewScreenshots(boolean disable) {
- mDisablePreviewScreenshots = disable;
+ void setRecentsScreenshotEnabled(boolean enabled) {
+ mEnablePreviewScreenshots = enabled;
}
/**
* Retrieves whether we'd like to generate a snapshot that's based solely on the theme. This is
- * the case when preview screenshots are disabled {@link #setDisablePreviewScreenshots} or when
+ * the case when preview screenshots are disabled {@link #setRecentsScreenshotEnabled} or when
* we can't take a snapshot for other reasons, for example, if we have a secure window.
*
* @return True if we need to generate an app theme snapshot, false if we'd like to take a real
* screenshot.
*/
boolean shouldUseAppThemeSnapshot() {
- return mDisablePreviewScreenshots || forAllWindows(WindowState::isSecureLocked,
+ return !mEnablePreviewScreenshots || forAllWindows(WindowState::isSecureLocked,
true /* topToBottom */);
}
@@ -5236,6 +5220,10 @@
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:
@@ -7697,6 +7685,8 @@
* <li>The activity is eligible for fixed orientation letterbox.
* <li>The activity is in fullscreen.
* <li>The activity is portrait-only.
+ * <li>The activity doesn't have a starting window (education should only be displayed
+ * once the starting window is removed in {@link #removeStartingWindow}).
* </ul>
*/
// TODO(b/215316431): Add tests
@@ -7704,7 +7694,8 @@
return mWmService.mLetterboxConfiguration.getIsEducationEnabled()
&& mIsEligibleForFixedOrientationLetterbox
&& getWindowingMode() == WINDOWING_MODE_FULLSCREEN
- && getRequestedConfigurationOrientation() == ORIENTATION_PORTRAIT;
+ && getRequestedConfigurationOrientation() == ORIENTATION_PORTRAIT
+ && mStartingWindow == null;
}
/**
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 5164bf0..5ffe214 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1820,7 +1820,7 @@
if (!mAvoidMoveToFront && mDoResume) {
mTargetRootTask.getRootTask().moveToFront("reuseOrNewTask", targetTask);
- if (!mTargetRootTask.isTopRootTaskInDisplayArea() && mService.mInternal.isDreaming()
+ if (!mTargetRootTask.isTopRootTaskInDisplayArea() && mService.isDreaming()
&& !dreamStopping) {
// Launching underneath dream activity (fullscreen, always-on-top). Run the launch-
// -behind transition so the Activity gets created and starts in visible state.
@@ -2003,8 +2003,8 @@
* @param targetTask the target task for launching activity, which could be different from
* the one who hosting the embedding.
*/
- private boolean canEmbedActivity(@NonNull TaskFragment taskFragment, ActivityRecord starting,
- boolean newTask, Task targetTask) {
+ private boolean canEmbedActivity(@NonNull TaskFragment taskFragment,
+ @NonNull ActivityRecord starting, boolean newTask, Task targetTask) {
final Task hostTask = taskFragment.getTask();
if (hostTask == null) {
return false;
@@ -2016,8 +2016,7 @@
return true;
}
- // Not allowed embedding an activity of another app.
- if (hostUid != starting.getUid()) {
+ if (!taskFragment.isAllowedToEmbedActivity(starting)) {
return false;
}
@@ -2100,7 +2099,7 @@
// At this point we are certain we want the task moved to the front. If we need to dismiss
// any other always-on-top root tasks, now is the time to do it.
- if (targetTaskTop.canTurnScreenOn() && mService.mInternal.isDreaming()) {
+ if (targetTaskTop.canTurnScreenOn() && mService.isDreaming()) {
targetTaskTop.mTaskSupervisor.wakeUp("recycleTask#turnScreenOnFlag");
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 23508d9..25c4d20 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -316,7 +316,6 @@
public abstract void clearHeavyWeightProcessIfEquals(WindowProcessController proc);
public abstract void finishHeavyWeightApp();
- public abstract boolean isDreaming();
public abstract boolean isSleeping();
public abstract boolean isShuttingDown();
public abstract boolean shuttingDown(boolean booted, int timeout);
@@ -456,15 +455,6 @@
/** Writes current activity states to the proto stream. */
public abstract void writeActivitiesToProto(ProtoOutputStream proto);
- /**
- * Saves the current activity manager state and includes the saved state in the next dump of
- * activity manager.
- */
- public abstract void saveANRState(String reason);
-
- /** Clears the previously saved activity manager ANR state. */
- public abstract void clearSavedANRState();
-
/** Dump the current state based on the command. */
public abstract void dump(String cmd, FileDescriptor fd, PrintWriter pw, String[] args,
int opti, boolean dumpAll, boolean dumpClient, String dumpPackage);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index ca4d717..193e476 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -208,6 +208,7 @@
import android.os.storage.StorageManager;
import android.provider.Settings;
import android.service.dreams.DreamActivity;
+import android.service.dreams.DreamManagerInternal;
import android.service.voice.IVoiceInteractionSession;
import android.service.voice.VoiceInteractionManagerInternal;
import android.sysprop.DisplayProperties;
@@ -671,7 +672,7 @@
* start/stop the dream. It is set to true shortly before the {@link DreamService} is started.
* It is set to false after the {@link DreamService} is stopped.
*/
- private boolean mDreaming = false;
+ private volatile boolean mDreaming;
/**
* The process state used for processes that are running the top activities.
@@ -1399,10 +1400,34 @@
}
}
+ boolean isDreaming() {
+ return mDreaming;
+ }
+
+ boolean canLaunchDreamActivity(String packageName) {
+ if (!mDreaming || packageName == null) {
+ return false;
+ }
+ final DreamManagerInternal dreamManager =
+ LocalServices.getService(DreamManagerInternal.class);
+ // Verify that the package is the current active dream or doze component. The
+ // getActiveDreamComponent() call path does not acquire the DreamManager lock and thus
+ // is safe to use.
+ final ComponentName activeDream = dreamManager.getActiveDreamComponent(false /* doze */);
+ if (activeDream != null && packageName.equals(activeDream.getPackageName())) {
+ return true;
+ }
+ final ComponentName activeDoze = dreamManager.getActiveDreamComponent(true /* doze */);
+ if (activeDoze != null && packageName.equals(activeDoze.getPackageName())) {
+ return true;
+ }
+ return false;
+ }
+
private void enforceCallerIsDream(String callerPackageName) {
final long origId = Binder.clearCallingIdentity();
try {
- if (!ActivityRecord.canLaunchDreamActivity(callerPackageName)) {
+ if (!canLaunchDreamActivity(callerPackageName)) {
throw new SecurityException("The dream activity can be started only when the device"
+ " is dreaming and only by the active dream package.");
}
@@ -1695,6 +1720,12 @@
}
@Override
+ public String getVoiceInteractorPackageName(IBinder callingVoiceInteractor) {
+ return LocalServices.getService(VoiceInteractionManagerInternal.class)
+ .getVoiceInteractorPackageName(callingVoiceInteractor);
+ }
+
+ @Override
public int startAssistantActivity(String callingPackage, @NonNull String callingFeatureId,
int callingPid, int callingUid, Intent intent, String resolvedType, Bundle bOptions,
int userId) {
@@ -3043,7 +3074,7 @@
* SecurityException} or returns false with a logcat message depending on whether the app
* targets SDK level {@link android.os.Build.VERSION_CODES#S} or not.
*/
- private boolean checkCanCloseSystemDialogs(int pid, int uid, @Nullable String packageName) {
+ boolean checkCanCloseSystemDialogs(int pid, int uid, @Nullable String packageName) {
final WindowProcessController process;
synchronized (mGlobalLock) {
process = mProcessMap.getProcess(pid);
@@ -3171,8 +3202,12 @@
permission, pid, uid, owningUid, exported);
}
+ boolean isCallerRecents(int callingUid) {
+ return mRecentTasks.isCallerRecents(callingUid);
+ }
+
boolean isGetTasksAllowed(String caller, int callingPid, int callingUid) {
- if (getRecentTasks().isCallerRecents(callingUid)) {
+ if (isCallerRecents(callingUid)) {
// Always allow the recents component to get tasks
return true;
}
@@ -5121,11 +5156,28 @@
}
/**
- * @return allowlist tag for a uid from mPendingTempAllowlist, null if not currently on
- * the allowlist
+ * Saves the current activity manager state and includes the saved state in the next dump of
+ * activity manager.
*/
- String getPendingTempAllowlistTagForUidLocked(int uid) {
- return mPendingTempAllowlist.get(uid);
+ void saveANRState(String reason) {
+ final StringWriter sw = new StringWriter();
+ final PrintWriter pw = new FastPrintWriter(sw, false, 1024);
+ pw.println(" ANR time: " + DateFormat.getDateTimeInstance().format(new Date()));
+ if (reason != null) {
+ pw.println(" Reason: " + reason);
+ }
+ pw.println();
+ getActivityStartController().dump(pw, " ", null);
+ pw.println();
+ pw.println("-------------------------------------------------------------------"
+ + "------------");
+ dumpActivitiesLocked(null /* fd */, pw, null /* args */, 0 /* opti */,
+ true /* dumpAll */, false /* dumpClient */, null /* dumpPackage */,
+ "" /* header */);
+ pw.println();
+ pw.close();
+
+ mLastANRState = sw.toString();
}
void logAppTooSlow(WindowProcessController app, long startTime, String msg) {
@@ -5267,6 +5319,18 @@
}
}
+ /**
+ * Returns {@code true} if the process represented by the pid passed as argument is
+ * instrumented.
+ */
+ boolean isInstrumenting(int pid) {
+ final WindowProcessController process;
+ synchronized (mGlobalLock) {
+ process = mProcessMap.getProcess(pid);
+ }
+ return process != null ? process.isInstrumenting() : false;
+ }
+
final class H extends Handler {
static final int REPORT_TIME_TRACKER_MSG = 1;
static final int UPDATE_PROCESS_ANIMATING_STATE = 2;
@@ -5496,7 +5560,7 @@
@Override
public boolean isCallerRecents(int callingUid) {
- return getRecentTasks().isCallerRecents(callingUid);
+ return ActivityTaskManagerService.this.isCallerRecents(callingUid);
}
@Override
@@ -5624,13 +5688,6 @@
}
}
- @Override
- public boolean isDreaming() {
- synchronized (mGlobalLock) {
- return mDreaming;
- }
- }
-
@HotPath(caller = HotPath.OOM_ADJUSTMENT)
@Override
public boolean isSleeping() {
@@ -6131,37 +6188,6 @@
}
@Override
- public void saveANRState(String reason) {
- synchronized (mGlobalLock) {
- final StringWriter sw = new StringWriter();
- final PrintWriter pw = new FastPrintWriter(sw, false, 1024);
- pw.println(" ANR time: " + DateFormat.getDateTimeInstance().format(new Date()));
- if (reason != null) {
- pw.println(" Reason: " + reason);
- }
- pw.println();
- getActivityStartController().dump(pw, " ", null);
- pw.println();
- pw.println("-------------------------------------------------------------------"
- + "------------");
- dumpActivitiesLocked(null /* fd */, pw, null /* args */, 0 /* opti */,
- true /* dumpAll */, false /* dumpClient */, null /* dumpPackage */,
- "" /* header */);
- pw.println();
- pw.close();
-
- mLastANRState = sw.toString();
- }
- }
-
- @Override
- public void clearSavedANRState() {
- synchronized (mGlobalLock) {
- mLastANRState = null;
- }
- }
-
- @Override
public void dump(String cmd, FileDescriptor fd, PrintWriter pw, String[] args, int opti,
boolean dumpAll, boolean dumpClient, String dumpPackage) {
synchronized (mGlobalLock) {
diff --git a/services/core/java/com/android/server/wm/AnimationAdapter.java b/services/core/java/com/android/server/wm/AnimationAdapter.java
index 5899a4e..a743091 100644
--- a/services/core/java/com/android/server/wm/AnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/AnimationAdapter.java
@@ -42,6 +42,22 @@
boolean getShowWallpaper();
/**
+ * @return Whether we should show a background behind the animating windows.
+ * @see Animation#getShowBackground()
+ */
+ default boolean getShowBackground() {
+ return false;
+ }
+
+ /**
+ * @return The background color to use during an animation if getShowBackground returns true.
+ * @see Animation#getBackgroundColor()
+ */
+ default int getBackgroundColor() {
+ return 0;
+ }
+
+ /**
* Requests to start the animation.
*
* @param animationLeash The surface to run the animation on. See {@link SurfaceAnimator} for an
diff --git a/services/core/java/com/android/server/wm/AnrController.java b/services/core/java/com/android/server/wm/AnrController.java
index 98cd40a..3d54b27 100644
--- a/services/core/java/com/android/server/wm/AnrController.java
+++ b/services/core/java/com/android/server/wm/AnrController.java
@@ -225,7 +225,7 @@
private void dumpAnrStateLocked(ActivityRecord activity, WindowState windowState,
String reason) {
mService.saveANRStateLocked(activity, windowState, reason);
- mService.mAtmInternal.saveANRState(reason);
+ mService.mAtmService.saveANRState(reason);
}
private boolean isWindowAboveSystem(WindowState windowState) {
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 56adcfd..05efb29 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -93,6 +93,7 @@
import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_AFTER_ANIM;
import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_NONE;
+import android.annotation.ColorInt;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
@@ -198,6 +199,7 @@
private IRemoteCallback mAnimationFinishedCallback;
private int mNextAppTransitionEnter;
private int mNextAppTransitionExit;
+ private @ColorInt int mNextAppTransitionBackgroundColor;
private int mNextAppTransitionInPlace;
private boolean mNextAppTransitionIsSync;
@@ -829,6 +831,7 @@
break;
}
a = animAttr != 0 ? loadAnimationAttr(lp, animAttr, transit) : null;
+
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
"applyAnimation: anim=%s animAttr=0x%x transit=%s isEntrance=%b "
+ "Callers=%s",
@@ -836,6 +839,11 @@
Debug.getCallers(3));
}
setAppTransitionFinishedCallbackIfNeeded(a);
+
+ if (mNextAppTransitionBackgroundColor != 0) {
+ a.setBackgroundColor(mNextAppTransitionBackgroundColor);
+ }
+
return a;
}
@@ -861,14 +869,15 @@
}
void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim,
- IRemoteCallback startedCallback, IRemoteCallback endedCallback,
- boolean overrideTaskTransaction) {
+ @ColorInt int backgroundColor, IRemoteCallback startedCallback,
+ IRemoteCallback endedCallback, boolean overrideTaskTransaction) {
if (canOverridePendingAppTransition()) {
clear();
mNextAppTransitionOverrideRequested = true;
mNextAppTransitionPackage = packageName;
mNextAppTransitionEnter = enterAnim;
mNextAppTransitionExit = exitAnim;
+ mNextAppTransitionBackgroundColor = backgroundColor;
postAnimationCallback();
mNextAppTransitionCallback = startedCallback;
mAnimationFinishedCallback = endedCallback;
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index 45a6cb9..e26748c 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -22,11 +22,14 @@
import android.annotation.Nullable;
import android.app.WindowConfiguration;
import android.content.ComponentName;
+import android.graphics.Point;
+import android.graphics.Rect;
import android.hardware.HardwareBuffer;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.util.Slog;
+import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.window.BackNavigationInfo;
import android.window.IOnBackInvokedCallback;
@@ -88,34 +91,39 @@
ActivityRecord activityRecord;
SurfaceControl animationLeashParent;
WindowConfiguration taskWindowConfiguration;
- SurfaceControl animLeash;
HardwareBuffer screenshotBuffer = null;
int prevTaskId;
int prevUserId;
- IOnBackInvokedCallback callback;
+ IOnBackInvokedCallback applicationCallback = null;
+ IOnBackInvokedCallback systemCallback = null;
+ RemoteAnimationTarget topAppTarget;
+ SurfaceControl animLeash;
synchronized (task.mWmService.mGlobalLock) {
activityRecord = task.topRunningActivity();
removedWindowContainer = activityRecord;
taskWindowConfiguration = task.getTaskInfo().configuration.windowConfiguration;
-
- WindowState topChild = activityRecord.getTopChild();
- callback = topChild.getOnBackInvokedCallback();
+ WindowState window = task.getWindow(WindowState::isFocused);
+ if (window != null) {
+ applicationCallback = window.getApplicationOnBackInvokedCallback();
+ systemCallback = window.getSystemOnBackInvokedCallback();
+ }
ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "startBackNavigation task=%s, "
- + "topRunningActivity=%s, topWindow=%s backCallback=%s",
- task, activityRecord, topChild,
- callback != null ? callback.getClass().getSimpleName() : null);
+ + "topRunningActivity=%s, applicationBackCallback=%s, "
+ + "systemBackCallback=%s",
+ task, activityRecord, applicationCallback, systemCallback);
// For IME and Home, either a callback is registered, or we do nothing. In both cases,
// we don't need to pass the leashes below.
if (task.getDisplayContent().getImeContainer().isVisible()
|| activityRecord.isActivityTypeHome()) {
- if (callback != null) {
+ if (applicationCallback != null) {
return new BackNavigationInfo(BackNavigationInfo.TYPE_CALLBACK,
null /* topWindowLeash */, null /* screenshotSurface */,
null /* screenshotBuffer */, null /* taskWindowConfiguration */,
- null /* onBackNavigationDone */, callback /* onBackInvokedCallback */);
+ null /* onBackNavigationDone */,
+ applicationCallback /* onBackInvokedCallback */);
} else {
return null;
}
@@ -124,8 +132,12 @@
prev = task.getActivity(
(r) -> !r.finishing && r.getTask() == task && !r.isTopRunningActivity());
- if (callback != null) {
- backType = BackNavigationInfo.TYPE_CALLBACK;
+ if (applicationCallback != null) {
+ return new BackNavigationInfo(BackNavigationInfo.TYPE_CALLBACK,
+ null /* topWindowLeash */, null /* screenshotSurface */,
+ null /* screenshotBuffer */, null /* taskWindowConfiguration */,
+ null /* onBackNavigationDone */,
+ applicationCallback /* onBackInvokedCallback */);
} else if (prev != null) {
backType = BackNavigationInfo.TYPE_CROSS_ACTIVITY;
} else if (task.returnsToHomeRootTask()) {
@@ -159,6 +171,11 @@
screenshotBuffer = getActivitySnapshot(task, prev.mActivityComponent);
}
+ // Only create a new leash if no leash has been created.
+ // Otherwise return null for animation target to avoid conflict.
+ if (removedWindowContainer.hasCommittedReparentToAnimationLeash()) {
+ return null;
+ }
// Prepare a leash to animate the current top window
animLeash = removedWindowContainer.makeAnimationLeash()
.setName("BackPreview Leash for " + removedWindowContainer)
@@ -166,8 +183,25 @@
.setBLASTLayer()
.build();
removedWindowContainer.reparentSurfaceControl(tx, animLeash);
-
animationLeashParent = removedWindowContainer.getAnimationLeashParent();
+ topAppTarget = new RemoteAnimationTarget(
+ task.mTaskId,
+ RemoteAnimationTarget.MODE_CLOSING,
+ animLeash,
+ false /* isTransluscent */,
+ new Rect() /* clipRect */,
+ new Rect() /* contentInsets */,
+ activityRecord.getPrefixOrderIndex(),
+ new Point(0, 0) /* position */,
+ new Rect() /* localBounds */,
+ new Rect() /* screenSpaceBounds */,
+ removedWindowContainer.getWindowConfiguration(),
+ true /* isNotInRecent */,
+ null,
+ null,
+ task.getTaskInfo(),
+ false,
+ activityRecord.windowType);
}
SurfaceControl.Builder builder = new SurfaceControl.Builder()
@@ -187,7 +221,7 @@
// The Animation leash needs to be above the screenshot surface, but the animation leash
// needs to be added before to be in the synchronized block.
- tx.setLayer(animLeash, 1);
+ tx.setLayer(topAppTarget.leash, 1);
tx.apply();
WindowContainer<?> finalRemovedWindowContainer = removedWindowContainer;
@@ -200,11 +234,13 @@
return null;
}
+ final IOnBackInvokedCallback callback =
+ applicationCallback != null ? applicationCallback : systemCallback;
RemoteCallback onBackNavigationDone = new RemoteCallback(
result -> resetSurfaces(finalRemovedWindowContainer
));
return new BackNavigationInfo(backType,
- animLeash,
+ topAppTarget,
screenshotSurface,
screenshotBuffer,
taskWindowConfiguration,
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 5a2cf17..afa4f19 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -544,6 +544,11 @@
return getActivityType() == ACTIVITY_TYPE_RECENTS;
}
+ final boolean isActivityTypeHomeOrRecents() {
+ final int activityType = getActivityType();
+ return activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS;
+ }
+
public boolean isActivityTypeAssistant() {
return getActivityType() == ACTIVITY_TYPE_ASSISTANT;
}
diff --git a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
index f61cc94..a83a033 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 @@
@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 @@
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 092cff3..e845034 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1054,6 +1054,7 @@
mAppTransition.registerListenerLocked(mWmService.mActivityManagerAppTransitionNotifier);
mAppTransition.registerListenerLocked(mFixedRotationTransitionListener);
mAppTransitionController = new AppTransitionController(mWmService, this);
+ mTransitionController.registerLegacyListener(mFixedRotationTransitionListener);
mUnknownAppVisibilityController = new UnknownAppVisibilityController(mWmService, this);
final InputChannel inputChannel = mWmService.mInputManager.monitorInput(
@@ -1111,6 +1112,7 @@
t.remove(mSurfaceControl);
mLastSurfacePosition.set(0, 0);
+ mLastDeltaRotation = Surface.ROTATION_0;
configureSurfaces(t);
@@ -1604,7 +1606,7 @@
*/
@Rotation
int rotationForActivityInDifferentOrientation(@NonNull ActivityRecord r) {
- if (mTransitionController.isShellTransitionsEnabled()) {
+ if (mTransitionController.useShellTransitionsRotation()) {
return ROTATION_UNDEFINED;
}
if (!WindowManagerService.ENABLE_FIXED_ROTATION_TRANSFORM) {
@@ -1645,18 +1647,30 @@
// It has been set and not yet finished.
return true;
}
- if (!r.occludesParent() || r.isVisible()) {
+ if (!r.occludesParent()) {
// While entering or leaving a translucent or floating activity (e.g. dialog style),
// there is a visible activity in the background. Then it still needs rotation animation
// to cover the activity configuration change.
return false;
}
+ if (mTransitionController.isShellTransitionsEnabled()
+ ? mTransitionController.wasVisibleAtStart(r) : r.isVisible()) {
+ // If activity is already visible, then it's not "launching". However, shell-transitions
+ // will make it visible immediately.
+ return false;
+ }
if (checkOpening) {
- if (!mAppTransition.isTransitionSet() || !mOpeningApps.contains(r)) {
- // Apply normal rotation animation in case of the activity set different requested
- // orientation without activity switch, or the transition is unset due to starting
- // window was transferred ({@link #mSkipAppTransitionAnimation}).
- return false;
+ if (mTransitionController.isShellTransitionsEnabled()) {
+ if (!mTransitionController.isCollecting(r)) {
+ return false;
+ }
+ } else {
+ if (!mAppTransition.isTransitionSet() || !mOpeningApps.contains(r)) {
+ // Apply normal rotation animation in case of the activity set different
+ // requested orientation without activity switch, or the transition is unset due
+ // to starting window was transferred ({@link #mSkipAppTransitionAnimation}).
+ return false;
+ }
}
if (r.isState(RESUMED) && !r.getRootTask().mInResumeTopActivity) {
// If the activity is executing or has done the lifecycle callback, use normal
@@ -1733,15 +1747,19 @@
}
void setFixedRotationLaunchingAppUnchecked(@Nullable ActivityRecord r, int rotation) {
+ final boolean useAsyncRotation = !mTransitionController.isShellTransitionsEnabled();
if (mFixedRotationLaunchingApp == null && r != null) {
- mWmService.mDisplayNotificationController.dispatchFixedRotationStarted(this, rotation);
- startAsyncRotation(
- // Delay the hide animation to avoid blinking by clicking navigation bar that
- // may toggle fixed rotation in a short time.
- r == mFixedRotationTransitionListener.mAnimatingRecents /* shouldDebounce */);
+ mWmService.mDisplayNotificationController.dispatchFixedRotationStarted(this,
+ rotation);
+ if (useAsyncRotation) {
+ startAsyncRotation(
+ // Delay the hide animation to avoid blinking by clicking navigation bar
+ // that may toggle fixed rotation in a short time.
+ r == mFixedRotationTransitionListener.mAnimatingRecents);
+ }
} else if (mFixedRotationLaunchingApp != null && r == null) {
mWmService.mDisplayNotificationController.dispatchFixedRotationFinished(this);
- finishAsyncRotationIfPossible();
+ if (useAsyncRotation) finishAsyncRotationIfPossible();
}
mFixedRotationLaunchingApp = r;
}
@@ -1760,7 +1778,8 @@
if (prevRotatedLaunchingApp != null
&& prevRotatedLaunchingApp.getWindowConfiguration().getRotation() == rotation
// It is animating so we can expect there will have a transition callback.
- && prevRotatedLaunchingApp.isAnimating(TRANSITION | PARENTS)) {
+ && (prevRotatedLaunchingApp.isAnimating(TRANSITION | PARENTS)
+ || mTransitionController.inTransition(prevRotatedLaunchingApp))) {
// It may be the case that multiple activities launch consecutively. Because their
// rotation are the same, the transformed state can be shared to avoid duplicating
// the heavy operations. This also benefits that the states of multiple activities
@@ -1798,6 +1817,7 @@
}
// Update directly because the app which will change the orientation of display is ready.
if (mDisplayRotation.updateOrientation(getOrientation(), false /* forceUpdate */)) {
+ mTransitionController.setSeamlessRotation(this);
sendNewConfiguration();
return;
}
@@ -3107,12 +3127,16 @@
mDisplayPolicy.switchUser();
}
- @Override
- void removeIfPossible() {
- if (isAnimating(TRANSITION | PARENTS)
+ private boolean shouldDeferRemoval() {
+ return isAnimating(TRANSITION | PARENTS)
// isAnimating is a legacy transition query and will be removed, so also add a
// check for whether this is in a shell-transition when not using legacy.
- || mTransitionController.inTransition()) {
+ || mTransitionController.isTransitionOnDisplay(this);
+ }
+
+ @Override
+ void removeIfPossible() {
+ if (shouldDeferRemoval()) {
mDeferredRemoval = true;
return;
}
@@ -3129,6 +3153,7 @@
mChangingContainers.clear();
mUnknownAppVisibilityController.clear();
mAppTransition.removeAppTransitionTimeoutCallbacks();
+ mTransitionController.unregisterLegacyListener(mFixedRotationTransitionListener);
handleAnimatingStoppedAndTransition();
mWmService.stopFreezingDisplayLocked();
super.removeImmediately();
@@ -3140,6 +3165,8 @@
mInputMonitor.onDisplayRemoved();
mWmService.mDisplayNotificationController.dispatchDisplayRemoved(this);
mWmService.mAccessibilityController.onDisplayRemoved(mDisplayId);
+ mRootWindowContainer.mTaskSupervisor
+ .getKeyguardController().onDisplayRemoved(mDisplayId);
} finally {
mDisplayReady = false;
}
@@ -3153,7 +3180,8 @@
/** Returns true if a removal action is still being deferred. */
@Override
boolean handleCompleteDeferredRemoval() {
- final boolean stillDeferringRemoval = super.handleCompleteDeferredRemoval();
+ final boolean stillDeferringRemoval =
+ super.handleCompleteDeferredRemoval() || shouldDeferRemoval();
if (!stillDeferringRemoval && mDeferredRemoval) {
removeImmediately();
@@ -4062,7 +4090,7 @@
final boolean renewImeSurface = mImeScreenshot == null
|| mImeScreenshot.getWidth() != mInputMethodWindow.getFrame().width()
|| mImeScreenshot.getHeight() != mInputMethodWindow.getFrame().height();
- if (task != null && !task.isHomeOrRecentsRootTask()) {
+ if (task != null && !task.isActivityTypeHomeOrRecents()) {
SurfaceControl.ScreenshotHardwareBuffer imeBuffer = renewImeSurface
? mWmService.mTaskSnapshotController.snapshotImeFromAttachedTask(task)
: null;
@@ -5761,7 +5789,10 @@
mCurrentOverrideConfigurationChanges = currOverrideConfig.diff(overrideConfiguration);
super.onRequestedOverrideConfigurationChanged(overrideConfiguration);
mCurrentOverrideConfigurationChanges = 0;
- mWmService.setNewDisplayOverrideConfiguration(currOverrideConfig, this);
+ if (mWaitingForConfig) {
+ mWaitingForConfig = false;
+ mWmService.mLastFinishedFreezeSource = "new-config";
+ }
mAtmService.addWindowLayoutReasons(
ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED);
}
@@ -5891,8 +5922,6 @@
forAllRootTasks(t -> {t.removeIfPossible("releaseSelfIfNeeded");});
} else if (getTopRootTask() == null) {
removeIfPossible();
- mRootWindowContainer.mTaskSupervisor
- .getKeyguardController().onDisplayRemoved(mDisplayId);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 1513d8b..30fffd3 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1037,7 +1037,7 @@
break;
case TYPE_NAVIGATION_BAR_PANEL:
// Check for permission if the caller is not the recents component.
- if (!mService.mAtmInternal.isCallerRecents(callingUid)) {
+ if (!mService.mAtmService.isCallerRecents(callingUid)) {
mContext.enforcePermission(
android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
"DisplayPolicy");
@@ -1056,7 +1056,7 @@
if (attrs.providesInsetsTypes != null) {
// Recents component is allowed to add inset types.
- if (!mService.mAtmInternal.isCallerRecents(callingUid)) {
+ if (!mService.mAtmService.isCallerRecents(callingUid)) {
mContext.enforcePermission(
android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
"DisplayPolicy");
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 2a05d05..6438d79 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.util.RotationUtils.deltaRotation;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE;
@@ -39,7 +40,6 @@
import android.annotation.AnimRes;
import android.annotation.IntDef;
-import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.content.ContentResolver;
import android.content.Context;
@@ -50,7 +50,6 @@
import android.content.res.Resources;
import android.database.ContentObserver;
import android.hardware.power.Boost;
-import android.net.Uri;
import android.os.Handler;
import android.os.RemoteException;
import android.os.SystemProperties;
@@ -58,6 +57,7 @@
import android.provider.Settings;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import android.view.IDisplayWindowRotationCallback;
import android.view.IWindowManager;
@@ -77,6 +77,7 @@
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayDeque;
/**
* Defines the mapping between orientation and rotation of a display.
@@ -106,6 +107,7 @@
private final int mDeskDockRotation;
private final int mUndockedHdmiRotation;
private final RotationAnimationPair mTmpRotationAnim = new RotationAnimationPair();
+ private final RotationHistory mRotationHistory = new RotationHistory();
private OrientationListener mOrientationListener;
private StatusBarManagerInternal mStatusBarManagerInternal;
@@ -139,6 +141,8 @@
@VisibleForTesting
int mUpsideDownRotation; // "other" portrait
+ int mLastSensorRotation = -1;
+
private boolean mAllowSeamlessRotationDespiteNavBarMoving;
private int mDeferredRotationPauseCount;
@@ -351,6 +355,7 @@
}
void applyCurrentRotation(@Surface.Rotation int rotation) {
+ mRotationHistory.addRecord(this, rotation);
if (mOrientationListener != null) {
mOrientationListener.setCurrentRotation(rotation);
}
@@ -1149,6 +1154,7 @@
int sensorRotation = mOrientationListener != null
? mOrientationListener.getProposedRotation() // may be -1
: -1;
+ mLastSensorRotation = sensorRotation;
if (sensorRotation < 0) {
sensorRotation = lastRotation;
}
@@ -1537,6 +1543,15 @@
pw.println(" mUndockedHdmiRotation=" + Surface.rotationToString(mUndockedHdmiRotation));
pw.println(prefix + " mLidOpenRotation=" + Surface.rotationToString(mLidOpenRotation));
pw.println(prefix + " mFixedToUserRotation=" + isFixedToUserRotation());
+
+ if (!mRotationHistory.mRecords.isEmpty()) {
+ pw.println();
+ pw.println(prefix + " RotationHistory");
+ prefix = " " + prefix;
+ for (RotationHistory.Record r : mRotationHistory.mRecords) {
+ r.dump(prefix, pw);
+ }
+ }
}
void dumpDebug(ProtoOutputStream proto, long fieldId) {
@@ -1650,9 +1665,69 @@
}
}
- @VisibleForTesting
- interface ContentObserverRegister {
- void registerContentObserver(Uri uri, boolean notifyForDescendants,
- ContentObserver observer, @UserIdInt int userHandle);
+ private static class RotationHistory {
+ private static final int MAX_SIZE = 8;
+ private static class Record {
+ final @Surface.Rotation int mFromRotation;
+ final @Surface.Rotation int mToRotation;
+ final @Surface.Rotation int mUserRotation;
+ final @WindowManagerPolicy.UserRotationMode int mUserRotationMode;
+ final int mSensorRotation;
+ final boolean mIgnoreOrientationRequest;
+ final String mNonDefaultRequestingTaskDisplayArea;
+ final String mLastOrientationSource;
+ final @ActivityInfo.ScreenOrientation int mSourceOrientation;
+ final long mTimestamp = System.currentTimeMillis();
+
+ Record(DisplayRotation dr, int fromRotation, int toRotation) {
+ mFromRotation = fromRotation;
+ mToRotation = toRotation;
+ mUserRotation = dr.mUserRotation;
+ mUserRotationMode = dr.mUserRotationMode;
+ final OrientationListener listener = dr.mOrientationListener;
+ mSensorRotation = (listener == null || !listener.mEnabled)
+ ? -2 /* disabled */ : dr.mLastSensorRotation;
+ final DisplayContent dc = dr.mDisplayContent;
+ mIgnoreOrientationRequest = dc.mIgnoreOrientationRequest;
+ final TaskDisplayArea requestingTda = dc.getOrientationRequestingTaskDisplayArea();
+ mNonDefaultRequestingTaskDisplayArea = requestingTda == null
+ ? "none" : requestingTda != dc.getDefaultTaskDisplayArea()
+ ? requestingTda.toString() : null;
+ final WindowContainer<?> source = dc.getLastOrientationSource();
+ if (source != null) {
+ mLastOrientationSource = source.toString();
+ mSourceOrientation = source.mOrientation;
+ } else {
+ mLastOrientationSource = null;
+ mSourceOrientation = SCREEN_ORIENTATION_UNSET;
+ }
+ }
+
+ void dump(String prefix, PrintWriter pw) {
+ pw.println(prefix + TimeUtils.logTimeOfDay(mTimestamp)
+ + " " + Surface.rotationToString(mFromRotation)
+ + " to " + Surface.rotationToString(mToRotation));
+ pw.println(prefix + " source=" + mLastOrientationSource
+ + " " + ActivityInfo.screenOrientationToString(mSourceOrientation));
+ pw.println(prefix + " mode="
+ + WindowManagerPolicy.userRotationModeToString(mUserRotationMode)
+ + " user=" + Surface.rotationToString(mUserRotation)
+ + " sensor=" + Surface.rotationToString(mSensorRotation));
+ if (mIgnoreOrientationRequest) pw.println(prefix + " ignoreRequest=true");
+ if (mNonDefaultRequestingTaskDisplayArea != null) {
+ pw.println(prefix + " requestingTda=" + mNonDefaultRequestingTaskDisplayArea);
+ }
+ }
+ }
+
+ final ArrayDeque<Record> mRecords = new ArrayDeque<>(MAX_SIZE);
+
+ void addRecord(DisplayRotation dr, int toRotation) {
+ if (mRecords.size() >= MAX_SIZE) {
+ mRecords.removeFirst();
+ }
+ final int fromRotation = dr.mDisplayContent.getWindowConfiguration().getRotation();
+ mRecords.addLast(new Record(dr, fromRotation, toRotation));
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index e0887e1..4ce0581 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -179,11 +179,9 @@
final SurfaceControl.Transaction transaction = mDragState.mTransaction;
transaction.setAlpha(surfaceControl, mDragState.mOriginalAlpha);
- transaction.setPosition(
- surfaceControl, touchX - thumbCenterX, touchY - thumbCenterY);
transaction.show(surfaceControl);
displayContent.reparentToOverlay(transaction, surfaceControl);
- callingWin.scheduleAnimation();
+ mDragState.updateDragSurfaceLocked(true, touchX, touchY);
if (SHOW_LIGHT_TRANSACTIONS) {
Slog.i(TAG_WM, "<<< CLOSE TRANSACTION performDrag");
}
diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
index 8db4306..2ab08e6 100644
--- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java
+++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
@@ -156,6 +156,7 @@
final IWindow mClient;
@Nullable final WindowState mHostWindowState;
@Nullable final ActivityRecord mHostActivityRecord;
+ final String mName;
final int mOwnerUid;
final int mOwnerPid;
final WindowManagerService mWmService;
@@ -186,7 +187,7 @@
*/
EmbeddedWindow(Session session, WindowManagerService service, IWindow clientToken,
WindowState hostWindowState, int ownerUid, int ownerPid, int windowType,
- int displayId, IBinder focusGrantToken) {
+ int displayId, IBinder focusGrantToken, String inputHandleName) {
mSession = session;
mWmService = service;
mClient = clientToken;
@@ -198,14 +199,15 @@
mWindowType = windowType;
mDisplayId = displayId;
mFocusGrantToken = focusGrantToken;
+ final String hostWindowName =
+ (mHostWindowState != null) ? "-" + mHostWindowState.getWindowTag().toString()
+ : "";
+ mName = "Embedded{" + inputHandleName + hostWindowName + "}";
}
@Override
public String toString() {
- final String hostWindowName = (mHostWindowState != null)
- ? mHostWindowState.getWindowTag().toString() : "Internal";
- return "EmbeddedWindow{ u" + UserHandle.getUserId(mOwnerUid) + " " + hostWindowName
- + "}";
+ return mName;
}
InputApplicationHandle getApplicationHandle() {
diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
index 8d3e071..aa5e20d 100644
--- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
+++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
@@ -104,7 +104,8 @@
for (int i = mTaskFragment.mChildren.size() - 1; i >= 0; --i) {
final WindowContainer child = mTaskFragment.mChildren.get(i);
final TaskFragment childTaskFragment = child.asTaskFragment();
- if (childTaskFragment != null && childTaskFragment.topRunningActivity() != null) {
+ if (childTaskFragment != null
+ && childTaskFragment.getTopNonFinishingActivity() != null) {
childTaskFragment.updateActivityVisibilities(starting, configChanges,
preserveWindows, notifyClients);
mBehindFullyOccludedContainer |=
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 2f95119..d28dfd5 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -144,15 +144,21 @@
getStatusControlTarget(focusedWin, false /* fake */);
final InsetsControlTarget navControlTarget =
getNavControlTarget(focusedWin, false /* fake */);
+ final WindowState notificationShade = mPolicy.getNotificationShade();
+ final WindowState topApp = mPolicy.getTopFullscreenOpaqueWindow();
mStateController.onBarControlTargetChanged(
statusControlTarget,
statusControlTarget == mDummyControlTarget
? getStatusControlTarget(focusedWin, true /* fake */)
- : null,
+ : statusControlTarget == notificationShade
+ ? getStatusControlTarget(topApp, true /* fake */)
+ : null,
navControlTarget,
navControlTarget == mDummyControlTarget
? getNavControlTarget(focusedWin, true /* fake */)
- : null);
+ : navControlTarget == notificationShade
+ ? getNavControlTarget(topApp, true /* fake */)
+ : null);
mStatusBar.updateVisibility(statusControlTarget, ITYPE_STATUS_BAR);
mNavBar.updateVisibility(navControlTarget, ITYPE_NAVIGATION_BAR);
}
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 5c8502b..c55af9b 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -235,7 +235,7 @@
*/
void keyguardGoingAway(int displayId, int flags) {
final KeyguardDisplayState state = getDisplayState(displayId);
- if (!state.mKeyguardShowing) {
+ if (!state.mKeyguardShowing || state.mKeyguardGoingAway) {
return;
}
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "keyguardGoingAway");
diff --git a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
index a3eb980..61f9fe2 100644
--- a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
@@ -51,6 +51,16 @@
}
@Override
+ public boolean getShowBackground() {
+ return mSpec.getShowBackground();
+ }
+
+ @Override
+ public int getBackgroundColor() {
+ return mSpec.getBackgroundColor();
+ }
+
+ @Override
public void startAnimation(SurfaceControl animationLeash, Transaction t,
@AnimationType int type, @NonNull OnAnimationFinishedCallback finishCallback) {
mAnimator.startAnimation(mSpec, animationLeash, t,
@@ -97,6 +107,20 @@
}
/**
+ * @see AnimationAdapter#getShowBackground
+ */
+ default boolean getShowBackground() {
+ return false;
+ }
+
+ /**
+ * @see AnimationAdapter#getBackgroundColor
+ */
+ default int getBackgroundColor() {
+ return 0;
+ }
+
+ /**
* @see AnimationAdapter#getStatusBarTransitionsStartTime
*/
default long calculateStatusBarTransitionStartTime() {
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index d4a7a5d..e259238 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -529,7 +529,7 @@
*/
void notifyTaskPersisterLocked(Task task, boolean flush) {
final Task rootTask = task != null ? task.getRootTask() : null;
- if (rootTask != null && rootTask.isHomeOrRecentsRootTask()) {
+ if (rootTask != null && rootTask.isActivityTypeHomeOrRecents()) {
// Never persist the home or recents task.
return;
}
@@ -563,7 +563,7 @@
private static boolean shouldPersistTaskLocked(Task task) {
final Task rootTask = task.getRootTask();
- return task.isPersistable && (rootTask == null || !rootTask.isHomeOrRecentsRootTask());
+ return task.isPersistable && (rootTask == null || !rootTask.isActivityTypeHomeOrRecents());
}
void onSystemReadyLocked() {
@@ -994,7 +994,7 @@
}
final Task rootTask = task.getRootTask();
if ((task.isPersistable || task.inRecents)
- && (rootTask == null || !rootTask.isHomeOrRecentsRootTask())) {
+ && (rootTask == null || !rootTask.isActivityTypeHomeOrRecents())) {
if (TaskPersister.DEBUG) Slog.d(TAG, "adding to persistentTaskIds task=" + task);
persistentTaskIds.add(task.mTaskId);
} else {
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 1183094..30906e5 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -18,8 +18,7 @@
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.view.RemoteAnimationTarget.MODE_CLOSING;
@@ -129,7 +128,6 @@
private ActivityRecord mTargetActivityRecord;
private DisplayContent mDisplayContent;
private int mTargetActivityType;
- private Rect mMinimizedHomeBounds = new Rect();
// We start the RecentsAnimationController in a pending-start state since we need to wait for
// the wallpaper/activity to draw before we can give control to the handler to start animating
@@ -480,11 +478,6 @@
mDisplayContent.setLayoutNeeded();
}
- // Save the minimized home height
- final Task rootHomeTask =
- mDisplayContent.getDefaultTaskDisplayArea().getRootHomeTask();
- mMinimizedHomeBounds = rootHomeTask != null ? rootHomeTask.getBounds() : null;
-
mService.mWindowPlacerLocked.performSurfacePlacement();
mDisplayContent.mFixedRotationTransitionListener.onStartRecentsAnimation(targetActivity);
@@ -502,9 +495,7 @@
*/
private boolean skipAnimation(Task task) {
final WindowConfiguration config = task.getWindowConfiguration();
- return task.isAlwaysOnTop()
- || config.tasksAreFloating()
- || config.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+ return task.isAlwaysOnTop() || config.tasksAreFloating();
}
@VisibleForTesting
@@ -568,10 +559,6 @@
// insets for the target app window after a rotation
mDisplayContent.performLayout(false /* initial */, false /* updateInputWindows */);
- final Rect minimizedHomeBounds = mTargetActivityRecord != null
- && mTargetActivityRecord.inSplitScreenSecondaryWindowingMode()
- ? mMinimizedHomeBounds
- : null;
final Rect contentInsets;
final WindowState targetAppMainWindow = getTargetAppMainWindow();
if (targetAppMainWindow != null) {
@@ -585,7 +572,7 @@
contentInsets = mTmpRect;
}
mRunner.onAnimationStart(mController, appTargets, wallpaperTargets, contentInsets,
- minimizedHomeBounds);
+ null);
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
"startAnimation(): Notify animation start: %s",
mPendingAnimations.stream()
@@ -623,16 +610,17 @@
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
final TaskAnimationAdapter adapter = mPendingAnimations.get(i);
final Task task = adapter.mTask;
- final boolean isSplitScreenSecondary =
- task.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
- if (task.isHomeOrRecentsRootTask()
- // TODO(b/178449492): Will need to update for the new split screen mode once
- // it's ready.
- // Skip if the task is the secondary split screen and in landscape.
- || (isSplitScreenSecondary && isDisplayLandscape)) {
+ final TaskFragment adjacentTask = task.getRootTask().getAdjacentTaskFragment();
+ final boolean inSplitScreen = task.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW
+ && adjacentTask != null;
+ if (task.isActivityTypeHomeOrRecents()
+ // Skip if the task is in split screen and in landscape.
+ || (inSplitScreen && isDisplayLandscape)
+ // Skip if the task is the top task in split screen.
+ || (inSplitScreen && task.getBounds().top < adjacentTask.getBounds().top)) {
continue;
}
- shouldTranslateNavBar = isSplitScreenSecondary;
+ shouldTranslateNavBar = inSplitScreen;
mNavBarAttachedApp = task.getTopVisibleActivity();
break;
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index ee03d02..d535018 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -637,36 +637,6 @@
return null;
}
- /**
- * Set new display override config. If called for the default display, global configuration
- * will also be updated.
- */
- void setDisplayOverrideConfigurationIfNeeded(Configuration newConfiguration,
- @NonNull DisplayContent displayContent) {
-
- final Configuration currentConfig = displayContent.getRequestedOverrideConfiguration();
- final boolean configChanged = currentConfig.diff(newConfiguration) != 0;
- if (!configChanged) {
- return;
- }
-
- displayContent.onRequestedOverrideConfigurationChanged(newConfiguration);
-
- if (displayContent.getDisplayId() == DEFAULT_DISPLAY) {
- // Override configuration of the default display duplicates global config. In this case
- // we also want to update the global config.
- setGlobalConfigurationIfNeeded(newConfiguration);
- }
- }
-
- private void setGlobalConfigurationIfNeeded(Configuration newConfiguration) {
- final boolean configChanged = getConfiguration().diff(newConfiguration) != 0;
- if (!configChanged) {
- return;
- }
- onConfigurationChanged(newConfiguration);
- }
-
@Override
void dispatchConfigurationToChild(DisplayContent child, Configuration config) {
if (child.isDefaultDisplay) {
@@ -981,29 +951,6 @@
mWmService.checkDrawnWindowsLocked();
}
- final int N = mWmService.mPendingRemove.size();
- if (N > 0) {
- if (mWmService.mPendingRemoveTmp.length < N) {
- mWmService.mPendingRemoveTmp = new WindowState[N + 10];
- }
- mWmService.mPendingRemove.toArray(mWmService.mPendingRemoveTmp);
- mWmService.mPendingRemove.clear();
- ArrayList<DisplayContent> displayList = new ArrayList();
- for (i = 0; i < N; i++) {
- final WindowState w = mWmService.mPendingRemoveTmp[i];
- w.removeImmediately();
- final DisplayContent displayContent = w.getDisplayContent();
- if (displayContent != null && !displayList.contains(displayContent)) {
- displayList.add(displayContent);
- }
- }
-
- for (int j = displayList.size() - 1; j >= 0; --j) {
- final DisplayContent dc = displayList.get(j);
- dc.assignWindowLayers(true /*setLayoutNeeded*/);
- }
- }
-
forAllDisplays(dc -> {
dc.getInputMonitor().updateInputWindowsLw(true /*force*/);
dc.updateSystemGestureExclusion();
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 7c5144e..cd8ddf4 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -69,6 +69,7 @@
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.InsetsVisibilities;
+import android.view.OnBackInvokedDispatcher;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.view.View;
@@ -837,7 +838,7 @@
@Override
public void grantInputChannel(int displayId, SurfaceControl surface,
IWindow window, IBinder hostInputToken, int flags, int privateFlags, int type,
- IBinder focusGrantToken, InputChannel outInputChannel) {
+ IBinder focusGrantToken, String inputHandleName, InputChannel outInputChannel) {
if (hostInputToken == null && !mCanAddInternalSystemWindow) {
// Callers without INTERNAL_SYSTEM_WINDOW permission cannot grant input channel to
// embedded windows without providing a host window input token
@@ -853,7 +854,8 @@
try {
mService.grantInputChannel(this, mUid, mPid, displayId, surface, window, hostInputToken,
flags, mCanAddInternalSystemWindow ? privateFlags : 0,
- mCanAddInternalSystemWindow ? type : 0, focusGrantToken, outInputChannel);
+ mCanAddInternalSystemWindow ? type : 0, focusGrantToken, inputHandleName,
+ outInputChannel);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -904,15 +906,17 @@
}
@Override
- public void setOnBackInvokedCallback(IWindow window,
- IOnBackInvokedCallback onBackInvokedCallback) throws RemoteException {
+ public void setOnBackInvokedCallback(
+ IWindow window,
+ IOnBackInvokedCallback onBackInvokedCallback,
+ @OnBackInvokedDispatcher.Priority int priority) throws RemoteException {
synchronized (mService.mGlobalLock) {
WindowState windowState = mService.windowForClientLocked(this, window, false);
if (windowState == null) {
Slog.e(TAG_WM,
"setOnBackInvokedCallback(): Can't find window state for window:" + window);
} else {
- windowState.setOnBackInvokedCallback(onBackInvokedCallback);
+ windowState.setOnBackInvokedCallback(onBackInvokedCallback, priority);
}
}
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index b84ef77..6df54cd 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -2711,7 +2711,7 @@
// they extend past their root task and sysui uses the root task surface to control
// cropping.
// TODO(b/158242495): get rid of this when drag/drop can use surface bounds.
- if (isActivityTypeHome() || isActivityTypeRecents()) {
+ if (isActivityTypeHomeOrRecents()) {
// Make sure this is the top-most non-organizer root task (if not top-most, it means
// another translucent task could be above this, so this needs to stay cropped.
final Task rootTask = getRootTask();
@@ -3306,7 +3306,7 @@
if (control != null) {
// We let the transition to be controlled by RecentsAnimation, and callback task's
// RemoteAnimationTarget for remote runner to animate.
- if (enter && !isHomeOrRecentsRootTask()) {
+ if (enter && !isActivityTypeHomeOrRecents()) {
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
"applyAnimationUnchecked, control: %s, task: %s, transit: %s",
control, asTask(), AppTransition.appTransitionOldToString(transit));
@@ -4591,10 +4591,6 @@
!PRESERVE_WINDOWS);
}
- final boolean isHomeOrRecentsRootTask() {
- return isActivityTypeHome() || isActivityTypeRecents();
- }
-
final boolean isOnHomeDisplay() {
return getDisplayId() == DEFAULT_DISPLAY;
}
@@ -5044,7 +5040,7 @@
// The transition animation and starting window are not needed if {@code allowMoveToFront}
// is false, because the activity won't be visible.
- if ((!isHomeOrRecentsRootTask() || hasActivity()) && allowMoveToFront) {
+ if ((!isActivityTypeHomeOrRecents() || hasActivity()) && allowMoveToFront) {
final DisplayContent dc = mDisplayContent;
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
"Prepare open transition: starting " + r);
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 177d2e6..c880aba 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -25,6 +25,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.pm.ActivityInfo.FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING;
import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
@@ -95,6 +96,7 @@
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.util.function.pooled.PooledPredicate;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -102,6 +104,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -505,6 +508,56 @@
}
/**
+ * Checks if the organized task fragment is allowed to have the specified activity, which is
+ * allowed if an activity allows embedding in untrusted mode, or if the trusted mode can be
+ * enabled.
+ * @see #isAllowedToEmbedActivityInTrustedMode(ActivityRecord)
+ */
+ boolean isAllowedToEmbedActivity(@NonNull ActivityRecord a) {
+ if ((a.info.flags & FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING)
+ == FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING) {
+ return true;
+ }
+
+ return isAllowedToEmbedActivityInTrustedMode(a);
+ }
+
+ /**
+ * Checks if the organized task fragment is allowed to embed activity in fully trusted mode,
+ * which means that all transactions are allowed. This is supported in the following cases:
+ * <li>the activity belongs to the same app as the organizer host;</li>
+ * <li>the activity has declared the organizer host as trusted explicitly via known
+ * certificate.</li>
+ */
+ private boolean isAllowedToEmbedActivityInTrustedMode(@NonNull ActivityRecord a) {
+ if (mTaskFragmentOrganizerUid == a.getUid()) {
+ // Activities from the same UID can be embedded freely by the host.
+ return true;
+ }
+
+ Set<String> knownActivityEmbeddingCerts = a.info.getKnownActivityEmbeddingCerts();
+ if (knownActivityEmbeddingCerts.isEmpty()) {
+ // An application must either declare that it allows untrusted embedding, or specify
+ // a set of app certificates that are allowed to embed it in trusted mode.
+ return false;
+ }
+
+ AndroidPackage hostPackage = mAtmService.getPackageManagerInternalLocked()
+ .getPackage(mTaskFragmentOrganizerUid);
+
+ return hostPackage != null && hostPackage.getSigningDetails().hasAncestorOrSelfWithDigest(
+ knownActivityEmbeddingCerts);
+ }
+
+ /**
+ * Checks if all activities in the task fragment are allowed to be embedded in trusted mode.
+ * @see #isAllowedToEmbedActivityInTrustedMode(ActivityRecord)
+ */
+ boolean isAllowedToBeEmbeddedInTrustedMode() {
+ return forAllActivities(this::isAllowedToEmbedActivityInTrustedMode);
+ }
+
+ /**
* Returns the TaskFragment that is being organized, which could be this or the ascendant
* TaskFragment.
*/
@@ -945,6 +998,10 @@
// we still want to check if the visibility of other windows have changed (e.g. bringing
// a fullscreen window forward to cover another freeform activity.)
if (taskDisplayArea.inMultiWindowMode()) {
+ if (taskDisplayArea.mDisplayContent != null
+ && taskDisplayArea.mDisplayContent.mFocusedApp != next) {
+ taskDisplayArea.mDisplayContent.setFocusedApp(next);
+ }
taskDisplayArea.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
false /* preserveWindows */, true /* notifyClients */);
}
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index 123ca88..19f921d 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -294,14 +294,28 @@
}
}
- /** Gets the {@link RemoteAnimationDefinition} set on the given organizer if exists. */
+ /**
+ * Gets the {@link RemoteAnimationDefinition} set on the given organizer if exists. Returns
+ * {@code null} if it doesn't, or if the organizer has activity(ies) embedded in untrusted mode.
+ */
@Nullable
public RemoteAnimationDefinition getRemoteAnimationDefinition(
ITaskFragmentOrganizer organizer) {
synchronized (mGlobalLock) {
final TaskFragmentOrganizerState organizerState =
mTaskFragmentOrganizerState.get(organizer.asBinder());
- return organizerState != null ? organizerState.mRemoteAnimationDefinition : null;
+ if (organizerState == null) {
+ return null;
+ }
+ for (TaskFragment tf : organizerState.mOrganizedTaskFragments) {
+ if (!tf.isAllowedToBeEmbeddedInTrustedMode()) {
+ // Disable client-driven animations for organizer if at least one of the
+ // embedded task fragments is not embedding in trusted mode.
+ // TODO(b/197364677): replace with a stub or Shell-driven one instead of skip?
+ return null;
+ }
+ }
+ return organizerState.mRemoteAnimationDefinition;
}
}
diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java
index 4d3219d..8f24f26 100644
--- a/services/core/java/com/android/server/wm/TaskPositioningController.java
+++ b/services/core/java/com/android/server/wm/TaskPositioningController.java
@@ -20,33 +20,22 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.annotation.Nullable;
-import android.app.IActivityTaskManager;
import android.graphics.Point;
import android.graphics.Rect;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.RemoteException;
import android.util.Slog;
import android.view.Display;
import android.view.IWindow;
import android.view.InputWindowHandle;
import android.view.SurfaceControl;
-import com.android.internal.annotations.GuardedBy;
-import com.android.server.input.InputManagerService;
-
/**
* Controller for task positioning by drag.
*/
class TaskPositioningController {
private final WindowManagerService mService;
- private final InputManagerService mInputManager;
- private final IActivityTaskManager mActivityManager;
- private final Handler mHandler;
private SurfaceControl mInputSurface;
private DisplayContent mPositioningDisplay;
- @GuardedBy("WindowManagerSerivce.mWindowMap")
private @Nullable TaskPositioner mTaskPositioner;
private final Rect mTmpClipRect = new Rect();
@@ -61,12 +50,8 @@
return mTaskPositioner != null ? mTaskPositioner.mDragWindowHandle : null;
}
- TaskPositioningController(WindowManagerService service, InputManagerService inputManager,
- IActivityTaskManager activityManager, Looper looper) {
+ TaskPositioningController(WindowManagerService service) {
mService = service;
- mInputManager = inputManager;
- mActivityManager = activityManager;
- mHandler = new Handler(looper);
mTransaction = service.mTransactionFactory.get();
}
@@ -121,15 +106,13 @@
win, false /*resize*/, false /*preserveOrientation*/, startX, startY)) {
return false;
}
+ mService.mAtmService.setFocusedTask(win.getTask().mTaskId);
}
- try {
- mActivityManager.setFocusedTask(win.getTask().mTaskId);
- } catch(RemoteException e) {}
return true;
}
void handleTapOutsideTask(DisplayContent displayContent, int x, int y) {
- mHandler.post(() -> {
+ mService.mH.post(() -> {
synchronized (mService.mGlobalLock) {
final Task task = displayContent.findTaskForResizePoint(x, y);
if (task != null) {
@@ -142,10 +125,7 @@
task.preserveOrientationOnResize(), x, y)) {
return;
}
- try {
- mActivityManager.setFocusedTask(task.mTaskId);
- } catch (RemoteException e) {
- }
+ mService.mAtmService.setFocusedTask(task.mTaskId);
}
}
});
@@ -187,7 +167,7 @@
&& displayContent.mCurrentFocus.mActivityRecord == win.mActivityRecord) {
transferFocusFromWin = displayContent.mCurrentFocus;
}
- if (!mInputManager.transferTouchFocus(
+ if (!mService.mInputManager.transferTouchFocus(
transferFocusFromWin.mInputChannel, mTaskPositioner.mClientChannel,
false /* isDragDrop */)) {
Slog.e(TAG_WM, "startPositioningLocked: Unable to transfer touch focus");
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index bf11ebc..a9add59 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -196,15 +196,21 @@
snapshotTasks(tasks, false /* allowSnapshotHome */);
}
- void recordTaskSnapshot(Task task, boolean allowSnapshotHome) {
+ /**
+ * This is different than {@link #recordTaskSnapshot(Task, boolean)} because it doesn't store
+ * the snapshot to the cache and returns the TaskSnapshot immediately.
+ *
+ * This is only used for testing so the snapshot content can be verified.
+ */
+ @VisibleForTesting
+ TaskSnapshot captureTaskSnapshot(Task task, boolean snapshotHome) {
final TaskSnapshot snapshot;
- final boolean snapshotHome = allowSnapshotHome && task.isActivityTypeHome();
if (snapshotHome) {
snapshot = snapshotTask(task);
} else {
switch (getSnapshotMode(task)) {
case SNAPSHOT_MODE_NONE:
- return;
+ return null;
case SNAPSHOT_MODE_APP_THEME:
snapshot = drawAppThemeSnapshot(task);
break;
@@ -216,19 +222,27 @@
break;
}
}
- if (snapshot != null) {
- final HardwareBuffer buffer = snapshot.getHardwareBuffer();
- if (buffer.getWidth() == 0 || buffer.getHeight() == 0) {
- buffer.close();
- Slog.e(TAG, "Invalid task snapshot dimensions " + buffer.getWidth() + "x"
- + buffer.getHeight());
- } else {
- mCache.putSnapshot(task, snapshot);
- // Don't persist or notify the change for the temporal snapshot.
- if (!snapshotHome) {
- mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);
- task.onSnapshotChanged(snapshot);
- }
+ return snapshot;
+ }
+
+ void recordTaskSnapshot(Task task, boolean allowSnapshotHome) {
+ final boolean snapshotHome = allowSnapshotHome && task.isActivityTypeHome();
+ final TaskSnapshot snapshot = captureTaskSnapshot(task, snapshotHome);
+ if (snapshot == null) {
+ return;
+ }
+
+ final HardwareBuffer buffer = snapshot.getHardwareBuffer();
+ if (buffer.getWidth() == 0 || buffer.getHeight() == 0) {
+ buffer.close();
+ Slog.e(TAG, "Invalid task snapshot dimensions " + buffer.getWidth() + "x"
+ + buffer.getHeight());
+ } else {
+ mCache.putSnapshot(task, snapshot);
+ // Don't persist or notify the change for the temporal snapshot.
+ if (!snapshotHome) {
+ mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);
+ task.onSnapshotChanged(snapshot);
}
}
}
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index d86382d..9f2188b 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -158,8 +158,8 @@
/** The final animation targets derived from participants after promotion. */
private ArrayList<WindowContainer> mTargets;
- /** The main display running this transition. */
- private DisplayContent mTargetDisplay;
+ /** The displays that this transition is running on. */
+ private final ArrayList<DisplayContent> mTargetDisplays = new ArrayList<>();
/**
* Set of participating windowtokens (activity/wallpaper) which are visible at the end of
@@ -209,6 +209,16 @@
return mTransientLaunches != null && mTransientLaunches.contains(activity);
}
+ boolean isOnDisplay(@NonNull DisplayContent dc) {
+ return mTargetDisplays.contains(dc);
+ }
+
+ void setSeamlessRotation(@NonNull WindowContainer wc) {
+ final ChangeInfo info = mChanges.get(wc);
+ if (info == null) return;
+ info.mFlags = info.mFlags | ChangeInfo.FLAG_SEAMLESS_ROTATION;
+ }
+
@VisibleForTesting
int getSyncId() {
return mSyncId;
@@ -274,6 +284,9 @@
mChanges.put(wc, info);
}
mParticipants.add(wc);
+ if (wc.getDisplayContent() != null && !mTargetDisplays.contains(wc.getDisplayContent())) {
+ mTargetDisplays.add(wc.getDisplayContent());
+ }
if (info.mShowWallpaper) {
// Collect the wallpaper token (for isWallpaper(wc)) so it is part of the sync set.
final WindowState wallpaper =
@@ -510,15 +523,23 @@
dc.getInputMonitor().setActiveRecents(null /* activity */, null /* layer */);
}
- final AsyncRotationController asyncRotationController =
- mTargetDisplay.getAsyncRotationController();
- if (asyncRotationController != null) {
- asyncRotationController.onTransitionFinished();
- }
- // Transient-launch activities cannot be IME target (WindowState#canBeImeTarget),
- // so re-compute in case the IME target is changed after transition.
- if (mTransientLaunches != null) {
- mTargetDisplay.computeImeTarget(true /* updateImeTarget */);
+ for (int i = 0; i < mTargetDisplays.size(); ++i) {
+ final DisplayContent dc = mTargetDisplays.get(i);
+ final AsyncRotationController asyncRotationController = dc.getAsyncRotationController();
+ if (asyncRotationController != null) {
+ asyncRotationController.onTransitionFinished();
+ }
+ if (mTransientLaunches != null) {
+ // Transient-launch activities cannot be IME target (WindowState#canBeImeTarget),
+ // so re-compute in case the IME target is changed after transition.
+ for (int t = 0; t < mTransientLaunches.size(); ++t) {
+ if (mTransientLaunches.valueAt(t).getDisplayContent() == dc) {
+ dc.computeImeTarget(true /* updateImeTarget */);
+ break;
+ }
+ }
+ }
+ dc.handleCompleteDeferredRemoval();
}
}
@@ -549,19 +570,13 @@
Slog.e(TAG, "Unexpected Sync ID " + syncId + ". Expected " + mSyncId);
return;
}
- boolean hasWallpaper = false;
- DisplayContent dc = null;
- for (int i = mParticipants.size() - 1; i >= 0; --i) {
- final WindowContainer<?> wc = mParticipants.valueAt(i);
- if (dc == null && wc.mDisplayContent != null) {
- dc = wc.mDisplayContent;
- }
- if (!hasWallpaper && isWallpaper(wc)) {
- hasWallpaper = true;
- }
+ if (mTargetDisplays.isEmpty()) {
+ mTargetDisplays.add(mController.mAtm.mRootWindowContainer.getDefaultDisplay());
}
- if (dc == null) dc = mController.mAtm.mRootWindowContainer.getDefaultDisplay();
- mTargetDisplay = dc;
+ // While there can be multiple DC's involved. For now, we just use the first one as
+ // the "primary" one for most things. Eventually, this will need to change, but, for the
+ // time being, we don't have full cross-display transitions so it isn't a problem.
+ final DisplayContent dc = mTargetDisplays.get(0);
if (mState == STATE_ABORT) {
mController.abort(this);
@@ -571,8 +586,11 @@
return;
}
// Ensure that wallpaper visibility is updated with the latest wallpaper target.
- if (hasWallpaper) {
- dc.mWallpaperController.adjustWallpaperWindows();
+ for (int i = mParticipants.size() - 1; i >= 0; --i) {
+ final WindowContainer<?> wc = mParticipants.valueAt(i);
+ if (isWallpaper(wc) && wc.getDisplayContent() != null) {
+ wc.getDisplayContent().mWallpaperController.adjustWallpaperWindows();
+ }
}
mState = STATE_PLAYING;
@@ -819,7 +837,7 @@
// the bottom of the screen, so we need to animate it.
for (int i = 0; i < mTargets.size(); ++i) {
final Task task = mTargets.get(i).asTask();
- if (task == null || !task.isHomeOrRecentsRootTask()) continue;
+ if (task == null || !task.isActivityTypeHomeOrRecents()) continue;
animate = task.isVisibleRequested();
break;
}
@@ -1122,6 +1140,15 @@
// hardware-screen-level surfaces.
return asDC.getWindowingLayer();
}
+ if (!wc.mTransitionController.useShellTransitionsRotation()) {
+ final WindowToken asToken = wc.asWindowToken();
+ if (asToken != null) {
+ // WindowTokens can have a fixed-rotation applied to them. In the current
+ // implementation this fact is hidden from the player, so we must create a leash.
+ final SurfaceControl leash = asToken.getOrCreateFixedRotationLeash();
+ if (leash != null) return leash;
+ }
+ }
return wc.getSurfaceControl();
}
@@ -1224,6 +1251,8 @@
final ActivityRecord topMostActivity = task.getTopMostActivity();
change.setAllowEnterPip(topMostActivity != null
&& topMostActivity.checkEnterPictureInPictureAppOpsState());
+ } else if ((info.mFlags & ChangeInfo.FLAG_SEAMLESS_ROTATION) != 0) {
+ change.setRotationAnimation(ROTATION_ANIMATION_SEAMLESS);
}
final ActivityRecord activityRecord = target.asActivityRecord();
if (activityRecord != null) {
@@ -1337,6 +1366,21 @@
@VisibleForTesting
static class ChangeInfo {
+ private static final int FLAG_NONE = 0;
+
+ /**
+ * When set, the associated WindowContainer has been explicitly requested to be a
+ * seamless rotation. This is currently only used by DisplayContent during fixed-rotation.
+ */
+ private static final int FLAG_SEAMLESS_ROTATION = 1;
+
+ @IntDef(prefix = { "FLAG_" }, value = {
+ FLAG_NONE,
+ FLAG_SEAMLESS_ROTATION
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface Flag {}
+
// Usually "post" change state.
WindowContainer mParent;
@@ -1350,6 +1394,9 @@
int mRotation = ROTATION_UNDEFINED;
@ActivityInfo.Config int mKnownConfigChanges;
+ /** These are just extra info. They aren't used for change-detection. */
+ @Flag int mFlags = FLAG_NONE;
+
ChangeInfo(@NonNull WindowContainer origState) {
mVisible = origState.isVisibleRequested();
mWindowingMode = origState.getWindowingMode();
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 60307ce..c267cba 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -34,6 +34,7 @@
import android.os.IRemoteCallback;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.util.ArrayMap;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
@@ -58,6 +59,10 @@
class TransitionController {
private static final String TAG = "TransitionController";
+ /** Whether to use shell-transitions rotation instead of fixed-rotation. */
+ private static final boolean SHELL_TRANSITIONS_ROTATION =
+ SystemProperties.getBoolean("persist.debug.shell_transit_rotate", false);
+
/** The same as legacy APP_TRANSITION_TIMEOUT_MS. */
private static final int DEFAULT_TIMEOUT_MS = 5000;
/** Less duration for CHANGE type because it does not involve app startup. */
@@ -203,6 +208,11 @@
return mTransitionPlayer != null;
}
+ /** @return {@code true} if using shell-transitions rotation instead of fixed-rotation. */
+ boolean useShellTransitionsRotation() {
+ return isShellTransitionsEnabled() && SHELL_TRANSITIONS_ROTATION;
+ }
+
/**
* @return {@code true} if transition is actively collecting changes. This is {@code false}
* once a transition is playing
@@ -246,6 +256,17 @@
return false;
}
+ /** @return {@code true} if wc is in a participant subtree */
+ boolean isTransitionOnDisplay(@NonNull DisplayContent dc) {
+ if (mCollectingTransition != null && mCollectingTransition.isOnDisplay(dc)) {
+ return true;
+ }
+ for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) {
+ if (mPlayingTransitions.get(i).isOnDisplay(dc)) return true;
+ }
+ return false;
+ }
+
/**
* @return {@code true} if {@param ar} is part of a transient-launch activity in an active
* transition.
@@ -260,6 +281,21 @@
return false;
}
+ /**
+ * Temporary work-around to deal with integration of legacy fixed-rotation. Returns whether
+ * the activity was visible before the collecting transition.
+ * TODO: at-least replace the polling mechanism.
+ */
+ boolean wasVisibleAtStart(@NonNull ActivityRecord ar) {
+ if (mCollectingTransition == null) return ar.isVisible();
+ final Transition.ChangeInfo ci = mCollectingTransition.mChanges.get(ar);
+ if (ci == null) {
+ // not part of transition, so use current state.
+ return ar.isVisible();
+ }
+ return ci.mVisible;
+ }
+
@WindowManager.TransitionType
int getCollectingTransitionType() {
return mCollectingTransition != null ? mCollectingTransition.mType : TRANSIT_NONE;
@@ -484,6 +520,11 @@
}
}
+ void setSeamlessRotation(@NonNull WindowContainer wc) {
+ if (mCollectingTransition == null) return;
+ mCollectingTransition.setSeamlessRotation(wc);
+ }
+
void legacyDetachNavigationBarFromApp(@NonNull IBinder token) {
final Transition transition = Transition.fromBinder(token);
if (transition == null || !mPlayingTransitions.contains(transition)) {
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index 36bb55e..6ee30bb 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -111,6 +111,14 @@
changed = true;
}
if (mTransitionController.isShellTransitionsEnabled()) {
+ // Apply legacy fixed rotation to wallpaper if it is becoming visible
+ if (!mTransitionController.useShellTransitionsRotation() && changed && visible) {
+ final WindowState wallpaperTarget =
+ mDisplayContent.mWallpaperController.getWallpaperTarget();
+ if (wallpaperTarget != null && wallpaperTarget.mToken.hasFixedRotationTransform()) {
+ linkFixedRotationTransform(wallpaperTarget.mToken);
+ }
+ }
return changed;
}
diff --git a/services/core/java/com/android/server/wm/WindowAnimationSpec.java b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
index 073a508..5bfd546 100644
--- a/services/core/java/com/android/server/wm/WindowAnimationSpec.java
+++ b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
@@ -80,6 +80,16 @@
}
@Override
+ public boolean getShowBackground() {
+ return mAnimation.getShowBackground();
+ }
+
+ @Override
+ public int getBackgroundColor() {
+ return mAnimation.getBackgroundColor();
+ }
+
+ @Override
public long getDuration() {
return mAnimation.computeDurationHint();
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 8a373bf..e1746cc 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -39,6 +39,7 @@
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SYNC_ENGINE;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.AppTransition.MAX_APP_TRANSITION_DURATION;
+import static com.android.server.wm.AppTransition.isActivityTransitOld;
import static com.android.server.wm.AppTransition.isTaskTransitOld;
import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
import static com.android.server.wm.IdentifierProto.HASH_CODE;
@@ -78,13 +79,14 @@
import android.util.ArraySet;
import android.util.Pair;
import android.util.Pools;
+import android.util.RotationUtils;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.DisplayInfo;
-import android.view.InsetsState;
import android.view.MagnificationSpec;
import android.view.RemoteAnimationDefinition;
import android.view.RemoteAnimationTarget;
+import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Builder;
import android.view.SurfaceControlViewHost;
@@ -98,6 +100,7 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.graphics.ColorUtils;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.ToBooleanFunction;
import com.android.server.wm.SurfaceAnimator.Animatable;
@@ -197,6 +200,7 @@
private final Point mTmpPos = new Point();
protected final Point mLastSurfacePosition = new Point();
+ protected @Surface.Rotation int mLastDeltaRotation = Surface.ROTATION_0;
/** Total number of elements in this subtree, including our own hierarchy element. */
private int mTreeWeight = 1;
@@ -473,6 +477,7 @@
t.remove(mSurfaceControl);
// Clear the last position so the new SurfaceControl will get correct position
mLastSurfacePosition.set(0, 0);
+ mLastDeltaRotation = Surface.ROTATION_0;
final SurfaceControl.Builder b = mWmService.makeSurfaceBuilder(null)
.setContainerLayer()
@@ -644,6 +649,7 @@
getSyncTransaction().remove(mSurfaceControl);
setSurfaceControl(null);
mLastSurfacePosition.set(0, 0);
+ mLastDeltaRotation = Surface.ROTATION_0;
scheduleAnimation();
}
if (mOverlayHost != null) {
@@ -2786,7 +2792,7 @@
@TransitionOldType int transit, boolean isVoiceInteraction,
@Nullable ArrayList<WindowContainer> sources) {
final Task task = asTask();
- if (task != null && !enter && !task.isHomeOrRecentsRootTask()) {
+ if (task != null && !enter && !task.isActivityTypeHomeOrRecents()) {
final InsetsControlTarget imeTarget = mDisplayContent.getImeTarget(IME_TARGET_LAYERING);
final boolean isImeLayeringTarget = imeTarget != null && imeTarget.getWindow() != null
&& imeTarget.getWindow().getTask() == task;
@@ -2816,6 +2822,25 @@
}
}
+ final ActivityRecord activityRecord = asActivityRecord();
+ if (activityRecord != null && isActivityTransitOld(transit)
+ && adapter.getShowBackground()) {
+ final @ColorInt int backgroundColorForTransition;
+ if (adapter.getBackgroundColor() != 0) {
+ // If available use the background color provided through getBackgroundColor
+ // which if set originates from a call to overridePendingAppTransition.
+ backgroundColorForTransition = adapter.getBackgroundColor();
+ } else {
+ // Otherwise default to the window's background color if provided through
+ // the theme as the background color for the animation - the top most window
+ // with a valid background color and showBackground set takes precedence.
+ final Task arTask = activityRecord.getTask();
+ backgroundColorForTransition = ColorUtils.setAlphaComponent(
+ arTask.getTaskDescription().getBackgroundColor(), 255);
+ }
+ animationRunnerBuilder.setTaskBackgroundColor(backgroundColorForTransition);
+ }
+
animationRunnerBuilder.build()
.startAnimation(getPendingTransaction(), adapter, !isVisible(),
ANIMATION_TYPE_APP_TRANSITION, thumbnailAdapter);
@@ -3127,12 +3152,43 @@
}
getRelativePosition(mTmpPos);
- if (mTmpPos.equals(mLastSurfacePosition)) {
+ final int deltaRotation = getRelativeDisplayRotation();
+ if (mTmpPos.equals(mLastSurfacePosition) && deltaRotation == mLastDeltaRotation) {
return;
}
t.setPosition(mSurfaceControl, mTmpPos.x, mTmpPos.y);
+ // set first, since we don't want rotation included in this (for now).
mLastSurfacePosition.set(mTmpPos.x, mTmpPos.y);
+
+ if (mTransitionController.isShellTransitionsEnabled()
+ && !mTransitionController.useShellTransitionsRotation()) {
+ if (deltaRotation != Surface.ROTATION_0) {
+ updateSurfaceRotation(t, deltaRotation, null /* positionLeash */);
+ } else if (deltaRotation != mLastDeltaRotation) {
+ t.setMatrix(mSurfaceControl, 1, 0, 0, 1);
+ }
+ }
+ mLastDeltaRotation = deltaRotation;
+ }
+
+ /**
+ * Updates the surface transform based on a difference in displayed-rotation from its parent.
+ * @param positionLeash If non-null, the rotated position will be set on this surface instead
+ * of the window surface. {@see WindowToken#getOrCreateFixedRotationLeash}.
+ */
+ protected void updateSurfaceRotation(Transaction t, @Surface.Rotation int deltaRotation,
+ @Nullable SurfaceControl positionLeash) {
+ // parent must be non-null otherwise deltaRotation would be 0.
+ RotationUtils.rotateSurface(t, mSurfaceControl, deltaRotation);
+ mTmpPos.set(mLastSurfacePosition.x, mLastSurfacePosition.y);
+ final Rect parentBounds = getParent().getBounds();
+ final boolean flipped = (deltaRotation % 2) != 0;
+ RotationUtils.rotatePoint(mTmpPos, deltaRotation,
+ flipped ? parentBounds.height() : parentBounds.width(),
+ flipped ? parentBounds.width() : parentBounds.height());
+ t.setPosition(positionLeash != null ? positionLeash : mSurfaceControl,
+ mTmpPos.x, mTmpPos.y);
}
@VisibleForTesting
@@ -3170,6 +3226,16 @@
}
}
+ /** @return the difference in displayed-rotation from parent. */
+ @Surface.Rotation
+ int getRelativeDisplayRotation() {
+ final WindowContainer parent = getParent();
+ if (parent == null) return Surface.ROTATION_0;
+ final int rotation = getWindowConfiguration().getDisplayRotation();
+ final int parentRotation = parent.getWindowConfiguration().getDisplayRotation();
+ return RotationUtils.deltaRotation(rotation, parentRotation);
+ }
+
void waitForAllWindowsDrawn() {
forAllWindows(w -> {
w.requestDrawIfNeeded(mWaitingForDrawn);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c9c3f1d..1a14727 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -116,6 +116,7 @@
import static com.android.server.wm.DisplayContent.IME_TARGET_CONTROL;
import static com.android.server.wm.DisplayContent.IME_TARGET_INPUT;
import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
+import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
@@ -151,11 +152,9 @@
import android.annotation.RequiresPermission;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
-import android.app.ActivityTaskManager;
import android.app.ActivityThread;
import android.app.AppOpsManager;
import android.app.IActivityManager;
-import android.app.IActivityTaskManager;
import android.app.IAssistDataReceiver;
import android.app.WindowConfiguration;
import android.content.BroadcastReceiver;
@@ -224,7 +223,6 @@
import android.util.EventLog;
import android.util.MergedConfiguration;
import android.util.Slog;
-import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.TimeUtils;
import android.util.TypedValue;
@@ -421,7 +419,7 @@
"persist.wm.enable_remote_keyguard_animation";
private static final int sEnableRemoteKeyguardAnimation =
- SystemProperties.getInt(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, 1);
+ SystemProperties.getInt(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, 2);
/**
* @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY
@@ -541,10 +539,7 @@
WindowManagerPolicy mPolicy;
final IActivityManager mActivityManager;
- // TODO: Probably not needed once activities are fully in WM.
- final IActivityTaskManager mActivityTaskManager;
final ActivityManagerInternal mAmInternal;
- final ActivityTaskManagerInternal mAtmInternal;
final AppOpsManager mAppOps;
final PackageManagerInternal mPmInternal;
@@ -584,20 +579,6 @@
final ArrayList<WindowState> mResizingWindows = new ArrayList<>();
/**
- * Windows whose animations have ended and now must be removed.
- */
- final ArrayList<WindowState> mPendingRemove = new ArrayList<>();
-
- /**
- * Used when processing mPendingRemove to avoid working on the original array.
- */
- WindowState[] mPendingRemoveTmp = new WindowState[20];
-
- // TODO: use WindowProcessController once go/wm-unified is done.
- /** Mapping of process pids to configurations */
- final SparseArray<Configuration> mProcessConfigurations = new SparseArray<>();
-
- /**
* Mapping of displayId to {@link DisplayImePolicy}.
* Note that this can be accessed without holding the lock.
*/
@@ -1271,9 +1252,7 @@
mTaskSystemBarsListenerController = new TaskSystemBarsListenerController();
mActivityManager = ActivityManager.getService();
- mActivityTaskManager = ActivityTaskManager.getService();
mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
- mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
AppOpsManager.OnOpChangedInternalListener opListener =
new AppOpsManager.OnOpChangedInternalListener() {
@@ -1342,8 +1321,7 @@
mAllowTheaterModeWakeFromLayout = context.getResources().getBoolean(
com.android.internal.R.bool.config_allowTheaterModeWakeFromWindowLayout);
- mTaskPositioningController = new TaskPositioningController(
- this, mInputManager, mActivityTaskManager, mH.getLooper());
+ mTaskPositioningController = new TaskPositioningController(this);
mDragDropController = new DragDropController(this, mH.getLooper());
mHighRefreshRateDenylist = HighRefreshRateDenylist.create(context.getResources());
@@ -1378,6 +1356,7 @@
float lightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0);
float ambientShadowAlpha = a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0);
float spotShadowAlpha = a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0);
+ a.recycle();
float[] ambientColor = {0.f, 0.f, 0.f, ambientShadowAlpha};
float[] spotColor = {0.f, 0.f, 0.f, spotShadowAlpha};
SurfaceControl.setGlobalShadowSettings(ambientColor, spotColor, lightY, lightZ,
@@ -2039,7 +2018,6 @@
dc.mWinRemovedSinceNullFocus.add(win);
}
mEmbeddedWindowController.onWindowRemoved(win);
- mPendingRemove.remove(win);
mResizingWindows.remove(win);
updateNonSystemOverlayWindowsVisibilityIfNeeded(win, false /* surfaceShown */);
mWindowsChanged = true;
@@ -2908,16 +2886,6 @@
}
}
- void setNewDisplayOverrideConfiguration(Configuration overrideConfig,
- @NonNull DisplayContent dc) {
- if (dc.mWaitingForConfig) {
- dc.mWaitingForConfig = false;
- mLastFinishedFreezeSource = "new-config";
- }
-
- mRoot.setDisplayOverrideConfigurationIfNeeded(overrideConfig, dc);
- }
-
// TODO(multi-display): remove when no default display use case.
void prepareAppTransitionNone() {
if (!checkCallingPermission(MANAGE_APP_TOKENS, "prepareAppTransition()")) {
@@ -3234,7 +3202,7 @@
if (!checkCallingPermission(permission.CONTROL_KEYGUARD, "dismissKeyguard")) {
throw new SecurityException("Requires CONTROL_KEYGUARD permission");
}
- if (mAtmInternal.isDreaming()) {
+ if (mAtmService.isDreaming()) {
mAtmService.mTaskSupervisor.wakeUp("dismissKeyguard");
}
synchronized (mGlobalLock) {
@@ -3268,7 +3236,7 @@
public void closeSystemDialogs(String reason) {
int callingPid = Binder.getCallingPid();
int callingUid = Binder.getCallingUid();
- if (!mAtmInternal.checkCanCloseSystemDialogs(callingPid, callingUid, null)) {
+ if (!mAtmService.checkCanCloseSystemDialogs(callingPid, callingUid, null)) {
return;
}
synchronized (mGlobalLock) {
@@ -3698,7 +3666,8 @@
* Sets the touch mode state.
*
* To be able to change touch mode state, the caller must either own the focused window, or must
- * have the MODIFY_TOUCH_MODE_STATE permission.
+ * have the MODIFY_TOUCH_MODE_STATE permission. Instrumented processes are allowed to switch
+ * touch mode at any time.
*
* @param mode the touch mode to set
*/
@@ -3710,8 +3679,9 @@
}
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
- final boolean hasPermission = checkCallingPermission(MODIFY_TOUCH_MODE_STATE,
- "setInTouchMode()");
+
+ final boolean hasPermission = mAtmService.isInstrumenting(pid)
+ || checkCallingPermission(MODIFY_TOUCH_MODE_STATE, "setInTouchMode()");
final long token = Binder.clearCallingIdentity();
try {
if (mInputManager.setInTouchMode(mode, pid, uid, hasPermission)) {
@@ -4951,10 +4921,7 @@
PackageManager.FEATURE_FAKETOUCH);
}
- try {
- mActivityTaskManager.updateConfiguration(null);
- } catch (RemoteException e) {
- }
+ mAtmService.updateConfiguration(null /* request to compute config */);
}
public void systemReady() {
@@ -5332,8 +5299,8 @@
case RESET_ANR_MESSAGE: {
synchronized (mGlobalLock) {
mLastANRState = null;
+ mAtmService.mLastANRState = null;
}
- mAtmInternal.clearSavedANRState();
break;
}
case WALLPAPER_DRAW_PENDING_TIMEOUT: {
@@ -6198,7 +6165,7 @@
@Override
public void createInputConsumer(IBinder token, String name, int displayId,
InputChannel inputChannel) {
- if (!mAtmInternal.isCallerRecents(Binder.getCallingUid())
+ if (!mAtmService.isCallerRecents(Binder.getCallingUid())
&& mContext.checkCallingOrSelfPermission(INPUT_CONSUMER) != PERMISSION_GRANTED) {
throw new SecurityException("createInputConsumer requires INPUT_CONSUMER permission");
}
@@ -6214,7 +6181,7 @@
@Override
public boolean destroyInputConsumer(String name, int displayId) {
- if (!mAtmInternal.isCallerRecents(Binder.getCallingUid())
+ if (!mAtmService.isCallerRecents(Binder.getCallingUid())
&& mContext.checkCallingOrSelfPermission(INPUT_CONSUMER) != PERMISSION_GRANTED) {
throw new SecurityException("destroyInputConsumer requires INPUT_CONSUMER permission");
}
@@ -6411,23 +6378,6 @@
}
}
}
- if (mPendingRemove.size() > 0) {
- pw.println();
- pw.println(" Remove pending for:");
- for (int i=mPendingRemove.size()-1; i>=0; i--) {
- WindowState w = mPendingRemove.get(i);
- if (windows == null || windows.contains(w)) {
- pw.print(" Remove #"); pw.print(i); pw.print(' ');
- pw.print(w);
- if (dumpAll) {
- pw.println(":");
- w.dump(pw, " ", true);
- } else {
- pw.println();
- }
- }
- }
- }
if (mForceRemoves != null && mForceRemoves.size() > 0) {
pw.println();
pw.println(" Windows force removing:");
@@ -8382,9 +8332,9 @@
* views.
*/
void grantInputChannel(Session session, int callingUid, int callingPid, int displayId,
- SurfaceControl surface, IWindow window, IBinder hostInputToken,
- int flags, int privateFlags, int type, IBinder focusGrantToken,
- InputChannel outInputChannel) {
+ SurfaceControl surface, IWindow window, IBinder hostInputToken,
+ int flags, int privateFlags, int type, IBinder focusGrantToken,
+ String inputHandleName, InputChannel outInputChannel) {
final InputApplicationHandle applicationHandle;
final String name;
final InputChannel clientChannel;
@@ -8392,7 +8342,7 @@
EmbeddedWindowController.EmbeddedWindow win =
new EmbeddedWindowController.EmbeddedWindow(session, this, window,
mInputToWindowMap.get(hostInputToken), callingUid, callingPid, type,
- displayId, focusGrantToken);
+ displayId, focusGrantToken, inputHandleName);
clientChannel = win.openInputChannel();
mEmbeddedWindowController.add(clientChannel.getToken(), win);
applicationHandle = win.getApplicationHandle();
@@ -8941,4 +8891,27 @@
mTaskFpsCallbackController.unregisterCallback(listener);
}
+
+ @Override
+ public Bitmap snapshotTaskForRecents(int taskId) {
+ if (!checkCallingPermission(READ_FRAME_BUFFER, "snapshotTaskForRecents()")) {
+ throw new SecurityException("Requires READ_FRAME_BUFFER permission");
+ }
+
+ TaskSnapshot taskSnapshot;
+ synchronized (mGlobalLock) {
+ Task task = mRoot.anyTaskForId(taskId, MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
+ if (task == null) {
+ throw new IllegalArgumentException(
+ "Failed to find matching task for taskId=" + taskId);
+ }
+ taskSnapshot = mTaskSnapshotController.captureTaskSnapshot(task, false);
+ }
+
+ if (taskSnapshot == null || taskSnapshot.getHardwareBuffer() == null) {
+ return null;
+ }
+ return Bitmap.wrapHardwareBuffer(taskSnapshot.getHardwareBuffer(),
+ taskSnapshot.getColorSpace());
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 27024ce..4c7891b 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -19,6 +19,8 @@
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
import static android.app.ActivityManager.isStartResultSuccessful;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.window.WindowContainerTransaction.Change.CHANGE_BOUNDS_TRANSACTION;
+import static android.window.WindowContainerTransaction.Change.CHANGE_BOUNDS_TRANSACTION_RECT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT;
@@ -1146,7 +1148,11 @@
final PendingTransaction pt = mPendingTransactions.remove(0);
pt.startSync();
// Post this so that the now-playing transition setup isn't interrupted.
- mService.mH.post(pt::startTransaction);
+ mService.mH.post(() -> {
+ synchronized (mGlobalLock) {
+ pt.startTransaction();
+ }
+ });
}
@Override
@@ -1220,10 +1226,14 @@
while (entries.hasNext()) {
final Map.Entry<IBinder, WindowContainerTransaction.Change> entry = entries.next();
// Only allow to apply changes to TaskFragment that is created by this organizer.
- enforceTaskFragmentOrganized(func, WindowContainer.fromBinder(entry.getKey()),
- organizer);
+ WindowContainer wc = WindowContainer.fromBinder(entry.getKey());
+ enforceTaskFragmentOrganized(func, wc, organizer);
+ enforceTaskFragmentConfigChangeAllowed(func, wc, entry.getValue(), organizer);
}
+ // TODO(b/197364677): Enforce safety of hierarchy operations in untrusted mode. E.g. one
+ // could first change a trusted TF, and then start/reparent untrusted activity there.
+
// Hierarchy changes
final List<WindowContainerTransaction.HierarchyOp> hops = t.getHierarchyOps();
for (int i = hops.size() - 1; i >= 0; i--) {
@@ -1293,6 +1303,57 @@
}
}
+ /**
+ * Makes sure that SurfaceControl transactions and the ability to set bounds outside of the
+ * parent bounds are not allowed for embedding without full trust between the host and the
+ * target.
+ * TODO(b/197364677): Allow SC transactions when the client-driven animations are protected from
+ * tapjacking.
+ */
+ private void enforceTaskFragmentConfigChangeAllowed(String func, @Nullable WindowContainer wc,
+ WindowContainerTransaction.Change change, ITaskFragmentOrganizer organizer) {
+ if (wc == null) {
+ Slog.e(TAG, "Attempt to operate on task fragment that no longer exists");
+ return;
+ }
+ // Check if TaskFragment is embedded in fully trusted mode
+ if (wc.asTaskFragment().isAllowedToBeEmbeddedInTrustedMode()) {
+ // Fully trusted, no need to check further
+ return;
+ }
+
+ if (change == null) {
+ return;
+ }
+ final int changeMask = change.getChangeMask();
+ if ((changeMask & (CHANGE_BOUNDS_TRANSACTION | CHANGE_BOUNDS_TRANSACTION_RECT)) != 0) {
+ String msg = "Permission Denial: " + func + " from pid="
+ + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+ + " trying to apply SurfaceControl changes to TaskFragment in non-trusted "
+ + "embedding mode, TaskFragmentOrganizer=" + organizer;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+ if (change.getWindowSetMask() == 0) {
+ // Nothing else to check.
+ return;
+ }
+ WindowConfiguration requestedWindowConfig = change.getConfiguration().windowConfiguration;
+ WindowContainer wcParent = wc.getParent();
+ if (wcParent == null) {
+ Slog.e(TAG, "Attempt to set bounds on task fragment that has no parent");
+ return;
+ }
+ if (!wcParent.getBounds().contains(requestedWindowConfig.getBounds())) {
+ String msg = "Permission Denial: " + func + " from pid="
+ + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+ + " trying to apply bounds outside of parent for non-trusted host,"
+ + " TaskFragmentOrganizer=" + organizer;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+ }
+
void createTaskFragment(@NonNull TaskFragmentCreationParams creationParams,
@Nullable IBinder errorCallbackToken, @NonNull CallerInfo caller) {
final ActivityRecord ownerActivity =
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 0d72e9a..e84a747 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -850,7 +850,8 @@
/**
* @see #setOnBackInvokedCallback(IOnBackInvokedCallback)
*/
- private IOnBackInvokedCallback mOnBackInvokedCallback;
+ private IOnBackInvokedCallback mApplicationOnBackInvokedCallback;
+ private IOnBackInvokedCallback mSystemOnBackInvokedCallback;
@Override
WindowState asWindowState() {
@@ -1073,15 +1074,25 @@
* called when a back navigation action is initiated.
* @see BackNavigationController
*/
- void setOnBackInvokedCallback(@Nullable IOnBackInvokedCallback onBackInvokedCallback) {
+ void setOnBackInvokedCallback(
+ @Nullable IOnBackInvokedCallback onBackInvokedCallback, int priority) {
ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "%s: Setting back callback %s",
this, onBackInvokedCallback);
- mOnBackInvokedCallback = onBackInvokedCallback;
+ if (priority >= 0) {
+ mApplicationOnBackInvokedCallback = onBackInvokedCallback;
+ } else {
+ mSystemOnBackInvokedCallback = onBackInvokedCallback;
+ }
}
@Nullable
- IOnBackInvokedCallback getOnBackInvokedCallback() {
- return mOnBackInvokedCallback;
+ IOnBackInvokedCallback getApplicationOnBackInvokedCallback() {
+ return mApplicationOnBackInvokedCallback;
+ }
+
+ @Nullable
+ IOnBackInvokedCallback getSystemOnBackInvokedCallback() {
+ return mSystemOnBackInvokedCallback;
}
interface PowerManagerWrapper {
@@ -2385,6 +2396,8 @@
dc.getDisplayPolicy().removeWindowLw(this);
disposeInputChannel();
+ mSystemOnBackInvokedCallback = null;
+ mApplicationOnBackInvokedCallback = null;
mSession.windowRemovedLocked();
try {
@@ -2438,6 +2451,8 @@
try {
disposeInputChannel();
+ mSystemOnBackInvokedCallback = null;
+ mApplicationOnBackInvokedCallback = null;
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
"Remove %s: mSurfaceController=%s mAnimatingExit=%b mRemoveOnExit=%b "
@@ -2929,7 +2944,7 @@
boolean canTurnScreenOn = mActivityRecord == null || mActivityRecord.currentLaunchCanTurnScreenOn();
if (allowTheaterMode && canTurnScreenOn
- && (mWmService.mAtmInternal.isDreaming()
+ && (mWmService.mAtmService.isDreaming()
|| !mPowerManagerWrapper.isInteractive())) {
if (DEBUG_VISIBILITY || DEBUG_POWER) {
Slog.v(TAG, "Relayout window turning screen on: " + this);
@@ -4910,15 +4925,20 @@
if (hasSurface) {
mWmService.mDestroySurface.add(this);
}
- if (mRemoveOnExit) {
- mWmService.mPendingRemove.add(this);
- mRemoveOnExit = false;
- }
}
mAnimatingExit = false;
getDisplayContent().mWallpaperController.hideWallpapers(this);
}
+ @Override
+ boolean handleCompleteDeferredRemoval() {
+ if (mRemoveOnExit && !isSelfAnimating(0 /* flags */, EXIT_ANIMATING_TYPES)) {
+ mRemoveOnExit = false;
+ removeImmediately();
+ }
+ return super.handleCompleteDeferredRemoval();
+ }
+
boolean clearAnimatingFlags() {
boolean didSomething = false;
// We don't want to clear it out for windows that get replaced, because the
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index db231f6..f398034 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -44,6 +44,7 @@
import android.util.proto.ProtoOutputStream;
import android.view.DisplayInfo;
import android.view.InsetsState;
+import android.view.Surface;
import android.view.SurfaceControl;
import android.view.WindowManager.LayoutParams.WindowType;
import android.window.WindowContext;
@@ -99,6 +100,7 @@
final boolean mOwnerCanManageAppTokens;
private FixedRotationTransformState mFixedRotationTransformState;
+ private SurfaceControl mFixedRotationTransformLeash;
/**
* When set to {@code true}, this window token is created from {@link WindowContext}
@@ -521,8 +523,14 @@
if (state == null) {
return;
}
-
- state.resetTransform();
+ if (!mTransitionController.isShellTransitionsEnabled()) {
+ state.resetTransform();
+ } else {
+ // Remove all the leashes
+ for (int i = state.mAssociatedTokens.size() - 1; i >= 0; --i) {
+ state.mAssociatedTokens.get(i).removeFixedRotationLeash();
+ }
+ }
// Clear the flag so if the display will be updated to the same orientation, the transform
// won't take effect.
state.mIsTransforming = false;
@@ -554,6 +562,43 @@
}
/**
+ * Gets or creates a leash which can be treated as if this window is not-rotated. This is
+ * used to adapt mismatched-rotation surfaces into code that expects all windows to share
+ * the same rotation.
+ */
+ @Nullable
+ SurfaceControl getOrCreateFixedRotationLeash() {
+ if (!mTransitionController.isShellTransitionsEnabled()) return null;
+ final int rotation = getRelativeDisplayRotation();
+ if (rotation == Surface.ROTATION_0) return mFixedRotationTransformLeash;
+ if (mFixedRotationTransformLeash != null) return mFixedRotationTransformLeash;
+
+ final SurfaceControl.Transaction t = getSyncTransaction();
+ final SurfaceControl leash = makeSurface().setContainerLayer()
+ .setParent(getParentSurfaceControl())
+ .setName(getSurfaceControl() + " - rotation-leash")
+ .setHidden(false)
+ .setEffectLayer()
+ .setCallsite("WindowToken.getOrCreateFixedRotationLeash")
+ .build();
+ t.setPosition(leash, mLastSurfacePosition.x, mLastSurfacePosition.y);
+ t.show(leash);
+ t.reparent(getSurfaceControl(), leash);
+ t.setAlpha(getSurfaceControl(), 1.f);
+ mFixedRotationTransformLeash = leash;
+ updateSurfaceRotation(t, rotation, mFixedRotationTransformLeash);
+ return mFixedRotationTransformLeash;
+ }
+
+ void removeFixedRotationLeash() {
+ if (mFixedRotationTransformLeash == null) return;
+ final SurfaceControl.Transaction t = getSyncTransaction();
+ t.reparent(getSurfaceControl(), getParentSurfaceControl());
+ t.remove(mFixedRotationTransformLeash);
+ mFixedRotationTransformLeash = null;
+ }
+
+ /**
* It is called when the window is using fixed rotation transform, and before display applies
* the same rotation, the rotation change for display is canceled, e.g. the orientation from
* sensor is updated to previous direction.
@@ -575,7 +620,7 @@
@Override
void updateSurfacePosition(SurfaceControl.Transaction t) {
super.updateSurfacePosition(t);
- if (isFixedRotationTransforming()) {
+ if (!mTransitionController.isShellTransitionsEnabled() && isFixedRotationTransforming()) {
final ActivityRecord r = asActivityRecord();
final Task rootTask = r != null ? r.getRootTask() : null;
// Don't transform the activity in PiP because the PiP task organizer will handle it.
@@ -588,6 +633,20 @@
}
@Override
+ protected void updateSurfaceRotation(SurfaceControl.Transaction t,
+ @Surface.Rotation int deltaRotation, SurfaceControl positionLeash) {
+ final ActivityRecord r = asActivityRecord();
+ if (r != null) {
+ final Task rootTask = r.getRootTask();
+ // Don't transform the activity in PiP because the PiP task organizer will handle it.
+ if (rootTask != null && rootTask.inPinnedWindowingMode()) {
+ return;
+ }
+ }
+ super.updateSurfaceRotation(t, deltaRotation, positionLeash);
+ }
+
+ @Override
void resetSurfacePositionForAnimationLeash(SurfaceControl.Transaction t) {
// Keep the transformed position to animate because the surface will show in different
// rotation than the animator of leash.
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 95e1aec..0d49f5f 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -160,7 +160,7 @@
"android.hardware.graphics.common@1.2",
"android.hardware.graphics.common-V3-ndk",
"android.hardware.graphics.mapper@4.0",
- "android.hardware.input.classifier@1.0",
+ "android.hardware.input.processor-V1-ndk",
"android.hardware.ir@1.0",
"android.hardware.light@2.0",
"android.hardware.memtrack-V1-ndk",
diff --git a/services/core/jni/com_android_server_companion_virtual_InputController.cpp b/services/core/jni/com_android_server_companion_virtual_InputController.cpp
index adc91fc..8197b67 100644
--- a/services/core/jni/com_android_server_companion_virtual_InputController.cpp
+++ b/services/core/jni/com_android_server_companion_virtual_InputController.cpp
@@ -243,22 +243,34 @@
xAbsSetup.code = ABS_MT_POSITION_X;
xAbsSetup.absinfo.maximum = screenWidth - 1;
xAbsSetup.absinfo.minimum = 0;
- ioctl(fd, UI_ABS_SETUP, xAbsSetup);
+ if (ioctl(fd, UI_ABS_SETUP, &xAbsSetup) != 0) {
+ ALOGE("Error creating touchscreen uinput x axis: %s", strerror(errno));
+ return -errno;
+ }
uinput_abs_setup yAbsSetup;
yAbsSetup.code = ABS_MT_POSITION_Y;
yAbsSetup.absinfo.maximum = screenHeight - 1;
yAbsSetup.absinfo.minimum = 0;
- ioctl(fd, UI_ABS_SETUP, yAbsSetup);
+ if (ioctl(fd, UI_ABS_SETUP, &yAbsSetup) != 0) {
+ ALOGE("Error creating touchscreen uinput y axis: %s", strerror(errno));
+ return -errno;
+ }
uinput_abs_setup majorAbsSetup;
majorAbsSetup.code = ABS_MT_TOUCH_MAJOR;
majorAbsSetup.absinfo.maximum = screenWidth - 1;
majorAbsSetup.absinfo.minimum = 0;
- ioctl(fd, UI_ABS_SETUP, majorAbsSetup);
+ if (ioctl(fd, UI_ABS_SETUP, &majorAbsSetup) != 0) {
+ ALOGE("Error creating touchscreen uinput major axis: %s", strerror(errno));
+ return -errno;
+ }
uinput_abs_setup pressureAbsSetup;
pressureAbsSetup.code = ABS_MT_PRESSURE;
pressureAbsSetup.absinfo.maximum = 255;
pressureAbsSetup.absinfo.minimum = 0;
- ioctl(fd, UI_ABS_SETUP, pressureAbsSetup);
+ if (ioctl(fd, UI_ABS_SETUP, &pressureAbsSetup) != 0) {
+ ALOGE("Error creating touchscreen uinput pressure axis: %s", strerror(errno));
+ return -errno;
+ }
}
if (ioctl(fd, UI_DEV_SETUP, &setup) != 0) {
ALOGE("Error creating uinput device: %s", strerror(errno));
@@ -266,6 +278,7 @@
}
} else {
// UI_DEV_SETUP was not introduced until version 5. Try setting up manually.
+ ALOGI("Falling back to version %d manual setup", version);
uinput_user_dev fallback;
memset(&fallback, 0, sizeof(fallback));
strlcpy(fallback.name, readableName, UINPUT_MAX_NAME_SIZE);
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index c7f1367..a9c6b8d 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -36,8 +36,6 @@
#include <android/hardware/gnss/BnGnssMeasurementCallback.h>
#include <android/hardware/gnss/BnGnssPowerIndicationCallback.h>
#include <android/hardware/gnss/BnGnssPsdsCallback.h>
-#include <android/hardware/gnss/measurement_corrections/1.0/IMeasurementCorrections.h>
-#include <android/hardware/gnss/measurement_corrections/1.1/IMeasurementCorrections.h>
#include <binder/IServiceManager.h>
#include <nativehelper/JNIHelp.h>
#include <pthread.h>
@@ -61,6 +59,7 @@
#include "gnss/GnssMeasurement.h"
#include "gnss/GnssNavigationMessage.h"
#include "gnss/GnssVisibilityControl.h"
+#include "gnss/MeasurementCorrections.h"
#include "gnss/Utils.h"
#include "hardware_legacy/power.h"
#include "jni.h"
@@ -82,31 +81,6 @@
static jmethodID method_requestUtcTime;
static jmethodID method_reportGnssServiceDied;
static jmethodID method_reportGnssPowerStats;
-static jmethodID method_setSubHalMeasurementCorrectionsCapabilities;
-static jmethodID method_correctionsGetLatitudeDegrees;
-static jmethodID method_correctionsGetLongitudeDegrees;
-static jmethodID method_correctionsGetAltitudeMeters;
-static jmethodID method_correctionsGetHorPosUncMeters;
-static jmethodID method_correctionsGetVerPosUncMeters;
-static jmethodID method_correctionsGetToaGpsNanosecondsOfWeek;
-static jmethodID method_correctionsGetSingleSatCorrectionList;
-static jmethodID method_correctionsHasEnvironmentBearing;
-static jmethodID method_correctionsGetEnvironmentBearingDegrees;
-static jmethodID method_correctionsGetEnvironmentBearingUncertaintyDegrees;
-static jmethodID method_listSize;
-static jmethodID method_correctionListGet;
-static jmethodID method_correctionSatFlags;
-static jmethodID method_correctionSatConstType;
-static jmethodID method_correctionSatId;
-static jmethodID method_correctionSatCarrierFreq;
-static jmethodID method_correctionSatIsLosProb;
-static jmethodID method_correctionSatEpl;
-static jmethodID method_correctionSatEplUnc;
-static jmethodID method_correctionSatRefPlane;
-static jmethodID method_correctionPlaneLatDeg;
-static jmethodID method_correctionPlaneLngDeg;
-static jmethodID method_correctionPlaneAltDeg;
-static jmethodID method_correctionPlaneAzimDeg;
static jmethodID method_reportNfwNotification;
static jmethodID method_isInEmergencySession;
static jmethodID method_gnssPowerStatsCtor;
@@ -135,15 +109,6 @@
using android::hardware::gnss::V1_0::IGnssXtraCallback;
using android::hardware::gnss::V2_0::ElapsedRealtimeFlags;
-using MeasurementCorrections_V1_0 = android::hardware::gnss::measurement_corrections::V1_0::MeasurementCorrections;
-using MeasurementCorrections_V1_1 = android::hardware::gnss::measurement_corrections::V1_1::MeasurementCorrections;
-
-using SingleSatCorrection_V1_0 =
- android::hardware::gnss::measurement_corrections::V1_0::SingleSatCorrection;
-using SingleSatCorrection_V1_1 =
- android::hardware::gnss::measurement_corrections::V1_1::SingleSatCorrection;
-using android::hardware::gnss::measurement_corrections::V1_0::ReflectingPlane;
-
using android::hidl::base::V1_0::IBase;
using GnssConstellationType_V1_0 = android::hardware::gnss::V1_0::GnssConstellationType;
@@ -158,11 +123,6 @@
using IGnssCallback_V2_0 = android::hardware::gnss::V2_0::IGnssCallback;
using IGnssCallback_V2_1 = android::hardware::gnss::V2_1::IGnssCallback;
-using IMeasurementCorrections_V1_0 = android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections;
-using IMeasurementCorrections_V1_1 = android::hardware::gnss::measurement_corrections::V1_1::IMeasurementCorrections;
-using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrectionsCallback;
-using android::hardware::gnss::measurement_corrections::V1_0::GnssSingleSatCorrectionFlags;
-
using android::hardware::gnss::BlocklistedSource;
using android::hardware::gnss::GnssConstellationType;
using android::hardware::gnss::GnssPowerStats;
@@ -207,8 +167,6 @@
sp<IGnssXtra> gnssXtraIface = nullptr;
sp<IGnssNi> gnssNiIface = nullptr;
sp<IGnssPowerIndication> gnssPowerIndicationIface = nullptr;
-sp<IMeasurementCorrections_V1_0> gnssCorrectionsIface_V1_0 = nullptr;
-sp<IMeasurementCorrections_V1_1> gnssCorrectionsIface_V1_1 = nullptr;
std::unique_ptr<GnssConfigurationInterface> gnssConfigurationIface = nullptr;
std::unique_ptr<android::gnss::GnssMeasurementInterface> gnssMeasurementIface = nullptr;
@@ -220,6 +178,8 @@
std::unique_ptr<android::gnss::AGnssRilInterface> agnssRilIface = nullptr;
std::unique_ptr<android::gnss::GnssVisibilityControlInterface> gnssVisibilityControlIface = nullptr;
std::unique_ptr<android::gnss::GnssAntennaInfoInterface> gnssAntennaInfoIface = nullptr;
+std::unique_ptr<android::gnss::MeasurementCorrectionsInterface> gnssMeasurementCorrectionsIface =
+ nullptr;
#define WAKE_LOCK_NAME "GPS"
@@ -825,23 +785,6 @@
}
/*
- * MeasurementCorrectionsCallback implements callback methods of interface
- * IMeasurementCorrectionsCallback.hal.
- */
-struct MeasurementCorrectionsCallback : public IMeasurementCorrectionsCallback {
- Return<void> setCapabilitiesCb(uint32_t capabilities) override;
-};
-
-Return<void> MeasurementCorrectionsCallback::setCapabilitiesCb(uint32_t capabilities) {
- ALOGD("%s: %du\n", __func__, capabilities);
- JNIEnv* env = getJniEnv();
- env->CallVoidMethod(mCallbacksObj, method_setSubHalMeasurementCorrectionsCapabilities,
- capabilities);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Void();
-}
-
-/*
* GnssNiCallback implements callback methods required by the IGnssNi interface.
*/
struct GnssNiCallback : public IGnssNiCallback {
@@ -944,63 +887,9 @@
"(Lcom/android/server/location/gnss/GnssPowerStats;)V");
method_isInEmergencySession = env->GetMethodID(clazz, "isInEmergencySession", "()Z");
- method_setSubHalMeasurementCorrectionsCapabilities = env->GetMethodID(clazz,
- "setSubHalMeasurementCorrectionsCapabilities", "(I)V");
method_setSubHalPowerIndicationCapabilities =
env->GetMethodID(clazz, "setSubHalPowerIndicationCapabilities", "(I)V");
- jclass measCorrClass = env->FindClass("android/location/GnssMeasurementCorrections");
- method_correctionsGetLatitudeDegrees = env->GetMethodID(
- measCorrClass,"getLatitudeDegrees", "()D");
- method_correctionsGetLongitudeDegrees = env->GetMethodID(
- measCorrClass, "getLongitudeDegrees", "()D");
- method_correctionsGetAltitudeMeters = env->GetMethodID(
- measCorrClass, "getAltitudeMeters", "()D");
- method_correctionsGetHorPosUncMeters = env->GetMethodID(
- measCorrClass, "getHorizontalPositionUncertaintyMeters", "()D");
- method_correctionsGetVerPosUncMeters = env->GetMethodID(
- measCorrClass, "getVerticalPositionUncertaintyMeters", "()D");
- method_correctionsGetToaGpsNanosecondsOfWeek = env->GetMethodID(
- measCorrClass, "getToaGpsNanosecondsOfWeek", "()J");
-
- method_correctionsGetSingleSatCorrectionList = env->GetMethodID(
- measCorrClass, "getSingleSatelliteCorrectionList", "()Ljava/util/List;");
-
- method_correctionsHasEnvironmentBearing = env->GetMethodID(
- measCorrClass, "hasEnvironmentBearing", "()Z");
- method_correctionsGetEnvironmentBearingDegrees = env->GetMethodID(
- measCorrClass, "getEnvironmentBearingDegrees", "()F");
- method_correctionsGetEnvironmentBearingUncertaintyDegrees = env->GetMethodID(
- measCorrClass, "getEnvironmentBearingUncertaintyDegrees", "()F");
-
- jclass corrListClass = env->FindClass("java/util/List");
- method_listSize = env->GetMethodID(corrListClass, "size", "()I");
- method_correctionListGet = env->GetMethodID(corrListClass, "get", "(I)Ljava/lang/Object;");
-
- jclass singleSatCorrClass = env->FindClass("android/location/GnssSingleSatCorrection");
- method_correctionSatFlags = env->GetMethodID(
- singleSatCorrClass, "getSingleSatelliteCorrectionFlags", "()I");
- method_correctionSatConstType = env->GetMethodID(
- singleSatCorrClass, "getConstellationType", "()I");
- method_correctionSatId= env->GetMethodID(
- singleSatCorrClass, "getSatelliteId", "()I");
- method_correctionSatCarrierFreq = env->GetMethodID(
- singleSatCorrClass, "getCarrierFrequencyHz", "()F");
- method_correctionSatIsLosProb = env->GetMethodID(
- singleSatCorrClass,"getProbabilityLineOfSight", "()F");
- method_correctionSatEpl = env->GetMethodID(
- singleSatCorrClass, "getExcessPathLengthMeters", "()F");
- method_correctionSatEplUnc = env->GetMethodID(
- singleSatCorrClass, "getExcessPathLengthUncertaintyMeters", "()F");
- method_correctionSatRefPlane = env->GetMethodID(
- singleSatCorrClass, "getReflectingPlane", "()Landroid/location/GnssReflectingPlane;");
-
- jclass refPlaneClass = env->FindClass("android/location/GnssReflectingPlane");
- method_correctionPlaneLatDeg = env->GetMethodID(refPlaneClass, "getLatitudeDegrees", "()D");
- method_correctionPlaneLngDeg = env->GetMethodID(refPlaneClass, "getLongitudeDegrees", "()D");
- method_correctionPlaneAltDeg = env->GetMethodID(refPlaneClass, "getAltitudeMeters", "()D");
- method_correctionPlaneAzimDeg = env->GetMethodID(refPlaneClass, "getAzimuthDegrees", "()D");
-
jclass gnssPowerStatsClass = env->FindClass("com/android/server/location/gnss/GnssPowerStats");
class_gnssPowerStats = (jclass)env->NewGlobalRef(gnssPowerStatsClass);
method_gnssPowerStatsCtor = env->GetMethodID(class_gnssPowerStats, "<init>", "(IJDDDDDD[D)V");
@@ -1012,6 +901,8 @@
gnss::GnssMeasurement_class_init_once(env, clazz);
gnss::GnssNavigationMessage_class_init_once(env, clazz);
gnss::GnssVisibilityControl_class_init_once(env, clazz);
+ gnss::MeasurementCorrections_class_init_once(env, clazz);
+ gnss::MeasurementCorrectionsCallback_class_init_once(env, clazz);
gnss::AGnss_class_init_once(env, clazz);
gnss::AGnssRil_class_init_once(env, clazz);
gnss::Utils_class_init_once(env);
@@ -1180,20 +1071,34 @@
}
}
- if (gnssHal_V2_1 != nullptr) {
- auto gnssCorrections = gnssHal_V2_1->getExtensionMeasurementCorrections_1_1();
- if (!gnssCorrections.isOk()) {
- ALOGD("Unable to get a handle to GnssMeasurementCorrections 1.1 interface");
- } else {
- gnssCorrectionsIface_V1_1 = gnssCorrections;
- gnssCorrectionsIface_V1_0 = gnssCorrectionsIface_V1_1;
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ sp<android::hardware::gnss::measurement_corrections::IMeasurementCorrectionsInterface>
+ gnssMeasurementCorrectionsAidl;
+ auto status =
+ gnssHalAidl->getExtensionMeasurementCorrections(&gnssMeasurementCorrectionsAidl);
+ if (checkAidlStatus(status,
+ "Unable to get a handle to GnssVisibilityControl AIDL interface.")) {
+ gnssMeasurementCorrectionsIface =
+ std::make_unique<gnss::MeasurementCorrectionsIface_Aidl>(
+ gnssMeasurementCorrectionsAidl);
}
- } else if (gnssHal_V2_0 != nullptr) {
+ }
+ if (gnssHal_V2_1 != nullptr && gnssMeasurementCorrectionsIface == nullptr) {
+ auto gnssCorrections = gnssHal_V2_1->getExtensionMeasurementCorrections_1_1();
+ if (checkHidlReturn(gnssCorrections,
+ "Unable to get a handle to GnssMeasurementCorrections HIDL "
+ "interface")) {
+ gnssMeasurementCorrectionsIface =
+ std::make_unique<gnss::MeasurementCorrectionsIface_V1_1>(gnssCorrections);
+ }
+ }
+ if (gnssHal_V2_0 != nullptr && gnssMeasurementCorrectionsIface == nullptr) {
auto gnssCorrections = gnssHal_V2_0->getExtensionMeasurementCorrections();
- if (!gnssCorrections.isOk()) {
- ALOGD("Unable to get a handle to GnssMeasurementCorrections interface");
- } else {
- gnssCorrectionsIface_V1_0 = gnssCorrections;
+ if (checkHidlReturn(gnssCorrections,
+ "Unable to get a handle to GnssMeasurementCorrections HIDL "
+ "interface")) {
+ gnssMeasurementCorrectionsIface =
+ std::make_unique<gnss::MeasurementCorrectionsIface_V1_0>(gnssCorrections);
}
}
@@ -1447,19 +1352,11 @@
ALOGI("Unable to initialize IGnssVisibilityControl interface.");
}
- // Set IMeasurementCorrections.hal callback.
- if (gnssCorrectionsIface_V1_1 != nullptr) {
- sp<IMeasurementCorrectionsCallback> gnssCorrectionsIfaceCbIface =
- new MeasurementCorrectionsCallback();
- auto result = gnssCorrectionsIface_V1_1->setCallback(gnssCorrectionsIfaceCbIface);
- checkHidlReturn(result, "IMeasurementCorrections 1.1 setCallback() failed.");
- } else if (gnssCorrectionsIface_V1_0 != nullptr) {
- sp<IMeasurementCorrectionsCallback> gnssCorrectionsIfaceCbIface =
- new MeasurementCorrectionsCallback();
- auto result = gnssCorrectionsIface_V1_0->setCallback(gnssCorrectionsIfaceCbIface);
- checkHidlReturn(result, "IMeasurementCorrections 1.0 setCallback() failed.");
- } else {
- ALOGI("Unable to find IMeasurementCorrections.");
+ // Set IMeasurementCorrection callback.
+ if (gnssMeasurementCorrectionsIface == nullptr ||
+ !gnssMeasurementCorrectionsIface->setCallback(
+ std::make_unique<gnss::MeasurementCorrectionsCallback>())) {
+ ALOGI("Unable to initialize IGnssMeasurementCorrections interface.");
}
// Set IGnssPowerIndication.hal callback.
@@ -1990,174 +1887,21 @@
static jboolean android_location_gnss_hal_GnssNative_is_measurement_corrections_supported(
JNIEnv* env, jclass) {
- if (gnssCorrectionsIface_V1_0 != nullptr || gnssCorrectionsIface_V1_1 != nullptr) {
+ if (gnssMeasurementCorrectionsIface != nullptr) {
return JNI_TRUE;
}
return JNI_FALSE;
}
-static SingleSatCorrection_V1_0 getSingleSatCorrection_1_0_withoutConstellation(
- JNIEnv* env, jobject singleSatCorrectionObj) {
- jint correctionFlags = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags);
- jint satId = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatId);
- jfloat carrierFreqHz =
- env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatCarrierFreq);
- jfloat probSatIsLos =
- env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatIsLosProb);
- jfloat eplMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEpl);
- jfloat eplUncMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEplUnc);
- uint16_t corrFlags = static_cast<uint16_t>(correctionFlags);
- jobject reflectingPlaneObj = nullptr;
- bool has_ref_plane = (corrFlags & GnssSingleSatCorrectionFlags::HAS_REFLECTING_PLANE) != 0;
- if (has_ref_plane) {
- reflectingPlaneObj =
- env->CallObjectMethod(singleSatCorrectionObj, method_correctionSatRefPlane);
- }
-
- ReflectingPlane reflectingPlane;
- if (has_ref_plane) {
- jdouble latitudeDegreesRefPlane =
- env->CallDoubleMethod(reflectingPlaneObj, method_correctionPlaneLatDeg);
- jdouble longitudeDegreesRefPlane =
- env->CallDoubleMethod(reflectingPlaneObj, method_correctionPlaneLngDeg);
- jdouble altitudeDegreesRefPlane =
- env->CallDoubleMethod(reflectingPlaneObj, method_correctionPlaneAltDeg);
- jdouble azimuthDegreeRefPlane =
- env->CallDoubleMethod(reflectingPlaneObj, method_correctionPlaneAzimDeg);
- reflectingPlane = {
- .latitudeDegrees = latitudeDegreesRefPlane,
- .longitudeDegrees = longitudeDegreesRefPlane,
- .altitudeMeters = altitudeDegreesRefPlane,
- .azimuthDegrees = azimuthDegreeRefPlane,
- };
- }
- env->DeleteLocalRef(reflectingPlaneObj);
-
- SingleSatCorrection_V1_0 singleSatCorrection = {
- .singleSatCorrectionFlags = corrFlags,
- .svid = static_cast<uint16_t>(satId),
- .carrierFrequencyHz = carrierFreqHz,
- .probSatIsLos = probSatIsLos,
- .excessPathLengthMeters = eplMeters,
- .excessPathLengthUncertaintyMeters = eplUncMeters,
- .reflectingPlane = reflectingPlane,
- };
-
- return singleSatCorrection;
-}
-
-static void getSingleSatCorrectionList_1_1(JNIEnv* env, jobject singleSatCorrectionList,
- hidl_vec<SingleSatCorrection_V1_1>& list) {
- for (uint16_t i = 0; i < list.size(); ++i) {
- jobject singleSatCorrectionObj =
- env->CallObjectMethod(singleSatCorrectionList, method_correctionListGet, i);
-
- SingleSatCorrection_V1_0 singleSatCorrection_1_0 =
- getSingleSatCorrection_1_0_withoutConstellation(env, singleSatCorrectionObj);
-
- jint constType = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatConstType);
-
- SingleSatCorrection_V1_1 singleSatCorrection_1_1 = {
- .v1_0 = singleSatCorrection_1_0,
- .constellation = static_cast<GnssConstellationType_V2_0>(constType),
- };
-
- list[i] = singleSatCorrection_1_1;
- env->DeleteLocalRef(singleSatCorrectionObj);
- }
-}
-
-static void getSingleSatCorrectionList_1_0(JNIEnv* env, jobject singleSatCorrectionList,
- hidl_vec<SingleSatCorrection_V1_0>& list) {
- for (uint16_t i = 0; i < list.size(); ++i) {
- jobject singleSatCorrectionObj =
- env->CallObjectMethod(singleSatCorrectionList, method_correctionListGet, i);
-
- SingleSatCorrection_V1_0 singleSatCorrection =
- getSingleSatCorrection_1_0_withoutConstellation(env, singleSatCorrectionObj);
-
- jint constType = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatConstType);
-
- singleSatCorrection.constellation = static_cast<GnssConstellationType_V1_0>(constType),
-
- list[i] = singleSatCorrection;
- env->DeleteLocalRef(singleSatCorrectionObj);
- }
-}
-
static jboolean android_location_gnss_hal_GnssNative_inject_measurement_corrections(
JNIEnv* env, jclass, jobject correctionsObj) {
- if (gnssCorrectionsIface_V1_0 == nullptr && gnssCorrectionsIface_V1_1 == nullptr) {
+ if (gnssMeasurementCorrectionsIface == nullptr) {
ALOGW("Trying to inject GNSS measurement corrections on a chipset that does not"
" support them.");
return JNI_FALSE;
}
-
- jobject singleSatCorrectionList = env->CallObjectMethod(correctionsObj,
- method_correctionsGetSingleSatCorrectionList);
-
- auto len = (singleSatCorrectionList == nullptr)
- ? 0
- : env->CallIntMethod(singleSatCorrectionList, method_listSize);
- if (len == 0) {
- ALOGI("Empty correction list injected....Returning with no HAL injection");
- return JNI_TRUE;
- }
-
- jdouble latitudeDegreesCorr = env->CallDoubleMethod(
- correctionsObj, method_correctionsGetLatitudeDegrees);
- jdouble longitudeDegreesCorr = env->CallDoubleMethod(
- correctionsObj, method_correctionsGetLongitudeDegrees);
- jdouble altitudeDegreesCorr = env->CallDoubleMethod(
- correctionsObj, method_correctionsGetAltitudeMeters);
- jdouble horizontalPositionUncertaintyMeters = env->CallDoubleMethod(
- correctionsObj, method_correctionsGetHorPosUncMeters);
- jdouble verticalPositionUncertaintyMeters = env->CallDoubleMethod(
- correctionsObj, method_correctionsGetVerPosUncMeters);
- jlong toaGpsNanosOfWeek = env->CallLongMethod(
- correctionsObj, method_correctionsGetToaGpsNanosecondsOfWeek);
-
- MeasurementCorrections_V1_0 measurementCorrections_1_0 = {
- .latitudeDegrees = latitudeDegreesCorr,
- .longitudeDegrees = longitudeDegreesCorr,
- .altitudeMeters = altitudeDegreesCorr,
- .horizontalPositionUncertaintyMeters = horizontalPositionUncertaintyMeters,
- .verticalPositionUncertaintyMeters = verticalPositionUncertaintyMeters,
- .toaGpsNanosecondsOfWeek = static_cast<uint64_t>(toaGpsNanosOfWeek),
- };
-
- if (gnssCorrectionsIface_V1_1 != nullptr) {
-
- jboolean hasEnvironmentBearingCorr = env->CallBooleanMethod(
- correctionsObj, method_correctionsHasEnvironmentBearing);
- jfloat environmentBearingDegreesCorr = env->CallFloatMethod(
- correctionsObj, method_correctionsGetEnvironmentBearingDegrees);
- jfloat environmentBearingUncertaintyDegreesCorr = env->CallFloatMethod(
- correctionsObj, method_correctionsGetEnvironmentBearingUncertaintyDegrees);
-
- hidl_vec<SingleSatCorrection_V1_1> list(len);
- getSingleSatCorrectionList_1_1(env, singleSatCorrectionList, list);
-
- MeasurementCorrections_V1_1 measurementCorrections_1_1 = {
- .v1_0 = measurementCorrections_1_0,
- .hasEnvironmentBearing = static_cast<bool>(hasEnvironmentBearingCorr),
- .environmentBearingDegrees = environmentBearingDegreesCorr,
- .environmentBearingUncertaintyDegrees = environmentBearingUncertaintyDegreesCorr,
- .satCorrections = list,
- };
-
- auto result = gnssCorrectionsIface_V1_1->setCorrections_1_1(measurementCorrections_1_1);
- return checkHidlReturn(result, "IMeasurementCorrections 1.1 setCorrections() failed.");
- }
-
- hidl_vec<SingleSatCorrection_V1_0> list(len);
- getSingleSatCorrectionList_1_0(env, singleSatCorrectionList, list);
- env->DeleteLocalRef(singleSatCorrectionList);
- measurementCorrections_1_0.satCorrections = list;
-
- auto result = gnssCorrectionsIface_V1_0->setCorrections(measurementCorrections_1_0);
- return checkHidlReturn(result, "IMeasurementCorrections 1.0 setCorrections() failed.");
+ return gnssMeasurementCorrectionsIface->setCorrections(env, correctionsObj);
}
static jboolean android_location_gnss_hal_GnssNative_is_navigation_message_supported(JNIEnv* env,
diff --git a/services/core/jni/gnss/Android.bp b/services/core/jni/gnss/Android.bp
index 252f0e8..e52df15 100644
--- a/services/core/jni/gnss/Android.bp
+++ b/services/core/jni/gnss/Android.bp
@@ -41,6 +41,8 @@
"GnssNavigationMessageCallback.cpp",
"GnssVisibilityControl.cpp",
"GnssVisibilityControlCallback.cpp",
+ "MeasurementCorrections.cpp",
+ "MeasurementCorrectionsCallback.cpp",
"Utils.cpp",
],
}
diff --git a/services/core/jni/gnss/MeasurementCorrections.cpp b/services/core/jni/gnss/MeasurementCorrections.cpp
new file mode 100644
index 0000000..8a3d84c
--- /dev/null
+++ b/services/core/jni/gnss/MeasurementCorrections.cpp
@@ -0,0 +1,444 @@
+/*
+ * 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 before <log/log.h> to overwrite the default value.
+#define LOG_TAG "MeasurementCorrectionsJni"
+
+#include "MeasurementCorrections.h"
+
+#include "Utils.h"
+
+using IMeasurementCorrections_V1_0 =
+ android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections;
+using IMeasurementCorrections_V1_1 =
+ android::hardware::gnss::measurement_corrections::V1_1::IMeasurementCorrections;
+using IMeasurementCorrections_Aidl =
+ android::hardware::gnss::measurement_corrections::IMeasurementCorrectionsInterface;
+using MeasurementCorrections_V1_0 =
+ android::hardware::gnss::measurement_corrections::V1_0::MeasurementCorrections;
+using MeasurementCorrections_V1_1 =
+ android::hardware::gnss::measurement_corrections::V1_1::MeasurementCorrections;
+using MeasurementCorrections_Aidl =
+ android::hardware::gnss::measurement_corrections::MeasurementCorrections;
+using GnssSingleSatCorrectionFlags_V1_0 =
+ android::hardware::gnss::measurement_corrections::V1_0::GnssSingleSatCorrectionFlags;
+using SingleSatCorrection_V1_0 =
+ android::hardware::gnss::measurement_corrections::V1_0::SingleSatCorrection;
+using SingleSatCorrection_V1_1 =
+ android::hardware::gnss::measurement_corrections::V1_1::SingleSatCorrection;
+using SingleSatCorrection_Aidl =
+ android::hardware::gnss::measurement_corrections::SingleSatCorrection;
+using ReflectingPlane_V1_0 =
+ android::hardware::gnss::measurement_corrections::V1_0::ReflectingPlane;
+using ReflectingPlane_Aidl = android::hardware::gnss::measurement_corrections::ReflectingPlane;
+using GnssConstellationType_V1_0 = android::hardware::gnss::V1_0::GnssConstellationType;
+using GnssConstellationType_V2_0 = android::hardware::gnss::V2_0::GnssConstellationType;
+using GnssConstellationType_Aidl = android::hardware::gnss::GnssConstellationType;
+
+namespace android::gnss {
+
+namespace {
+jmethodID method_correctionsGetLatitudeDegrees;
+jmethodID method_correctionsGetLongitudeDegrees;
+jmethodID method_correctionsGetAltitudeMeters;
+jmethodID method_correctionsGetHorPosUncMeters;
+jmethodID method_correctionsGetVerPosUncMeters;
+jmethodID method_correctionsGetToaGpsNanosecondsOfWeek;
+jmethodID method_correctionsGetSingleSatCorrectionList;
+jmethodID method_correctionsHasEnvironmentBearing;
+jmethodID method_correctionsGetEnvironmentBearingDegrees;
+jmethodID method_correctionsGetEnvironmentBearingUncertaintyDegrees;
+jmethodID method_listSize;
+jmethodID method_correctionListGet;
+jmethodID method_correctionSatFlags;
+jmethodID method_correctionSatConstType;
+jmethodID method_correctionSatId;
+jmethodID method_correctionSatCarrierFreq;
+jmethodID method_correctionSatIsLosProb;
+jmethodID method_correctionSatEpl;
+jmethodID method_correctionSatEplUnc;
+jmethodID method_correctionSatRefPlane;
+jmethodID method_correctionPlaneLatDeg;
+jmethodID method_correctionPlaneLngDeg;
+jmethodID method_correctionPlaneAltDeg;
+jmethodID method_correctionPlaneAzimDeg;
+} // anonymous namespace
+
+void MeasurementCorrections_class_init_once(JNIEnv* env, jclass clazz) {
+ jclass measCorrClass = env->FindClass("android/location/GnssMeasurementCorrections");
+ method_correctionsGetLatitudeDegrees =
+ env->GetMethodID(measCorrClass, "getLatitudeDegrees", "()D");
+ method_correctionsGetLongitudeDegrees =
+ env->GetMethodID(measCorrClass, "getLongitudeDegrees", "()D");
+ method_correctionsGetAltitudeMeters =
+ env->GetMethodID(measCorrClass, "getAltitudeMeters", "()D");
+ method_correctionsGetHorPosUncMeters =
+ env->GetMethodID(measCorrClass, "getHorizontalPositionUncertaintyMeters", "()D");
+ method_correctionsGetVerPosUncMeters =
+ env->GetMethodID(measCorrClass, "getVerticalPositionUncertaintyMeters", "()D");
+ method_correctionsGetToaGpsNanosecondsOfWeek =
+ env->GetMethodID(measCorrClass, "getToaGpsNanosecondsOfWeek", "()J");
+ method_correctionsGetSingleSatCorrectionList =
+ env->GetMethodID(measCorrClass, "getSingleSatelliteCorrectionList",
+ "()Ljava/util/List;");
+ method_correctionsHasEnvironmentBearing =
+ env->GetMethodID(measCorrClass, "hasEnvironmentBearing", "()Z");
+ method_correctionsGetEnvironmentBearingDegrees =
+ env->GetMethodID(measCorrClass, "getEnvironmentBearingDegrees", "()F");
+ method_correctionsGetEnvironmentBearingUncertaintyDegrees =
+ env->GetMethodID(measCorrClass, "getEnvironmentBearingUncertaintyDegrees", "()F");
+
+ jclass corrListClass = env->FindClass("java/util/List");
+ method_listSize = env->GetMethodID(corrListClass, "size", "()I");
+ method_correctionListGet = env->GetMethodID(corrListClass, "get", "(I)Ljava/lang/Object;");
+
+ jclass singleSatCorrClass = env->FindClass("android/location/GnssSingleSatCorrection");
+ method_correctionSatFlags =
+ env->GetMethodID(singleSatCorrClass, "getSingleSatelliteCorrectionFlags", "()I");
+ method_correctionSatConstType =
+ env->GetMethodID(singleSatCorrClass, "getConstellationType", "()I");
+ method_correctionSatId = env->GetMethodID(singleSatCorrClass, "getSatelliteId", "()I");
+ method_correctionSatCarrierFreq =
+ env->GetMethodID(singleSatCorrClass, "getCarrierFrequencyHz", "()F");
+ method_correctionSatIsLosProb =
+ env->GetMethodID(singleSatCorrClass, "getProbabilityLineOfSight", "()F");
+ method_correctionSatEpl =
+ env->GetMethodID(singleSatCorrClass, "getExcessPathLengthMeters", "()F");
+ method_correctionSatEplUnc =
+ env->GetMethodID(singleSatCorrClass, "getExcessPathLengthUncertaintyMeters", "()F");
+ method_correctionSatRefPlane = env->GetMethodID(singleSatCorrClass, "getReflectingPlane",
+ "()Landroid/location/GnssReflectingPlane;");
+
+ jclass refPlaneClass = env->FindClass("android/location/GnssReflectingPlane");
+ method_correctionPlaneLatDeg = env->GetMethodID(refPlaneClass, "getLatitudeDegrees", "()D");
+ method_correctionPlaneLngDeg = env->GetMethodID(refPlaneClass, "getLongitudeDegrees", "()D");
+ method_correctionPlaneAltDeg = env->GetMethodID(refPlaneClass, "getAltitudeMeters", "()D");
+ method_correctionPlaneAzimDeg = env->GetMethodID(refPlaneClass, "getAzimuthDegrees", "()D");
+}
+
+template <>
+bool MeasurementCorrectionsUtil::translateMeasurementCorrections(
+ JNIEnv* env, jobject correctionsObj, MeasurementCorrections_V1_0& corrections) {
+ jobject singleSatCorrectionList =
+ env->CallObjectMethod(correctionsObj, method_correctionsGetSingleSatCorrectionList);
+ if (singleSatCorrectionList == nullptr) return false;
+ auto len = env->CallIntMethod(singleSatCorrectionList, method_listSize);
+
+ jdouble latitudeDegreesCorr =
+ env->CallDoubleMethod(correctionsObj, method_correctionsGetLatitudeDegrees);
+ jdouble longitudeDegreesCorr =
+ env->CallDoubleMethod(correctionsObj, method_correctionsGetLongitudeDegrees);
+ jdouble altitudeDegreesCorr =
+ env->CallDoubleMethod(correctionsObj, method_correctionsGetAltitudeMeters);
+ jdouble horizontalPositionUncertaintyMeters =
+ env->CallDoubleMethod(correctionsObj, method_correctionsGetHorPosUncMeters);
+ jdouble verticalPositionUncertaintyMeters =
+ env->CallDoubleMethod(correctionsObj, method_correctionsGetVerPosUncMeters);
+ jlong toaGpsNanosOfWeek =
+ env->CallLongMethod(correctionsObj, method_correctionsGetToaGpsNanosecondsOfWeek);
+
+ corrections.latitudeDegrees = latitudeDegreesCorr;
+ corrections.longitudeDegrees = longitudeDegreesCorr;
+ corrections.altitudeMeters = altitudeDegreesCorr;
+ corrections.horizontalPositionUncertaintyMeters = horizontalPositionUncertaintyMeters;
+ corrections.verticalPositionUncertaintyMeters = verticalPositionUncertaintyMeters;
+ corrections.toaGpsNanosecondsOfWeek = static_cast<uint64_t>(toaGpsNanosOfWeek);
+
+ hardware::hidl_vec<SingleSatCorrection_V1_0> list(len);
+ MeasurementCorrectionsUtil::getSingleSatCorrectionList_1_0(env, singleSatCorrectionList, list);
+ env->DeleteLocalRef(singleSatCorrectionList);
+ corrections.satCorrections = list;
+ return true;
+}
+
+template <>
+bool MeasurementCorrectionsUtil::translateMeasurementCorrections(
+ JNIEnv* env, jobject correctionsObj, MeasurementCorrections_V1_1& corrections) {
+ jobject singleSatCorrectionList =
+ env->CallObjectMethod(correctionsObj, method_correctionsGetSingleSatCorrectionList);
+ if (singleSatCorrectionList == nullptr) return false;
+ auto len = env->CallIntMethod(singleSatCorrectionList, method_listSize);
+
+ MeasurementCorrections_V1_0 measurementCorrections_1_0;
+ translateMeasurementCorrections<MeasurementCorrections_V1_0>(env, correctionsObj,
+ measurementCorrections_1_0);
+ measurementCorrections_1_0.satCorrections.resize(0);
+
+ jboolean hasEnvironmentBearingCorr =
+ env->CallBooleanMethod(correctionsObj, method_correctionsHasEnvironmentBearing);
+ jfloat environmentBearingDegreesCorr =
+ env->CallFloatMethod(correctionsObj, method_correctionsGetEnvironmentBearingDegrees);
+ jfloat environmentBearingUncertaintyDegreesCorr =
+ env->CallFloatMethod(correctionsObj,
+ method_correctionsGetEnvironmentBearingUncertaintyDegrees);
+
+ hardware::hidl_vec<SingleSatCorrection_V1_1> list(len);
+ MeasurementCorrectionsUtil::getSingleSatCorrectionList_1_1(env, singleSatCorrectionList, list);
+ env->DeleteLocalRef(singleSatCorrectionList);
+
+ corrections.v1_0 = measurementCorrections_1_0;
+ corrections.hasEnvironmentBearing = static_cast<bool>(hasEnvironmentBearingCorr);
+ corrections.environmentBearingDegrees = environmentBearingDegreesCorr;
+ corrections.environmentBearingUncertaintyDegrees = environmentBearingUncertaintyDegreesCorr;
+ corrections.satCorrections = list;
+ return true;
+}
+
+template <>
+bool MeasurementCorrectionsUtil::translateMeasurementCorrections(
+ JNIEnv* env, jobject correctionsObj, MeasurementCorrections_Aidl& corrections) {
+ jobject singleSatCorrectionList =
+ env->CallObjectMethod(correctionsObj, method_correctionsGetSingleSatCorrectionList);
+ if (singleSatCorrectionList == nullptr) return false;
+ auto len = env->CallIntMethod(singleSatCorrectionList, method_listSize);
+
+ jdouble latitudeDegreesCorr =
+ env->CallDoubleMethod(correctionsObj, method_correctionsGetLatitudeDegrees);
+ jdouble longitudeDegreesCorr =
+ env->CallDoubleMethod(correctionsObj, method_correctionsGetLongitudeDegrees);
+ jdouble altitudeDegreesCorr =
+ env->CallDoubleMethod(correctionsObj, method_correctionsGetAltitudeMeters);
+ jdouble horizontalPositionUncertaintyMeters =
+ env->CallDoubleMethod(correctionsObj, method_correctionsGetHorPosUncMeters);
+ jdouble verticalPositionUncertaintyMeters =
+ env->CallDoubleMethod(correctionsObj, method_correctionsGetVerPosUncMeters);
+ jlong toaGpsNanosOfWeek =
+ env->CallLongMethod(correctionsObj, method_correctionsGetToaGpsNanosecondsOfWeek);
+
+ corrections.latitudeDegrees = static_cast<double>(latitudeDegreesCorr);
+ corrections.longitudeDegrees = static_cast<double>(longitudeDegreesCorr);
+ corrections.altitudeMeters = static_cast<double>(altitudeDegreesCorr);
+ corrections.horizontalPositionUncertaintyMeters =
+ static_cast<double>(horizontalPositionUncertaintyMeters);
+ corrections.verticalPositionUncertaintyMeters =
+ static_cast<double>(verticalPositionUncertaintyMeters);
+ corrections.toaGpsNanosecondsOfWeek = static_cast<int64_t>(toaGpsNanosOfWeek);
+
+ jboolean hasEnvironmentBearingCorr =
+ env->CallBooleanMethod(correctionsObj, method_correctionsHasEnvironmentBearing);
+ jfloat environmentBearingDegreesCorr =
+ env->CallFloatMethod(correctionsObj, method_correctionsGetEnvironmentBearingDegrees);
+ jfloat environmentBearingUncertaintyDegreesCorr =
+ env->CallFloatMethod(correctionsObj,
+ method_correctionsGetEnvironmentBearingUncertaintyDegrees);
+
+ std::vector<SingleSatCorrection_Aidl> list(len);
+ MeasurementCorrectionsUtil::getSingleSatCorrectionList_Aidl(env, singleSatCorrectionList, list);
+ env->DeleteLocalRef(singleSatCorrectionList);
+
+ corrections.hasEnvironmentBearing = static_cast<bool>(hasEnvironmentBearingCorr);
+ corrections.environmentBearingDegrees = environmentBearingDegreesCorr;
+ corrections.environmentBearingUncertaintyDegrees = environmentBearingUncertaintyDegreesCorr;
+ corrections.satCorrections = list;
+ return true;
+}
+
+// Implementation of MeasurementCorrections (AIDL HAL)
+
+MeasurementCorrectionsIface_Aidl::MeasurementCorrectionsIface_Aidl(
+ const sp<IMeasurementCorrections_Aidl>& iMeasurementCorrections)
+ : mIMeasurementCorrectionsAidl(iMeasurementCorrections) {
+ assert(mIMeasurementCorrectionsAidl != nullptr);
+}
+
+jboolean MeasurementCorrectionsIface_Aidl::setCorrections(JNIEnv* env, jobject correctionsObj) {
+ MeasurementCorrections_Aidl measurementCorrections_aidl;
+ if (!MeasurementCorrectionsUtil::translateMeasurementCorrections<
+ MeasurementCorrections_Aidl>(env, correctionsObj, measurementCorrections_aidl)) {
+ ALOGI("Empty correction list injected....Returning with no HAL injection");
+ return JNI_TRUE;
+ }
+ auto status = mIMeasurementCorrectionsAidl->setCorrections(measurementCorrections_aidl);
+ return checkAidlStatus(status, "IMeasurementCorrectionsAidl setCorrections() failed");
+}
+
+jboolean MeasurementCorrectionsIface_Aidl::setCallback(
+ const std::unique_ptr<MeasurementCorrectionsCallback>& callback) {
+ auto status = mIMeasurementCorrectionsAidl->setCallback(callback->getAidl());
+ return checkAidlStatus(status, "IMeasurementCorrectionsAidl setCallback() failed.");
+}
+
+// Implementation of MeasurementCorrectionsIface_V1_0
+
+MeasurementCorrectionsIface_V1_0::MeasurementCorrectionsIface_V1_0(
+ const sp<IMeasurementCorrections_V1_0>& iMeasurementCorrections)
+ : mIMeasurementCorrections_V1_0(iMeasurementCorrections) {
+ assert(mIMeasurementCorrections_V1_0 != nullptr);
+}
+
+jboolean MeasurementCorrectionsIface_V1_0::setCorrections(JNIEnv* env, jobject correctionsObj) {
+ MeasurementCorrections_V1_0 measurementCorrections_1_0;
+ if (!MeasurementCorrectionsUtil::translateMeasurementCorrections<
+ MeasurementCorrections_V1_0>(env, correctionsObj, measurementCorrections_1_0)) {
+ ALOGI("Empty correction list injected....Returning with no HAL injection");
+ return JNI_TRUE;
+ }
+ auto result = mIMeasurementCorrections_V1_0->setCorrections(measurementCorrections_1_0);
+ return checkHidlReturn(result, "IMeasurementCorrections 1.0 setCorrections() failed.");
+}
+
+jboolean MeasurementCorrectionsIface_V1_0::setCallback(
+ const std::unique_ptr<MeasurementCorrectionsCallback>& callback) {
+ auto result = mIMeasurementCorrections_V1_0->setCallback(callback->getHidl());
+ return checkHidlReturn(result, "IMeasurementCorrections_V1_0 setCallback() failed.");
+}
+
+// Implementation of MeasurementCorrectionsIface_V1_1
+
+MeasurementCorrectionsIface_V1_1::MeasurementCorrectionsIface_V1_1(
+ const sp<IMeasurementCorrections_V1_1>& iMeasurementCorrections)
+ : mIMeasurementCorrections_V1_1(iMeasurementCorrections) {
+ assert(mIMeasurementCorrections_V1_1 != nullptr);
+}
+
+jboolean MeasurementCorrectionsIface_V1_1::setCorrections(JNIEnv* env, jobject correctionsObj) {
+ MeasurementCorrections_V1_1 measurementCorrections_1_1;
+ if (!MeasurementCorrectionsUtil::translateMeasurementCorrections<
+ MeasurementCorrections_V1_1>(env, correctionsObj, measurementCorrections_1_1)) {
+ ALOGI("Empty correction list injected....Returning with no HAL injection");
+ return JNI_TRUE;
+ }
+ auto result = mIMeasurementCorrections_V1_1->setCorrections_1_1(measurementCorrections_1_1);
+ return checkHidlReturn(result, "IMeasurementCorrections 1.1 setCorrections() failed.");
+}
+
+jboolean MeasurementCorrectionsIface_V1_1::setCallback(
+ const std::unique_ptr<MeasurementCorrectionsCallback>& callback) {
+ auto result = mIMeasurementCorrections_V1_1->setCallback(callback->getHidl());
+ return checkHidlReturn(result, "IMeasurementCorrections_V1_1 setCallback() failed.");
+}
+
+SingleSatCorrection_V1_0
+MeasurementCorrectionsUtil::getSingleSatCorrection_1_0_withoutConstellation(
+ JNIEnv* env, jobject singleSatCorrectionObj) {
+ jint correctionFlags = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags);
+ jint satId = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatId);
+ jfloat carrierFreqHz =
+ env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatCarrierFreq);
+ jfloat probSatIsLos =
+ env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatIsLosProb);
+ jfloat eplMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEpl);
+ jfloat eplUncMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEplUnc);
+ uint16_t corrFlags = static_cast<uint16_t>(correctionFlags);
+
+ ReflectingPlane_V1_0 reflectingPlane;
+ if ((corrFlags & GnssSingleSatCorrectionFlags_V1_0::HAS_REFLECTING_PLANE) != 0)
+ MeasurementCorrectionsUtil::getReflectingPlane<ReflectingPlane_V1_0>(env,
+ singleSatCorrectionObj,
+ reflectingPlane);
+
+ SingleSatCorrection_V1_0 singleSatCorrection = {
+ .singleSatCorrectionFlags = corrFlags,
+ .svid = static_cast<uint16_t>(satId),
+ .carrierFrequencyHz = carrierFreqHz,
+ .probSatIsLos = probSatIsLos,
+ .excessPathLengthMeters = eplMeters,
+ .excessPathLengthUncertaintyMeters = eplUncMeters,
+ .reflectingPlane = reflectingPlane,
+ };
+
+ return singleSatCorrection;
+}
+
+SingleSatCorrection_Aidl MeasurementCorrectionsUtil::getSingleSatCorrection_Aidl(
+ JNIEnv* env, jobject singleSatCorrectionObj) {
+ jint correctionFlags = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags);
+ jint satId = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatId);
+ jfloat carrierFreqHz =
+ env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatCarrierFreq);
+ jfloat probSatIsLos =
+ env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatIsLosProb);
+ jfloat eplMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEpl);
+ jfloat eplUncMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEplUnc);
+ int32_t corrFlags = static_cast<int32_t>(correctionFlags);
+
+ ReflectingPlane_Aidl reflectingPlane;
+ if ((corrFlags & SingleSatCorrection_Aidl::SINGLE_SAT_CORRECTION_HAS_REFLECTING_PLANE) != 0)
+ MeasurementCorrectionsUtil::getReflectingPlane<ReflectingPlane_Aidl>(env,
+ singleSatCorrectionObj,
+ reflectingPlane);
+
+ jint constType = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatConstType);
+
+ SingleSatCorrection_Aidl singleSatCorrection;
+ singleSatCorrection.singleSatCorrectionFlags = corrFlags;
+ singleSatCorrection.constellation = static_cast<GnssConstellationType_Aidl>(constType);
+ singleSatCorrection.svid = static_cast<int32_t>(satId);
+ singleSatCorrection.carrierFrequencyHz = carrierFreqHz;
+ singleSatCorrection.probSatIsLos = probSatIsLos;
+ singleSatCorrection.excessPathLengthMeters = eplMeters;
+ singleSatCorrection.excessPathLengthUncertaintyMeters = eplUncMeters;
+ singleSatCorrection.reflectingPlane = reflectingPlane;
+
+ return singleSatCorrection;
+}
+
+void MeasurementCorrectionsUtil::getSingleSatCorrectionList_1_0(
+ JNIEnv* env, jobject singleSatCorrectionList,
+ hardware::hidl_vec<SingleSatCorrection_V1_0>& list) {
+ for (uint16_t i = 0; i < list.size(); ++i) {
+ jobject singleSatCorrectionObj =
+ env->CallObjectMethod(singleSatCorrectionList, method_correctionListGet, i);
+
+ SingleSatCorrection_V1_0 singleSatCorrection =
+ getSingleSatCorrection_1_0_withoutConstellation(env, singleSatCorrectionObj);
+
+ jint constType = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatConstType);
+
+ singleSatCorrection.constellation = static_cast<GnssConstellationType_V1_0>(constType),
+
+ list[i] = singleSatCorrection;
+ env->DeleteLocalRef(singleSatCorrectionObj);
+ }
+}
+
+void MeasurementCorrectionsUtil::getSingleSatCorrectionList_1_1(
+ JNIEnv* env, jobject singleSatCorrectionList,
+ hardware::hidl_vec<SingleSatCorrection_V1_1>& list) {
+ for (uint16_t i = 0; i < list.size(); ++i) {
+ jobject singleSatCorrectionObj =
+ env->CallObjectMethod(singleSatCorrectionList, method_correctionListGet, i);
+
+ SingleSatCorrection_V1_0 singleSatCorrection_1_0 =
+ getSingleSatCorrection_1_0_withoutConstellation(env, singleSatCorrectionObj);
+
+ jint constType = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatConstType);
+
+ SingleSatCorrection_V1_1 singleSatCorrection_1_1 = {
+ .v1_0 = singleSatCorrection_1_0,
+ .constellation = static_cast<GnssConstellationType_V2_0>(constType),
+ };
+
+ list[i] = singleSatCorrection_1_1;
+ env->DeleteLocalRef(singleSatCorrectionObj);
+ }
+}
+
+void MeasurementCorrectionsUtil::getSingleSatCorrectionList_Aidl(
+ JNIEnv* env, jobject singleSatCorrectionList, std::vector<SingleSatCorrection_Aidl>& list) {
+ for (uint16_t i = 0; i < list.size(); ++i) {
+ jobject singleSatCorrectionObj =
+ env->CallObjectMethod(singleSatCorrectionList, method_correctionListGet, i);
+
+ SingleSatCorrection_Aidl singleSatCorrection_Aidl =
+ getSingleSatCorrection_Aidl(env, singleSatCorrectionObj);
+
+ list[i] = singleSatCorrection_Aidl;
+ env->DeleteLocalRef(singleSatCorrectionObj);
+ }
+}
+
+} // namespace android::gnss
diff --git a/services/core/jni/gnss/MeasurementCorrections.h b/services/core/jni/gnss/MeasurementCorrections.h
new file mode 100644
index 0000000..a2e6027
--- /dev/null
+++ b/services/core/jni/gnss/MeasurementCorrections.h
@@ -0,0 +1,158 @@
+/*
+ * 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.
+ */
+
+#ifndef _ANDROID_SERVER_MEASUREMENTCORRECTIONS_H
+#define _ANDROID_SERVER_MEASUREMENTCORRECTIONS_H
+
+#pragma once
+
+#ifndef LOG_TAG
+#error LOG_TAG must be defined before including this file.
+#endif
+
+#include <android/hardware/gnss/measurement_corrections/BnMeasurementCorrectionsInterface.h>
+#include <log/log.h>
+
+#include "MeasurementCorrectionsCallback.h"
+#include "jni.h"
+
+namespace android::gnss {
+
+namespace {
+extern jmethodID method_correctionsGetLatitudeDegrees;
+extern jmethodID method_correctionsGetLongitudeDegrees;
+extern jmethodID method_correctionsGetAltitudeMeters;
+extern jmethodID method_correctionsGetHorPosUncMeters;
+extern jmethodID method_correctionsGetVerPosUncMeters;
+extern jmethodID method_correctionsGetToaGpsNanosecondsOfWeek;
+extern jmethodID method_correctionsGetSingleSatCorrectionList;
+extern jmethodID method_correctionsHasEnvironmentBearing;
+extern jmethodID method_correctionsGetEnvironmentBearingDegrees;
+extern jmethodID method_correctionsGetEnvironmentBearingUncertaintyDegrees;
+extern jmethodID method_listSize;
+extern jmethodID method_correctionListGet;
+extern jmethodID method_correctionSatFlags;
+extern jmethodID method_correctionSatConstType;
+extern jmethodID method_correctionSatId;
+extern jmethodID method_correctionSatCarrierFreq;
+extern jmethodID method_correctionSatIsLosProb;
+extern jmethodID method_correctionSatEpl;
+extern jmethodID method_correctionSatEplUnc;
+extern jmethodID method_correctionSatRefPlane;
+extern jmethodID method_correctionPlaneLatDeg;
+extern jmethodID method_correctionPlaneLngDeg;
+extern jmethodID method_correctionPlaneAltDeg;
+extern jmethodID method_correctionPlaneAzimDeg;
+} // anonymous namespace
+
+void MeasurementCorrections_class_init_once(JNIEnv* env, jclass clazz);
+
+class MeasurementCorrectionsInterface {
+public:
+ virtual ~MeasurementCorrectionsInterface() {}
+ virtual jboolean setCorrections(JNIEnv* env, jobject correctionsObj) = 0;
+ virtual jboolean setCallback(
+ const std::unique_ptr<MeasurementCorrectionsCallback>& callback) = 0;
+};
+
+class MeasurementCorrectionsIface_Aidl : public MeasurementCorrectionsInterface {
+public:
+ MeasurementCorrectionsIface_Aidl(
+ const sp<android::hardware::gnss::measurement_corrections::
+ IMeasurementCorrectionsInterface>& iMeasurementCorrections);
+ jboolean setCorrections(JNIEnv* env, jobject correctionsObj) override;
+ jboolean setCallback(const std::unique_ptr<MeasurementCorrectionsCallback>& callback) override;
+
+private:
+ const sp<android::hardware::gnss::measurement_corrections::IMeasurementCorrectionsInterface>
+ mIMeasurementCorrectionsAidl;
+};
+
+class MeasurementCorrectionsIface_V1_0 : public MeasurementCorrectionsInterface {
+public:
+ MeasurementCorrectionsIface_V1_0(
+ const sp<android::hardware::gnss::measurement_corrections::V1_0::
+ IMeasurementCorrections>& iMeasurementCorrections);
+ jboolean setCorrections(JNIEnv* env, jobject correctionsObj) override;
+ jboolean setCallback(const std::unique_ptr<MeasurementCorrectionsCallback>& callback) override;
+
+private:
+ const sp<android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections>
+ mIMeasurementCorrections_V1_0;
+};
+
+class MeasurementCorrectionsIface_V1_1 : public MeasurementCorrectionsInterface {
+public:
+ MeasurementCorrectionsIface_V1_1(
+ const sp<android::hardware::gnss::measurement_corrections::V1_1::
+ IMeasurementCorrections>& iMeasurementCorrections);
+ jboolean setCorrections(JNIEnv* env, jobject correctionsObj) override;
+ jboolean setCallback(const std::unique_ptr<MeasurementCorrectionsCallback>& callback) override;
+
+private:
+ const sp<android::hardware::gnss::measurement_corrections::V1_1::IMeasurementCorrections>
+ mIMeasurementCorrections_V1_1;
+};
+
+struct MeasurementCorrectionsUtil {
+ static android::hardware::gnss::measurement_corrections::V1_0::SingleSatCorrection
+ getSingleSatCorrection_1_0_withoutConstellation(JNIEnv* env, jobject singleSatCorrectionObj);
+ static android::hardware::gnss::measurement_corrections::SingleSatCorrection
+ getSingleSatCorrection_Aidl(JNIEnv* env, jobject singleSatCorrectionObj);
+ static void getSingleSatCorrectionList_1_1(
+ JNIEnv* env, jobject singleSatCorrectionList,
+ hardware::hidl_vec<
+ android::hardware::gnss::measurement_corrections::V1_1::SingleSatCorrection>&
+ list);
+ static void getSingleSatCorrectionList_1_0(
+ JNIEnv* env, jobject singleSatCorrectionList,
+ hardware::hidl_vec<
+ android::hardware::gnss::measurement_corrections::V1_0::SingleSatCorrection>&
+ list);
+ static void getSingleSatCorrectionList_Aidl(
+ JNIEnv* env, jobject singleSatCorrectionList,
+ std::vector<android::hardware::gnss::measurement_corrections::SingleSatCorrection>&
+ list);
+ template <class T>
+ static bool translateMeasurementCorrections(JNIEnv* env, jobject correctionsObj,
+ T& corrections);
+ template <class T>
+ static void getReflectingPlane(JNIEnv* env, jobject singleSatCorrectionObj, T& reflectingPlane);
+};
+
+template <class T>
+void MeasurementCorrectionsUtil::getReflectingPlane(JNIEnv* env, jobject singleSatCorrectionObj,
+ T& reflectingPlane) {
+ jobject reflectingPlaneObj =
+ env->CallObjectMethod(singleSatCorrectionObj, method_correctionSatRefPlane);
+ jdouble latitudeDegreesRefPlane =
+ env->CallDoubleMethod(reflectingPlaneObj, method_correctionPlaneLatDeg);
+ jdouble longitudeDegreesRefPlane =
+ env->CallDoubleMethod(reflectingPlaneObj, method_correctionPlaneLngDeg);
+ jdouble altitudeDegreesRefPlane =
+ env->CallDoubleMethod(reflectingPlaneObj, method_correctionPlaneAltDeg);
+ jdouble azimuthDegreeRefPlane =
+ env->CallDoubleMethod(reflectingPlaneObj, method_correctionPlaneAzimDeg);
+ reflectingPlane.latitudeDegrees = latitudeDegreesRefPlane;
+ reflectingPlane.longitudeDegrees = longitudeDegreesRefPlane;
+ reflectingPlane.altitudeMeters = altitudeDegreesRefPlane;
+ reflectingPlane.azimuthDegrees = azimuthDegreeRefPlane;
+ env->DeleteLocalRef(reflectingPlaneObj);
+}
+
+} // namespace android::gnss
+
+#endif // _ANDROID_SERVER_MEASUREMENTCORRECTIONS_H
diff --git a/services/core/jni/gnss/MeasurementCorrectionsCallback.cpp b/services/core/jni/gnss/MeasurementCorrectionsCallback.cpp
new file mode 100644
index 0000000..a319a0d
--- /dev/null
+++ b/services/core/jni/gnss/MeasurementCorrectionsCallback.cpp
@@ -0,0 +1,59 @@
+/*
+ * 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 "MeasurementCorrectionsCbJni"
+
+#include "MeasurementCorrectionsCallback.h"
+
+namespace android::gnss {
+
+namespace {
+jmethodID method_setSubHalMeasurementCorrectionsCapabilities;
+}
+
+void MeasurementCorrectionsCallback_class_init_once(JNIEnv* env, jclass clazz) {
+ method_setSubHalMeasurementCorrectionsCapabilities =
+ env->GetMethodID(clazz, "setSubHalMeasurementCorrectionsCapabilities", "(I)V");
+}
+
+using binder::Status;
+using hardware::Return;
+
+// Implementation of MeasurementCorrectionsCallbackAidl class.
+
+Status MeasurementCorrectionsCallbackAidl::setCapabilitiesCb(const int capabilities) {
+ MeasurementCorrectionsCallbackUtil::setCapabilitiesCb(capabilities);
+ return Status::ok();
+}
+
+// Implementation of MeasurementCorrectionsCallbackHidl class.
+
+Return<void> MeasurementCorrectionsCallbackHidl::setCapabilitiesCb(uint32_t capabilities) {
+ MeasurementCorrectionsCallbackUtil::setCapabilitiesCb(capabilities);
+ return hardware::Void();
+}
+
+// Implementation of MeasurementCorrectionsCallbackUtil class.
+
+void MeasurementCorrectionsCallbackUtil::setCapabilitiesCb(uint32_t capabilities) {
+ ALOGD("%s: %du\n", __func__, capabilities);
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_setSubHalMeasurementCorrectionsCapabilities,
+ capabilities);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+} // namespace android::gnss
diff --git a/services/core/jni/gnss/MeasurementCorrectionsCallback.h b/services/core/jni/gnss/MeasurementCorrectionsCallback.h
new file mode 100644
index 0000000..a493a8ae
--- /dev/null
+++ b/services/core/jni/gnss/MeasurementCorrectionsCallback.h
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+#ifndef _ANDROID_SERVER_GNSS_MEASUREMENTCORRECTIONSCALLBACK_H
+#define _ANDROID_SERVER_GNSS_MEASUREMENTCORRECTIONSCALLBACK_H
+
+#pragma once
+
+#ifndef LOG_TAG
+#error LOG_TAG must be defined before including this file.
+#endif
+
+#include <android/hardware/gnss/measurement_corrections/1.0/IMeasurementCorrections.h>
+#include <android/hardware/gnss/measurement_corrections/1.1/IMeasurementCorrections.h>
+#include <android/hardware/gnss/measurement_corrections/BnMeasurementCorrectionsCallback.h>
+#include <log/log.h>
+
+#include "Utils.h"
+#include "jni.h"
+
+namespace android::gnss {
+
+namespace {
+extern jmethodID method_setSubHalMeasurementCorrectionsCapabilities;
+}
+
+void MeasurementCorrectionsCallback_class_init_once(JNIEnv* env, jclass clazz);
+
+/*
+ * MeasurementCorrectionsCallbackAidl class implements the callback methods required by the
+ * android::hardware::gnss::measurement_corrections::IMeasurementCorrectionsCallback interface.
+ */
+class MeasurementCorrectionsCallbackAidl
+ : public hardware::gnss::measurement_corrections::BnMeasurementCorrectionsCallback {
+public:
+ MeasurementCorrectionsCallbackAidl() {}
+ binder::Status setCapabilitiesCb(const int capabilities) override;
+};
+
+/*
+ * MeasurementCorrectionsCallbackHidl implements callback methods of
+ * IMeasurementCorrectionsCallback.hal interface.
+ */
+class MeasurementCorrectionsCallbackHidl : public android::hardware::gnss::measurement_corrections::
+ V1_0::IMeasurementCorrectionsCallback {
+public:
+ MeasurementCorrectionsCallbackHidl() {}
+ hardware::Return<void> setCapabilitiesCb(uint32_t capabilities) override;
+};
+
+class MeasurementCorrectionsCallback {
+public:
+ MeasurementCorrectionsCallback() {}
+ sp<MeasurementCorrectionsCallbackAidl> getAidl() {
+ if (callbackAidl == nullptr) {
+ callbackAidl = sp<MeasurementCorrectionsCallbackAidl>::make();
+ }
+ return callbackAidl;
+ }
+
+ sp<MeasurementCorrectionsCallbackHidl> getHidl() {
+ if (callbackHidl == nullptr) {
+ callbackHidl = sp<MeasurementCorrectionsCallbackHidl>::make();
+ }
+ return callbackHidl;
+ }
+
+private:
+ sp<MeasurementCorrectionsCallbackAidl> callbackAidl;
+ sp<MeasurementCorrectionsCallbackHidl> callbackHidl;
+};
+
+struct MeasurementCorrectionsCallbackUtil {
+ static void setCapabilitiesCb(uint32_t capabilities);
+
+private:
+ MeasurementCorrectionsCallbackUtil() = delete;
+};
+
+} // namespace android::gnss
+
+#endif // _ANDROID_SERVER_GNSS_MEASUREMENTCORRECTIONSCALLBACK_H
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index ebfa2c6..091d879 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -7331,7 +7331,7 @@
}
@Override
- public void reportPasswordChanged(@UserIdInt int userId) {
+ public void reportPasswordChanged(PasswordMetrics metrics, @UserIdInt int userId) {
if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
return;
}
@@ -7363,6 +7363,10 @@
affectedUserIds.addAll(removeCaApprovalsIfNeeded(userId));
saveSettingsForUsersLocked(affectedUserIds);
}
+ if (mInjector.securityLogIsLoggingEnabled()) {
+ SecurityLog.writeEvent(SecurityLog.TAG_PASSWORD_CHANGED,
+ /* complexity */ metrics.determineComplexity(), /*user*/ userId);
+ }
}
/**
@@ -9616,18 +9620,22 @@
"Cannot set the profile owner on a user which is already set-up");
if (!mIsWatch) {
- // Only the default supervision profile owner can be set as profile owner after SUW
+ final String supervisionRolePackage = mContext.getResources().getString(
+ com.android.internal.R.string.config_systemSupervision);
+ // Only the default supervision profile owner or supervision role holder
+ // can be set as profile owner after SUW
final String supervisor = mContext.getResources().getString(
com.android.internal.R.string
.config_defaultSupervisionProfileOwnerComponent);
- if (supervisor == null) {
+ if (supervisor == null && supervisionRolePackage == null) {
throw new IllegalStateException("Unable to set profile owner post-setup, no"
+ "default supervisor profile owner defined");
}
final ComponentName supervisorComponent = ComponentName.unflattenFromString(
supervisor);
- if (!owner.equals(supervisorComponent)) {
+ if (!owner.equals(supervisorComponent)
+ && !owner.getPackageName().equals(supervisionRolePackage)) {
throw new IllegalStateException("Unable to set non-default profile owner"
+ " post-setup " + owner);
}
@@ -10982,13 +10990,12 @@
}
@Override
- public void acknowledgeNewUserDisclaimer() {
+ public void acknowledgeNewUserDisclaimer(@UserIdInt int userId) {
CallerIdentity callerIdentity = getCallerIdentity();
Preconditions.checkCallAuthorization(canManageUsers(callerIdentity)
|| hasCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS));
- setShowNewUserDisclaimer(callerIdentity.getUserId(),
- DevicePolicyData.NEW_USER_DISCLAIMER_ACKNOWLEDGED);
+ setShowNewUserDisclaimer(userId, DevicePolicyData.NEW_USER_DISCLAIMER_ACKNOWLEDGED);
}
private void setShowNewUserDisclaimer(@UserIdInt int userId, String value) {
@@ -11021,11 +11028,10 @@
}
@Override
- public boolean isNewUserDisclaimerAcknowledged() {
+ public boolean isNewUserDisclaimerAcknowledged(@UserIdInt int userId) {
CallerIdentity callerIdentity = getCallerIdentity();
Preconditions.checkCallAuthorization(canManageUsers(callerIdentity)
|| hasCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS));
- int userId = callerIdentity.getUserId();
synchronized (getLockObject()) {
DevicePolicyData policyData = getUserData(userId);
return policyData.isNewUserDisclaimerAcknowledged();
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a7539b5..5c3721d 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -264,6 +264,10 @@
"com.android.server.companion.virtual.VirtualDeviceManagerService";
private static final String STATS_COMPANION_APEX_PATH =
"/apex/com.android.os.statsd/javalib/service-statsd.jar";
+ private static final String SCHEDULING_APEX_PATH =
+ "/apex/com.android.scheduling/javalib/service-scheduling.jar";
+ private static final String REBOOT_READINESS_LIFECYCLE_CLASS =
+ "com.android.server.scheduling.RebootReadinessManagerService$Lifecycle";
private static final String CONNECTIVITY_SERVICE_APEX_PATH =
"/apex/com.android.tethering/javalib/service-connectivity.jar";
private static final String STATS_COMPANION_LIFECYCLE_CLASS =
@@ -2575,6 +2579,12 @@
STATS_COMPANION_LIFECYCLE_CLASS, STATS_COMPANION_APEX_PATH);
t.traceEnd();
+ // Reboot Readiness
+ t.traceBegin("StartRebootReadinessManagerService");
+ mSystemServiceManager.startServiceFromJar(
+ REBOOT_READINESS_LIFECYCLE_CLASS, SCHEDULING_APEX_PATH);
+ t.traceEnd();
+
// Statsd pulled atoms
t.traceBegin("StartStatsPullAtomService");
mSystemServiceManager.startService(STATS_PULL_ATOM_SERVICE_CLASS);
diff --git a/services/midi/java/com/android/server/midi/MidiService.java b/services/midi/java/com/android/server/midi/MidiService.java
index 717168f..f72b23c 100644
--- a/services/midi/java/com/android/server/midi/MidiService.java
+++ b/services/midi/java/com/android/server/midi/MidiService.java
@@ -43,6 +43,7 @@
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.ParcelUuid;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -64,6 +65,14 @@
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+import java.util.UUID;
+
+// NOTE about locking order:
+// if there is a path that syncs on BOTH mDevicesByInfo AND mDeviceConnections,
+// this order must be observed
+// 1. synchronized (mDevicesByInfo)
+// 2. synchronized (mDeviceConnections)
+//TODO Introduce a single lock object to lock the whole state and avoid the requirement above.
public class MidiService extends IMidiManager.Stub {
@@ -122,6 +131,9 @@
// UID of BluetoothMidiService
private int mBluetoothServiceUid;
+ private static final UUID MIDI_SERVICE = UUID.fromString(
+ "03B80E5A-EDE8-4B33-A751-6CE34EC4C700");
+
// PackageMonitor for listening to package changes
private final PackageMonitor mPackageMonitor = new PackageMonitor() {
@Override
@@ -434,14 +446,19 @@
public void onServiceConnected(ComponentName name, IBinder service) {
IMidiDeviceServer server = null;
if (mBluetoothDevice != null) {
- IBluetoothMidiService mBluetoothMidiService = IBluetoothMidiService.Stub.asInterface(service);
- try {
- // We need to explicitly add the device in a separate method
- // because onBind() is only called once.
- IBinder deviceBinder = mBluetoothMidiService.addBluetoothDevice(mBluetoothDevice);
- server = IMidiDeviceServer.Stub.asInterface(deviceBinder);
- } catch(RemoteException e) {
- Log.e(TAG, "Could not call addBluetoothDevice()", e);
+ IBluetoothMidiService mBluetoothMidiService =
+ IBluetoothMidiService.Stub.asInterface(service);
+ if (mBluetoothMidiService != null) {
+ try {
+ // We need to explicitly add the device in a separate method
+ // because onBind() is only called once.
+ IBinder deviceBinder =
+ mBluetoothMidiService.addBluetoothDevice(
+ mBluetoothDevice);
+ server = IMidiDeviceServer.Stub.asInterface(deviceBinder);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not call addBluetoothDevice()", e);
+ }
}
} else {
server = IMidiDeviceServer.Stub.asInterface(service);
@@ -482,19 +499,19 @@
}
public void removeDeviceConnection(DeviceConnection connection) {
- synchronized (mDeviceConnections) {
- mDeviceConnections.remove(connection);
+ synchronized (mDevicesByInfo) {
+ synchronized (mDeviceConnections) {
+ mDeviceConnections.remove(connection);
- if (mDeviceConnections.size() == 0 && mServiceConnection != null) {
- mContext.unbindService(mServiceConnection);
- mServiceConnection = null;
- if (mBluetoothDevice != null) {
- // Bluetooth devices are ephemeral - remove when no clients exist
- synchronized (mDevicesByInfo) {
+ if (mDeviceConnections.size() == 0 && mServiceConnection != null) {
+ mContext.unbindService(mServiceConnection);
+ mServiceConnection = null;
+ if (mBluetoothDevice != null) {
+ // Bluetooth devices are ephemeral - remove when no clients exist
closeLocked();
+ } else {
+ setDeviceServer(null);
}
- } else {
- setDeviceServer(null);
}
}
}
@@ -589,6 +606,20 @@
}
}
+ // Note, this isn't useful at connect-time because the service UUIDs haven't
+ // been gathered yet.
+ private boolean isBLEMIDIDevice(BluetoothDevice btDevice) {
+ ParcelUuid[] uuids = btDevice.getUuids();
+ if (uuids != null) {
+ for (ParcelUuid uuid : uuids) {
+ if (uuid.getUuid().equals(MIDI_SERVICE)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
private final BroadcastReceiver mBleMidiReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -603,6 +634,8 @@
Log.d(TAG, "ACTION_ACL_CONNECTED");
BluetoothDevice btDevice =
intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ // We can't determine here if this is a BLD-MIDI device, so go ahead and try
+ // to open as a MIDI device, further down it will get figured out.
openBluetoothDevice(btDevice);
}
break;
@@ -611,7 +644,11 @@
Log.d(TAG, "ACTION_ACL_DISCONNECTED");
BluetoothDevice btDevice =
intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
- closeBluetoothDevice(btDevice);
+ // We DO know at this point if we are disconnecting a MIDI device, so
+ // don't bother if we are not.
+ if (isBLEMIDIDevice(btDevice)) {
+ closeBluetoothDevice(btDevice);
+ }
}
break;
}
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index 62a16f7..c5f990d 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 @@
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 @@
}
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 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 @@
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 5d01d3e..0e081f1 100644
--- a/services/proguard.flags
+++ b/services/proguard.flags
@@ -1,21 +1,105 @@
-# 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 *;
-}
-# Various classes subclassed in ethernet-service (avoid marking final).
--keep public class android.net.** { *; }
-
-# Referenced via CarServiceHelperService in car-frameworks-service (avoid removing).
--keep public class com.android.server.utils.Slogf { *; }
+# 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
-# 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 *;
+# 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 * extends android.app.backup.BackupAgent
+-keep,allowoptimization,allowaccessmodification class * extends android.content.BroadcastReceiver
+-keep,allowoptimization,allowaccessmodification class * extends android.content.ContentProvider
+
+# 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)
+-keep public class com.android.server.utils.Slogf { *; }
+
+# 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.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* { *; }
+
+# 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/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index cc663d9..11300ce 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -508,7 +508,8 @@
AndroidPackage::shouldInheritKeyStoreKeys,
ParsingPackage::setInheritKeyStoreKeys,
true
- )
+ ),
+ getter(AndroidPackage::getKnownActivityEmbeddingCerts, setOf("TESTEMBEDDINGCERT"))
)
override fun initialObject() = PackageImpl.forParsing(
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt
index a89b717..5180786 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt
@@ -53,7 +53,7 @@
ParsedActivity::getTaskAffinity,
ParsedActivity::getTheme,
ParsedActivity::getUiOptions,
- ParsedActivity::isSupportsSizeChanges,
+ ParsedActivity::isSupportsSizeChanges
)
override fun mainComponentSubclassExtraParams() = listOf(
@@ -73,6 +73,7 @@
ActivityInfo.WindowLayout::minHeight
)
}
- )
+ ),
+ getter(ParsedActivity::getKnownActivityEmbeddingCerts, setOf("TESTEMBEDDINGCERT"))
)
}
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index 75669d5..3e60af3 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -53,6 +53,7 @@
"service-jobscheduler",
"service-permission.impl",
"service-supplementalprocess.impl",
+ "services.companion",
"services.core",
"services.devicepolicy",
"services.net",
diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
index d710308..ac115a2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
@@ -30,7 +30,6 @@
import static com.android.server.DeviceIdleController.LIGHT_STATE_IDLE_MAINTENANCE;
import static com.android.server.DeviceIdleController.LIGHT_STATE_INACTIVE;
import static com.android.server.DeviceIdleController.LIGHT_STATE_OVERRIDE;
-import static com.android.server.DeviceIdleController.LIGHT_STATE_PRE_IDLE;
import static com.android.server.DeviceIdleController.LIGHT_STATE_WAITING_FOR_NETWORK;
import static com.android.server.DeviceIdleController.MSG_REPORT_STATIONARY_STATUS;
import static com.android.server.DeviceIdleController.MSG_RESET_PRE_IDLE_TIMEOUT_FACTOR;
@@ -112,6 +111,7 @@
/**
* Tests for {@link com.android.server.DeviceIdleController}.
*/
+@SuppressWarnings("GuardedBy")
@RunWith(AndroidJUnit4.class)
public class DeviceIdleControllerTest {
private DeviceIdleController mDeviceIdleController;
@@ -875,7 +875,7 @@
@Test
public void testLightStepIdleStateLocked_InvalidStates() {
mDeviceIdleController.becomeActiveLocked("testing", 0);
- mDeviceIdleController.stepLightIdleStateLocked("testing");
+ mDeviceIdleController.stepLightIdleStateLocked("testing", true);
// stepLightIdleStateLocked doesn't handle the ACTIVE case, so the state
// should stay as ACTIVE.
verifyLightStateConditions(LIGHT_STATE_ACTIVE);
@@ -888,7 +888,7 @@
@Test
public void testLightStepIdleStateLocked_Overriden() {
enterLightState(LIGHT_STATE_OVERRIDE);
- mDeviceIdleController.stepLightIdleStateLocked("testing");
+ mDeviceIdleController.stepLightIdleStateLocked("testing", true);
verifyLightStateConditions(LIGHT_STATE_OVERRIDE);
}
@@ -906,18 +906,18 @@
verifyLightStateConditions(LIGHT_STATE_INACTIVE);
// No active ops means INACTIVE should go straight to IDLE.
- mDeviceIdleController.stepLightIdleStateLocked("testing");
+ mDeviceIdleController.stepLightIdleStateLocked("testing", true);
verifyLightStateConditions(LIGHT_STATE_IDLE);
// Should just alternate between IDLE and IDLE_MAINTENANCE now.
- mDeviceIdleController.stepLightIdleStateLocked("testing");
+ mDeviceIdleController.stepLightIdleStateLocked("testing", true);
verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
- mDeviceIdleController.stepLightIdleStateLocked("testing");
+ mDeviceIdleController.stepLightIdleStateLocked("testing", true);
verifyLightStateConditions(LIGHT_STATE_IDLE);
- mDeviceIdleController.stepLightIdleStateLocked("testing");
+ mDeviceIdleController.stepLightIdleStateLocked("testing", true);
verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
}
@@ -930,26 +930,22 @@
setScreenOn(false);
verifyLightStateConditions(LIGHT_STATE_INACTIVE);
- // Active ops means INACTIVE should go to PRE_IDLE to wait.
+ // After enough time, INACTIVE should go to IDLE regardless of any active ops.
mDeviceIdleController.setJobsActive(true);
mDeviceIdleController.setAlarmsActive(true);
mDeviceIdleController.setActiveIdleOpsForTest(1);
- mDeviceIdleController.stepLightIdleStateLocked("testing");
- verifyLightStateConditions(LIGHT_STATE_PRE_IDLE);
-
- // Even with active ops, PRE_IDLE should go to IDLE.
- mDeviceIdleController.stepLightIdleStateLocked("testing");
+ mDeviceIdleController.stepLightIdleStateLocked("testing", true);
verifyLightStateConditions(LIGHT_STATE_IDLE);
// Should just alternate between IDLE and IDLE_MAINTENANCE now.
- mDeviceIdleController.stepLightIdleStateLocked("testing");
+ mDeviceIdleController.stepLightIdleStateLocked("testing", true);
verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
- mDeviceIdleController.stepLightIdleStateLocked("testing");
+ mDeviceIdleController.stepLightIdleStateLocked("testing", true);
verifyLightStateConditions(LIGHT_STATE_IDLE);
- mDeviceIdleController.stepLightIdleStateLocked("testing");
+ mDeviceIdleController.stepLightIdleStateLocked("testing", true);
verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
}
@@ -967,24 +963,24 @@
verifyLightStateConditions(LIGHT_STATE_INACTIVE);
// No active ops means INACTIVE should go straight to IDLE.
- mDeviceIdleController.stepLightIdleStateLocked("testing");
+ mDeviceIdleController.stepLightIdleStateLocked("testing", true);
verifyLightStateConditions(LIGHT_STATE_IDLE);
// Should cycle between IDLE, WAITING_FOR_NETWORK, and IDLE_MAINTENANCE now.
- mDeviceIdleController.stepLightIdleStateLocked("testing");
+ mDeviceIdleController.stepLightIdleStateLocked("testing", true);
verifyLightStateConditions(LIGHT_STATE_WAITING_FOR_NETWORK);
- mDeviceIdleController.stepLightIdleStateLocked("testing");
+ mDeviceIdleController.stepLightIdleStateLocked("testing", true);
verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
- mDeviceIdleController.stepLightIdleStateLocked("testing");
+ mDeviceIdleController.stepLightIdleStateLocked("testing", true);
verifyLightStateConditions(LIGHT_STATE_IDLE);
- mDeviceIdleController.stepLightIdleStateLocked("testing");
+ mDeviceIdleController.stepLightIdleStateLocked("testing", true);
verifyLightStateConditions(LIGHT_STATE_WAITING_FOR_NETWORK);
- mDeviceIdleController.stepLightIdleStateLocked("testing");
+ mDeviceIdleController.stepLightIdleStateLocked("testing", true);
verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
}
@@ -997,36 +993,177 @@
setScreenOn(false);
verifyLightStateConditions(LIGHT_STATE_INACTIVE);
- // Active ops means INACTIVE should go to PRE_IDLE to wait.
+ // After enough time, INACTIVE should go to IDLE regardless of any active ops.
mDeviceIdleController.setJobsActive(true);
mDeviceIdleController.setAlarmsActive(true);
mDeviceIdleController.setActiveIdleOpsForTest(1);
- mDeviceIdleController.stepLightIdleStateLocked("testing");
- verifyLightStateConditions(LIGHT_STATE_PRE_IDLE);
-
- // Even with active ops, PRE_IDLE should go to IDLE.
- mDeviceIdleController.stepLightIdleStateLocked("testing");
+ mDeviceIdleController.stepLightIdleStateLocked("testing", true);
verifyLightStateConditions(LIGHT_STATE_IDLE);
// Should cycle between IDLE, WAITING_FOR_NETWORK, and IDLE_MAINTENANCE now.
- mDeviceIdleController.stepLightIdleStateLocked("testing");
+ mDeviceIdleController.stepLightIdleStateLocked("testing", true);
verifyLightStateConditions(LIGHT_STATE_WAITING_FOR_NETWORK);
- mDeviceIdleController.stepLightIdleStateLocked("testing");
+ mDeviceIdleController.stepLightIdleStateLocked("testing", true);
verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
- mDeviceIdleController.stepLightIdleStateLocked("testing");
+ mDeviceIdleController.stepLightIdleStateLocked("testing", true);
verifyLightStateConditions(LIGHT_STATE_IDLE);
- mDeviceIdleController.stepLightIdleStateLocked("testing");
+ mDeviceIdleController.stepLightIdleStateLocked("testing", true);
verifyLightStateConditions(LIGHT_STATE_WAITING_FOR_NETWORK);
- mDeviceIdleController.stepLightIdleStateLocked("testing");
+ mDeviceIdleController.stepLightIdleStateLocked("testing", true);
verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
}
@Test
+ public void testLightStepIdleStateSkippedAlarms() {
+ setNetworkConnected(true);
+ mDeviceIdleController.setJobsActive(false);
+ mDeviceIdleController.setAlarmsActive(false);
+ mDeviceIdleController.setActiveIdleOpsForTest(0);
+
+ final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListenerCaptor = ArgumentCaptor
+ .forClass(AlarmManager.OnAlarmListener.class);
+ doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(),
+ eq("DeviceIdleController.light"), alarmListenerCaptor.capture(), any());
+ doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(),
+ eq("DeviceIdleController.light"), alarmListenerCaptor.capture(), any());
+
+ // Set state to INACTIVE.
+ mDeviceIdleController.becomeActiveLocked("testing", 0);
+ setChargingOn(false);
+ setScreenOn(false);
+ verifyLightStateConditions(LIGHT_STATE_INACTIVE);
+
+ final AlarmManager.OnAlarmListener progressionListener =
+ alarmListenerCaptor.getAllValues().get(0);
+ final AlarmManager.OnAlarmListener maintenanceListener =
+ alarmListenerCaptor.getAllValues().get(1);
+
+ // Set things to make it look like the INACTIVE -> IDLE alarm didn't fire and the
+ // MAINTENANCE alarm just fired.
+ mInjector.nowElapsed = mDeviceIdleController.getNextLightMaintenanceAlarmTimeForTesting();
+ // If the non-wakeup alarm doesn't fire in a timely manner, we would see both fire at the
+ // same time.
+ progressionListener.onAlarm();
+ verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
+ maintenanceListener.onAlarm();
+ verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
+
+ assertTrue(mInjector.nowElapsed < mDeviceIdleController.getNextLightAlarmTimeForTesting());
+
+ // MAINTENANCE->IDLE alarm goes off at correct time.
+ mInjector.nowElapsed = mDeviceIdleController.getNextLightAlarmTimeForTesting();
+ progressionListener.onAlarm();
+ verifyLightStateConditions(LIGHT_STATE_IDLE);
+
+ // Go back to MAINTENANCE
+ mInjector.nowElapsed = mDeviceIdleController.getNextLightMaintenanceAlarmTimeForTesting();
+ maintenanceListener.onAlarm();
+ verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
+
+ assertTrue(mInjector.nowElapsed < mDeviceIdleController.getNextLightAlarmTimeForTesting());
+ assertTrue(mInjector.nowElapsed
+ < mDeviceIdleController.getNextLightMaintenanceAlarmTimeForTesting());
+
+ // MAINTENANCE->IDLE alarm is delayed until IDLE->MAINTENANCE alarm goes off.
+ mInjector.nowElapsed = mDeviceIdleController.getNextLightMaintenanceAlarmTimeForTesting();
+ progressionListener.onAlarm();
+ verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
+ maintenanceListener.onAlarm();
+ verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
+ }
+
+ @Test
+ public void testLightStepIdleStateIdlingTimeIncreases() {
+ final long maintenanceTimeMs = 60_000L;
+ mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET = maintenanceTimeMs;
+ mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET = maintenanceTimeMs;
+ mConstants.LIGHT_IDLE_TIMEOUT = 5 * 60_000L;
+ mConstants.LIGHT_MAX_IDLE_TIMEOUT = 20 * 60_000L;
+ mConstants.LIGHT_IDLE_FACTOR = 2f;
+
+ setNetworkConnected(true);
+ mDeviceIdleController.setJobsActive(false);
+ mDeviceIdleController.setAlarmsActive(false);
+ mDeviceIdleController.setActiveIdleOpsForTest(0);
+
+ InOrder alarmManagerInOrder = inOrder(mAlarmManager);
+
+ final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListenerCaptor = ArgumentCaptor
+ .forClass(AlarmManager.OnAlarmListener.class);
+ doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(),
+ eq("DeviceIdleController.light"), alarmListenerCaptor.capture(), any());
+ doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(),
+ eq("DeviceIdleController.light"), alarmListenerCaptor.capture(), any());
+
+ // Set state to INACTIVE.
+ mDeviceIdleController.becomeActiveLocked("testing", 0);
+ setChargingOn(false);
+ setScreenOn(false);
+ verifyLightStateConditions(LIGHT_STATE_INACTIVE);
+ long idlingTimeMs = mConstants.LIGHT_IDLE_TIMEOUT;
+ final long idleAfterInactiveExpiryTime =
+ mInjector.nowElapsed + mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT;
+ alarmManagerInOrder.verify(mAlarmManager).setWindow(
+ eq(AlarmManager.ELAPSED_REALTIME),
+ eq(idleAfterInactiveExpiryTime),
+ anyLong(), anyString(), any(), any());
+ // Maintenance alarm
+ alarmManagerInOrder.verify(mAlarmManager).setWindow(
+ eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
+ eq(idleAfterInactiveExpiryTime + idlingTimeMs),
+ anyLong(), anyString(), any(), any());
+
+ final AlarmManager.OnAlarmListener progressionListener =
+ alarmListenerCaptor.getAllValues().get(0);
+ final AlarmManager.OnAlarmListener maintenanceListener =
+ alarmListenerCaptor.getAllValues().get(1);
+
+ // INACTIVE -> IDLE alarm
+ mInjector.nowElapsed = mDeviceIdleController.getNextLightAlarmTimeForTesting();
+ progressionListener.onAlarm();
+ verifyLightStateConditions(LIGHT_STATE_IDLE);
+ alarmManagerInOrder.verify(mAlarmManager).setWindow(
+ eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
+ eq(mInjector.nowElapsed + idlingTimeMs),
+ anyLong(), anyString(), any(), any());
+
+ for (int i = 0; i < 2; ++i) {
+ // IDLE->MAINTENANCE alarm
+ mInjector.nowElapsed =
+ mDeviceIdleController.getNextLightMaintenanceAlarmTimeForTesting();
+ maintenanceListener.onAlarm();
+ verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
+ long maintenanceExpiryTime = mInjector.nowElapsed + maintenanceTimeMs;
+ idlingTimeMs *= mConstants.LIGHT_IDLE_FACTOR;
+ // Set MAINTENANCE->IDLE
+ alarmManagerInOrder.verify(mAlarmManager).setWindow(
+ eq(AlarmManager.ELAPSED_REALTIME),
+ eq(maintenanceExpiryTime),
+ anyLong(), anyString(), any(), any());
+ // Set IDLE->MAINTENANCE
+ alarmManagerInOrder.verify(mAlarmManager).setWindow(
+ eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
+ eq(maintenanceExpiryTime + idlingTimeMs),
+ anyLong(), anyString(), any(), any());
+
+ // MAINTENANCE->IDLE alarm
+ mInjector.nowElapsed = mDeviceIdleController.getNextLightAlarmTimeForTesting();
+ progressionListener.onAlarm();
+ verifyLightStateConditions(LIGHT_STATE_IDLE);
+ // Set IDLE->MAINTENANCE again
+ alarmManagerInOrder.verify(mAlarmManager).setWindow(
+ eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
+ eq(mInjector.nowElapsed + idlingTimeMs),
+ anyLong(), anyString(), any(), any());
+ }
+ }
+
+ @Test
public void testLightIdleAlarmUnaffectedByMotion() {
setNetworkConnected(true);
mDeviceIdleController.setJobsActive(false);
@@ -1043,45 +1180,37 @@
verifyLightStateConditions(LIGHT_STATE_INACTIVE);
// No active ops means INACTIVE should go straight to IDLE.
- mDeviceIdleController.stepLightIdleStateLocked("testing");
+ mDeviceIdleController.stepLightIdleStateLocked("testing", true);
verifyLightStateConditions(LIGHT_STATE_IDLE);
- inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked(
- longThat(l -> l == mConstants.LIGHT_IDLE_TIMEOUT),
- longThat(l -> l == mConstants.LIGHT_IDLE_TIMEOUT_INITIAL_FLEX),
- eq(false));
+ inOrder.verify(mDeviceIdleController).scheduleLightMaintenanceAlarmLocked(
+ longThat(l -> l == mConstants.LIGHT_IDLE_TIMEOUT));
// Should just alternate between IDLE and IDLE_MAINTENANCE now.
- mDeviceIdleController.stepLightIdleStateLocked("testing");
+ mDeviceIdleController.stepLightIdleStateLocked("testing", true);
verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked(
longThat(l -> l >= mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET),
- longThat(l -> l == mConstants.FLEX_TIME_SHORT),
- eq(true));
+ longThat(l -> l == mConstants.FLEX_TIME_SHORT));
- mDeviceIdleController.stepLightIdleStateLocked("testing");
+ mDeviceIdleController.stepLightIdleStateLocked("testing", true);
verifyLightStateConditions(LIGHT_STATE_IDLE);
- inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked(
- longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT),
- longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT_INITIAL_FLEX),
- eq(false));
+ inOrder.verify(mDeviceIdleController).scheduleLightMaintenanceAlarmLocked(
+ longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT));
- mDeviceIdleController.stepLightIdleStateLocked("testing");
+ mDeviceIdleController.stepLightIdleStateLocked("testing", true);
verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked(
longThat(l -> l >= mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET),
- longThat(l -> l == mConstants.FLEX_TIME_SHORT),
- eq(true));
+ longThat(l -> l == mConstants.FLEX_TIME_SHORT));
// Test that motion doesn't reset the idle timeout.
mDeviceIdleController.handleMotionDetectedLocked(50, "test");
- mDeviceIdleController.stepLightIdleStateLocked("testing");
+ mDeviceIdleController.stepLightIdleStateLocked("testing", true);
verifyLightStateConditions(LIGHT_STATE_IDLE);
- inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked(
- longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT),
- longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT_INITIAL_FLEX),
- eq(false));
+ inOrder.verify(mDeviceIdleController).scheduleLightMaintenanceAlarmLocked(
+ longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT));
}
///////////////// EXIT conditions ///////////////////
@@ -1268,10 +1397,6 @@
mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
verifyLightStateConditions(LIGHT_STATE_INACTIVE);
- enterLightState(LIGHT_STATE_PRE_IDLE);
- mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
- verifyLightStateConditions(LIGHT_STATE_IDLE);
-
enterLightState(LIGHT_STATE_IDLE);
mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
verifyLightStateConditions(LIGHT_STATE_IDLE);
@@ -1307,10 +1432,6 @@
mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
verifyLightStateConditions(LIGHT_STATE_INACTIVE);
- enterLightState(LIGHT_STATE_PRE_IDLE);
- mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
- verifyLightStateConditions(LIGHT_STATE_PRE_IDLE);
-
enterLightState(LIGHT_STATE_IDLE);
mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
verifyLightStateConditions(LIGHT_STATE_IDLE);
@@ -1344,10 +1465,6 @@
mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
verifyLightStateConditions(LIGHT_STATE_INACTIVE);
- enterLightState(LIGHT_STATE_PRE_IDLE);
- mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
- verifyLightStateConditions(LIGHT_STATE_PRE_IDLE);
-
enterLightState(LIGHT_STATE_IDLE);
mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
verifyLightStateConditions(LIGHT_STATE_IDLE);
@@ -1381,10 +1498,6 @@
mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
verifyLightStateConditions(LIGHT_STATE_INACTIVE);
- enterLightState(LIGHT_STATE_PRE_IDLE);
- mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
- verifyLightStateConditions(LIGHT_STATE_PRE_IDLE);
-
enterLightState(LIGHT_STATE_IDLE);
mDeviceIdleController.exitMaintenanceEarlyIfNeededLocked();
verifyLightStateConditions(LIGHT_STATE_IDLE);
@@ -1510,10 +1623,6 @@
mDeviceIdleController.handleMotionDetectedLocked(50, "test");
verifyLightStateConditions(LIGHT_STATE_INACTIVE);
- enterLightState(LIGHT_STATE_PRE_IDLE);
- mDeviceIdleController.handleMotionDetectedLocked(50, "test");
- verifyLightStateConditions(LIGHT_STATE_PRE_IDLE);
-
enterLightState(LIGHT_STATE_IDLE);
mDeviceIdleController.handleMotionDetectedLocked(50, "test");
verifyLightStateConditions(LIGHT_STATE_IDLE);
@@ -1580,10 +1689,6 @@
mDeviceIdleController.becomeActiveLocked("test", 1000);
verifyLightStateConditions(LIGHT_STATE_ACTIVE);
- enterLightState(LIGHT_STATE_PRE_IDLE);
- mDeviceIdleController.becomeActiveLocked("test", 1000);
- verifyLightStateConditions(LIGHT_STATE_ACTIVE);
-
enterLightState(LIGHT_STATE_IDLE);
mDeviceIdleController.becomeActiveLocked("test", 1000);
verifyLightStateConditions(LIGHT_STATE_ACTIVE);
@@ -2059,7 +2164,7 @@
while (mDeviceIdleController.getLightState() != lightState) {
// Stepping through each state ensures that the proper features are turned
// on/off.
- mDeviceIdleController.stepLightIdleStateLocked("testing");
+ mDeviceIdleController.stepLightIdleStateLocked("testing", true);
count++;
if (count > 10) {
@@ -2068,7 +2173,6 @@
}
}
break;
- case LIGHT_STATE_PRE_IDLE:
case LIGHT_STATE_WAITING_FOR_NETWORK:
case LIGHT_STATE_OVERRIDE:
setScreenOn(false);
@@ -2213,7 +2317,6 @@
> mAlarmManager.getNextWakeFromIdleTime());
break;
case LIGHT_STATE_INACTIVE:
- case LIGHT_STATE_PRE_IDLE:
case LIGHT_STATE_IDLE:
case LIGHT_STATE_WAITING_FOR_NETWORK:
case LIGHT_STATE_IDLE_MAINTENANCE:
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index 5885470..f05658b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -108,6 +108,7 @@
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
+import android.Manifest;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
@@ -124,6 +125,7 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.PermissionChecker;
import android.content.pm.PackageManagerInternal;
import android.database.ContentObserver;
import android.net.Uri;
@@ -389,6 +391,7 @@
.mockStatic(LocalServices.class)
.spyStatic(Looper.class)
.mockStatic(MetricsHelper.class)
+ .mockStatic(PermissionChecker.class)
.mockStatic(PermissionManagerService.class)
.mockStatic(ServiceManager.class)
.mockStatic(Settings.Global.class)
@@ -445,6 +448,10 @@
doReturn(true)
.when(() -> DateFormat.is24HourFormat(eq(mMockContext), anyInt()));
+ doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(
+ () -> PermissionChecker.checkPermissionForPreflight(any(),
+ eq(Manifest.permission.USE_EXACT_ALARM), anyInt(), anyInt(), anyString()));
+
when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager);
registerAppIds(new String[]{TEST_CALLING_PACKAGE},
@@ -2158,6 +2165,7 @@
@Test
public void canScheduleExactAlarmsBinderCall() throws RemoteException {
+ // Policy permission is denied in setUp().
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
// No permission, no exemption.
@@ -2168,6 +2176,14 @@
mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
assertFalse(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
+ // Policy permission only, no exemption.
+ mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
+ doReturn(PermissionChecker.PERMISSION_GRANTED).when(
+ () -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
+ eq(Manifest.permission.USE_EXACT_ALARM), anyInt(), eq(TEST_CALLING_UID),
+ eq(TEST_CALLING_PACKAGE)));
+ assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
+
// Permission, no exemption.
mockExactAlarmPermissionGrant(true, false, MODE_DEFAULT);
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
@@ -2699,7 +2715,8 @@
mService.handleChangesToExactAlarmDenyList(new ArraySet<>(packages), false);
// No permission revoked.
- verify(mService, never()).removeExactAlarmsOnPermissionRevokedLocked(anyInt(), anyString());
+ verify(mService, never()).removeExactAlarmsOnPermissionRevokedLocked(anyInt(), anyString(),
+ anyBoolean());
// Permission got granted only for (appId1, userId2).
final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
@@ -2754,14 +2771,14 @@
// Permission got revoked only for (appId1, userId2)
verify(mService, never()).removeExactAlarmsOnPermissionRevokedLocked(
- eq(UserHandle.getUid(userId1, appId1)), eq(packages[0]));
+ eq(UserHandle.getUid(userId1, appId1)), eq(packages[0]), eq(true));
verify(mService, never()).removeExactAlarmsOnPermissionRevokedLocked(
- eq(UserHandle.getUid(userId1, appId2)), eq(packages[1]));
+ eq(UserHandle.getUid(userId1, appId2)), eq(packages[1]), eq(true));
verify(mService, never()).removeExactAlarmsOnPermissionRevokedLocked(
- eq(UserHandle.getUid(userId2, appId2)), eq(packages[1]));
+ eq(UserHandle.getUid(userId2, appId2)), eq(packages[1]), eq(true));
verify(mService).removeExactAlarmsOnPermissionRevokedLocked(
- eq(UserHandle.getUid(userId2, appId1)), eq(packages[0]));
+ eq(UserHandle.getUid(userId2, appId1)), eq(packages[0]), eq(true));
}
@Test
@@ -2774,7 +2791,7 @@
mIAppOpsCallback.opChanged(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID, TEST_CALLING_PACKAGE);
assertAndHandleMessageSync(REMOVE_EXACT_ALARMS);
verify(mService).removeExactAlarmsOnPermissionRevokedLocked(TEST_CALLING_UID,
- TEST_CALLING_PACKAGE);
+ TEST_CALLING_PACKAGE, true);
}
@Test
@@ -2859,7 +2876,8 @@
null);
assertEquals(6, mService.mAlarmStore.size());
- mService.removeExactAlarmsOnPermissionRevokedLocked(TEST_CALLING_UID, TEST_CALLING_PACKAGE);
+ mService.removeExactAlarmsOnPermissionRevokedLocked(TEST_CALLING_UID, TEST_CALLING_PACKAGE,
+ true);
final ArrayList<Alarm> remaining = mService.mAlarmStore.asList();
assertEquals(3, remaining.size());
@@ -3080,7 +3098,7 @@
SCHEDULE_EXACT_ALARM)).thenReturn(exactAlarmRequesters);
final Intent packageAdded = new Intent(Intent.ACTION_PACKAGE_ADDED)
- .setPackage(TEST_CALLING_PACKAGE)
+ .setData(Uri.fromParts("package", TEST_CALLING_PACKAGE, null))
.putExtra(Intent.EXTRA_REPLACING, true);
mPackageChangesReceiver.onReceive(mMockContext, packageAdded);
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
index a112baf..936940f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
@@ -17,12 +17,15 @@
package com.android.server.am;
import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
+import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.app.ActivityManager.RESTRICTION_LEVEL_ADAPTIVE_BUCKET;
import static android.app.ActivityManager.RESTRICTION_LEVEL_BACKGROUND_RESTRICTED;
import static android.app.ActivityManager.RESTRICTION_LEVEL_EXEMPTED;
import static android.app.ActivityManager.RESTRICTION_LEVEL_RESTRICTED_BUCKET;
+import static android.app.ActivityManager.isLowRamDeviceStatic;
import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_SYSTEM;
import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_USER;
import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE;
@@ -46,10 +49,17 @@
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static com.android.internal.notification.SystemNotificationChannels.ABUSIVE_BACKGROUND_APPS;
-import static com.android.server.am.AppBatteryTracker.BATT_DIMEN_BG;
-import static com.android.server.am.AppBatteryTracker.BATT_DIMEN_FG;
-import static com.android.server.am.AppBatteryTracker.BATT_DIMEN_FGS;
+import static com.android.server.am.AppBatteryTracker.AppBatteryPolicy.getFloatArray;
+import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATTERY_USAGE_INDEX_BACKGROUND;
+import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATTERY_USAGE_INDEX_FOREGROUND;
+import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATTERY_USAGE_INDEX_FOREGROUND_SERVICE;
+import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATT_DIMENS;
+import static com.android.server.am.AppPermissionTracker.AppPermissionPolicy;
import static com.android.server.am.AppRestrictionController.STOCK_PM_FLAGS;
+import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_FGS_LOCATION;
+import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_FGS_MEDIA_PLAYBACK;
+import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_MEDIA_SESSION;
+import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_PERMISSION;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -100,6 +110,7 @@
import android.os.SystemClock;
import android.os.UidBatteryConsumer;
import android.os.UserHandle;
+import android.permission.PermissionManager;
import android.provider.DeviceConfig;
import android.telephony.TelephonyManager;
import android.util.Log;
@@ -107,12 +118,14 @@
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.R;
import com.android.server.AppStateTracker;
import com.android.server.DeviceIdleInternal;
import com.android.server.am.AppBatteryExemptionTracker.AppBatteryExemptionPolicy;
import com.android.server.am.AppBatteryExemptionTracker.UidBatteryStates;
import com.android.server.am.AppBatteryExemptionTracker.UidStateEventWithBattery;
import com.android.server.am.AppBatteryTracker.AppBatteryPolicy;
+import com.android.server.am.AppBatteryTracker.ImmutableBatteryUsage;
import com.android.server.am.AppBindServiceEventsTracker.AppBindServiceEventsPolicy;
import com.android.server.am.AppBroadcastEventsTracker.AppBroadcastEventsPolicy;
import com.android.server.am.AppFGSTracker.AppFGSPolicy;
@@ -122,6 +135,7 @@
import com.android.server.am.AppRestrictionController.UidBatteryUsageProvider;
import com.android.server.am.BaseAppStateTimeEvents.BaseTimeEvent;
import com.android.server.apphibernation.AppHibernationManagerInternal;
+import com.android.server.notification.NotificationManagerInternal;
import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.usage.AppStandbyInternal;
@@ -146,6 +160,7 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.BiConsumer;
+import java.util.stream.Collectors;
/**
* Tests for {@link AppRestrictionController}.
@@ -210,6 +225,8 @@
@Mock private PackageManager mPackageManager;
@Mock private PackageManagerInternal mPackageManagerInternal;
@Mock private NotificationManager mNotificationManager;
+ @Mock private NotificationManagerInternal mNotificationManagerInternal;
+ @Mock private PermissionManager mPermissionManager;
@Mock private PermissionManagerServiceInternal mPermissionManagerServiceInternal;
@Mock private MediaSessionManager mMediaSessionManager;
@Mock private RoleManager mRoleManager;
@@ -245,6 +262,7 @@
private AppBindServiceEventsTracker mAppBindServiceEventsTracker;
private AppFGSTracker mAppFGSTracker;
private AppMediaSessionTracker mAppMediaSessionTracker;
+ private AppPermissionTracker mAppPermissionTracker;
@Before
public void setUp() throws Exception {
@@ -284,12 +302,16 @@
doReturn(AppOpsManager.MODE_IGNORED)
.when(mAppOpsManager)
.checkOpNoThrow(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, uid, packageName);
- doReturn(PERMISSION_DENIED)
- .when(mPermissionManagerServiceInternal)
- .checkUidPermission(uid, ACCESS_BACKGROUND_LOCATION);
- doReturn(PERMISSION_DENIED)
- .when(mPermissionManagerServiceInternal)
- .checkPermission(packageName, ACCESS_BACKGROUND_LOCATION, userId);
+ final String[] permissions = new String[] {ACCESS_BACKGROUND_LOCATION,
+ ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION};
+ for (String permission : permissions) {
+ doReturn(PERMISSION_DENIED)
+ .when(mPermissionManagerServiceInternal)
+ .checkUidPermission(uid, permission);
+ doReturn(PERMISSION_DENIED)
+ .when(mPermissionManagerServiceInternal)
+ .checkPermission(packageName, permission, userId);
+ }
}
doReturn(appStandbyInfoList).when(mAppStandbyInternal).getAppStandbyBuckets(userId);
}
@@ -531,11 +553,14 @@
final float bgRestrictedThreshold = 4.0f;
final float bgRestrictedThresholdMah =
BATTERY_FULL_CHARGE_MAH * bgRestrictedThreshold / 100.0f;
+ final int testPid = 1234;
+ final int notificationId = 1000;
DeviceConfigSession<Boolean> bgCurrentDrainMonitor = null;
DeviceConfigSession<Long> bgCurrentDrainWindow = null;
DeviceConfigSession<Float> bgCurrentDrainRestrictedBucketThreshold = null;
DeviceConfigSession<Float> bgCurrentDrainBgRestrictedThreshold = null;
+ DeviceConfigSession<Boolean> bgPromptFgsWithNotiToBgRestricted = null;
mBgRestrictionController.addAppBackgroundRestrictionListener(listener);
@@ -552,34 +577,54 @@
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_MONITOR_ENABLED,
DeviceConfig::getBoolean,
- AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_MONITOR_ENABLED);
+ mContext.getResources().getBoolean(
+ R.bool.config_bg_current_drain_monitor_enabled));
bgCurrentDrainMonitor.set(true);
bgCurrentDrainWindow = new DeviceConfigSession<>(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_WINDOW,
DeviceConfig::getLong,
- AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_WINDOW_MS);
+ (long) mContext.getResources().getInteger(
+ R.integer.config_bg_current_drain_window));
bgCurrentDrainWindow.set(windowMs);
bgCurrentDrainRestrictedBucketThreshold = new DeviceConfigSession<>(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET,
DeviceConfig::getFloat,
- AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_BG_RESTRICTED_THRESHOLD);
+ getFloatArray(mContext.getResources().obtainTypedArray(
+ R.array.config_bg_current_drain_threshold_to_restricted_bucket))[
+ isLowRamDeviceStatic() ? 1 : 0]);
bgCurrentDrainRestrictedBucketThreshold.set(restrictBucketThreshold);
bgCurrentDrainBgRestrictedThreshold = new DeviceConfigSession<>(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_BG_RESTRICTED,
DeviceConfig::getFloat,
- AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_BG_RESTRICTED_THRESHOLD);
+ getFloatArray(mContext.getResources().obtainTypedArray(
+ R.array.config_bg_current_drain_threshold_to_bg_restricted))[
+ isLowRamDeviceStatic() ? 1 : 0]);
bgCurrentDrainBgRestrictedThreshold.set(bgRestrictedThreshold);
+ bgPromptFgsWithNotiToBgRestricted = new DeviceConfigSession<>(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ ConstantsObserver.KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_TO_BG_RESTRICTED,
+ DeviceConfig::getBoolean,
+ mContext.getResources().getBoolean(
+ R.bool.config_bg_prompt_fgs_with_noti_to_bg_restricted));
+ bgPromptFgsWithNotiToBgRestricted.set(true);
+
mCurrentTimeMillis = 10_000L;
doReturn(mCurrentTimeMillis - windowMs).when(stats).getStatsStartTimestamp();
doReturn(mCurrentTimeMillis).when(stats).getStatsEndTimestamp();
doReturn(statsList).when(mBatteryStatsInternal).getBatteryUsageStats(anyObject());
+ doReturn(true).when(mNotificationManagerInternal).isNotificationShown(
+ testPkgName, null, notificationId, testUser);
+ mAppFGSTracker.onForegroundServiceStateChanged(testPkgName, testUid,
+ testPid, true);
+ mAppFGSTracker.onForegroundServiceNotificationUpdated(
+ testPkgName, testUid, notificationId);
runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
new double[]{restrictBucketThresholdMah - 1, 0},
@@ -710,6 +755,85 @@
Thread.sleep(windowMs);
clearInvocations(mInjector.getAppStandbyInternal());
clearInvocations(mBgRestrictionController);
+
+ // We're not going to prompt the user if the abusive app has a FGS with notification.
+ bgPromptFgsWithNotiToBgRestricted.set(false);
+
+ runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
+ new double[]{bgRestrictedThresholdMah + 1, 0},
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ () -> {
+ doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
+ doReturn(mCurrentTimeMillis + windowMs)
+ .when(stats).getStatsEndTimestamp();
+ mCurrentTimeMillis += windowMs + 1;
+ // We won't change restriction level automatically because it needs
+ // user consent.
+ try {
+ listener.verify(timeout, testUid, testPkgName,
+ RESTRICTION_LEVEL_BACKGROUND_RESTRICTED);
+ fail("There shouldn't be level change event like this");
+ } catch (Exception e) {
+ // Expected.
+ }
+ verify(mInjector.getAppStandbyInternal(), never()).setAppStandbyBucket(
+ eq(testPkgName),
+ eq(STANDBY_BUCKET_RARE),
+ eq(testUser),
+ anyInt(), anyInt());
+ // We should have requested to goto background restricted level.
+ verify(mBgRestrictionController, times(1)).handleRequestBgRestricted(
+ eq(testPkgName),
+ eq(testUid));
+ // However, we won't have the prompt to user posted because the policy
+ // is not to show that for FGS with notification.
+ checkNotificationShown(new String[] {testPkgName}, never(), false);
+ });
+
+ // Pretend we have the notification dismissed.
+ mAppFGSTracker.onForegroundServiceNotificationUpdated(
+ testPkgName, testUid, -notificationId);
+ clearInvocations(mInjector.getAppStandbyInternal());
+ clearInvocations(mBgRestrictionController);
+
+ runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
+ new double[]{bgRestrictedThresholdMah + 1, 0},
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ () -> {
+ doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
+ doReturn(mCurrentTimeMillis + windowMs)
+ .when(stats).getStatsEndTimestamp();
+ mCurrentTimeMillis += windowMs + 1;
+ // We won't change restriction level automatically because it needs
+ // user consent.
+ try {
+ listener.verify(timeout, testUid, testPkgName,
+ RESTRICTION_LEVEL_BACKGROUND_RESTRICTED);
+ fail("There shouldn't be level change event like this");
+ } catch (Exception e) {
+ // Expected.
+ }
+ verify(mInjector.getAppStandbyInternal(), never()).setAppStandbyBucket(
+ eq(testPkgName),
+ eq(STANDBY_BUCKET_RARE),
+ eq(testUser),
+ anyInt(), anyInt());
+ // We should have requested to goto background restricted level.
+ verify(mBgRestrictionController, times(1)).handleRequestBgRestricted(
+ eq(testPkgName),
+ eq(testUid));
+ // Verify we have the notification posted now because its FGS is invisible.
+ checkNotificationShown(new String[] {testPkgName}, atLeast(1), true);
+ });
+
+ // Pretend notification is back on.
+ mAppFGSTracker.onForegroundServiceNotificationUpdated(
+ testPkgName, testUid, notificationId);
+ // Now we'll prompt the user even it has a FGS with notification.
+ bgPromptFgsWithNotiToBgRestricted.set(true);
+ clearInvocations(mInjector.getAppStandbyInternal());
+ clearInvocations(mBgRestrictionController);
+
runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
new double[]{bgRestrictedThresholdMah + 1, 0},
new double[]{0, restrictBucketThresholdMah - 1}, zeros,
@@ -774,6 +898,7 @@
closeIfNotNull(bgCurrentDrainWindow);
closeIfNotNull(bgCurrentDrainRestrictedBucketThreshold);
closeIfNotNull(bgCurrentDrainBgRestrictedThreshold);
+ closeIfNotNull(bgPromptFgsWithNotiToBgRestricted);
}
}
@@ -1168,7 +1293,8 @@
.checkPermission(packageName, perm, UserHandle.getUserId(uid));
doReturn(PERMISSION_GRANTED)
.when(mPermissionManagerServiceInternal)
- .checkUidPermission(uid, ACCESS_BACKGROUND_LOCATION);
+ .checkUidPermission(uid, perm);
+ mInjector.getAppPermissionTracker().onPermissionsChanged(uid);
}
if (mediaControllers != null) {
@@ -1193,7 +1319,8 @@
.checkPermission(packageName, perm, UserHandle.getUserId(uid));
doReturn(PERMISSION_DENIED)
.when(mPermissionManagerServiceInternal)
- .checkUidPermission(uid, ACCESS_BACKGROUND_LOCATION);
+ .checkUidPermission(uid, perm);
+ mInjector.getAppPermissionTracker().onPermissionsChanged(uid);
}
if (topStateThread != null) {
topStateThread.join();
@@ -1261,6 +1388,10 @@
DeviceConfigSession<Long> bgLocationMinDurationThreshold = null;
DeviceConfigSession<Boolean> bgCurrentDrainEventDurationBasedThresholdEnabled = null;
DeviceConfigSession<Boolean> bgBatteryExemptionEnabled = null;
+ DeviceConfigSession<Integer> bgBatteryExemptionTypes = null;
+ DeviceConfigSession<Boolean> bgPermissionMonitorEnabled = null;
+ DeviceConfigSession<String> bgPermissionsInMonitor = null;
+ DeviceConfigSession<Boolean> bgCurrentDrainHighThresholdByBgLocation = null;
mBgRestrictionController.addAppBackgroundRestrictionListener(listener);
@@ -1280,64 +1411,76 @@
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_MONITOR_ENABLED,
DeviceConfig::getBoolean,
- AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_MONITOR_ENABLED);
+ mContext.getResources().getBoolean(
+ R.bool.config_bg_current_drain_monitor_enabled));
bgCurrentDrainMonitor.set(true);
bgCurrentDrainWindow = new DeviceConfigSession<>(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_WINDOW,
DeviceConfig::getLong,
- AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_WINDOW_MS);
+ (long) mContext.getResources().getInteger(
+ R.integer.config_bg_current_drain_window));
bgCurrentDrainWindow.set(windowMs);
bgCurrentDrainRestrictedBucketThreshold = new DeviceConfigSession<>(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET,
DeviceConfig::getFloat,
- AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_BG_RESTRICTED_THRESHOLD);
+ getFloatArray(mContext.getResources().obtainTypedArray(
+ R.array.config_bg_current_drain_threshold_to_restricted_bucket))[
+ isLowRamDeviceStatic() ? 1 : 0]);
bgCurrentDrainRestrictedBucketThreshold.set(restrictBucketThreshold);
bgCurrentDrainBgRestrictedThreshold = new DeviceConfigSession<>(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_BG_RESTRICTED,
DeviceConfig::getFloat,
- AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_BG_RESTRICTED_THRESHOLD);
+ getFloatArray(mContext.getResources().obtainTypedArray(
+ R.array.config_bg_current_drain_threshold_to_bg_restricted))[
+ isLowRamDeviceStatic() ? 1 : 0]);
bgCurrentDrainBgRestrictedThreshold.set(bgRestrictedThreshold);
bgCurrentDrainRestrictedBucketHighThreshold = new DeviceConfigSession<>(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_RESTRICTED_BUCKET,
DeviceConfig::getFloat,
- AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_RESTRICTED_BUCKET_HIGH_THRESHOLD);
+ getFloatArray(mContext.getResources().obtainTypedArray(
+ R.array.config_bg_current_drain_high_threshold_to_restricted_bucket))[
+ isLowRamDeviceStatic() ? 1 : 0]);
bgCurrentDrainRestrictedBucketHighThreshold.set(restrictBucketHighThreshold);
bgCurrentDrainBgRestrictedHighThreshold = new DeviceConfigSession<>(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_BG_RESTRICTED,
DeviceConfig::getFloat,
- AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_BG_RESTRICTED_HIGH_THRESHOLD);
+ getFloatArray(mContext.getResources().obtainTypedArray(
+ R.array.config_bg_current_drain_high_threshold_to_bg_restricted))[
+ isLowRamDeviceStatic() ? 1 : 0]);
bgCurrentDrainBgRestrictedHighThreshold.set(bgRestrictedHighThreshold);
bgMediaPlaybackMinDurationThreshold = new DeviceConfigSession<>(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_MEDIA_PLAYBACK_MIN_DURATION,
DeviceConfig::getLong,
- AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_MEDIA_PLAYBACK_MIN_DURATION);
+ (long) mContext.getResources().getInteger(
+ R.integer.config_bg_current_drain_media_playback_min_duration));
bgMediaPlaybackMinDurationThreshold.set(bgMediaPlaybackMinDuration);
bgLocationMinDurationThreshold = new DeviceConfigSession<>(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_LOCATION_MIN_DURATION,
DeviceConfig::getLong,
- AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_LOCATION_MIN_DURATION);
+ (long) mContext.getResources().getInteger(
+ R.integer.config_bg_current_drain_location_min_duration));
bgLocationMinDurationThreshold.set(bgLocationMinDuration);
bgCurrentDrainEventDurationBasedThresholdEnabled = new DeviceConfigSession<>(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_EVENT_DURATION_BASED_THRESHOLD_ENABLED,
DeviceConfig::getBoolean,
- AppBatteryPolicy
- .DEFAULT_BG_CURRENT_DRAIN_EVENT_DURATION_BASED_THRESHOLD_ENABLED);
+ mContext.getResources().getBoolean(
+ R.bool.config_bg_current_drain_event_duration_based_threshold_enabled));
bgCurrentDrainEventDurationBasedThresholdEnabled.set(true);
bgBatteryExemptionEnabled = new DeviceConfigSession<>(
@@ -1347,6 +1490,38 @@
AppBatteryExemptionPolicy.DEFAULT_BG_BATTERY_EXEMPTION_ENABLED);
bgBatteryExemptionEnabled.set(false);
+ bgBatteryExemptionTypes = new DeviceConfigSession<>(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES,
+ DeviceConfig::getInt,
+ mContext.getResources().getInteger(
+ R.integer.config_bg_current_drain_exempted_types));
+ bgBatteryExemptionTypes.set(STATE_TYPE_MEDIA_SESSION | STATE_TYPE_FGS_MEDIA_PLAYBACK
+ | STATE_TYPE_FGS_LOCATION | STATE_TYPE_PERMISSION);
+
+ bgPermissionMonitorEnabled = new DeviceConfigSession<>(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ AppPermissionPolicy.KEY_BG_PERMISSION_MONITOR_ENABLED,
+ DeviceConfig::getBoolean,
+ AppPermissionPolicy.DEFAULT_BG_PERMISSION_MONITOR_ENABLED);
+ bgPermissionMonitorEnabled.set(true);
+
+ bgPermissionsInMonitor = new DeviceConfigSession<>(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ AppPermissionPolicy.KEY_BG_PERMISSION_MONITOR_ENABLED,
+ DeviceConfig::getString,
+ Arrays.stream(AppPermissionPolicy.DEFAULT_BG_PERMISSIONS_IN_MONITOR)
+ .collect(Collectors.joining(",")));
+ bgPermissionsInMonitor.set(ACCESS_FINE_LOCATION);
+
+ bgCurrentDrainHighThresholdByBgLocation = new DeviceConfigSession<>(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_BY_BG_LOCATION,
+ DeviceConfig::getBoolean,
+ mContext.getResources().getBoolean(
+ R.bool.config_bg_current_drain_high_threshold_by_bg_location));
+ bgCurrentDrainHighThresholdByBgLocation.set(true);
+
mCurrentTimeMillis = 10_000L;
doReturn(mCurrentTimeMillis - windowMs).when(stats).getStatsStartTimestamp();
doReturn(mCurrentTimeMillis).when(stats).getStatsEndTimestamp();
@@ -1496,15 +1671,44 @@
setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
mAppBatteryPolicy.reset();
- // Run with bg location permission, with higher current drain.
+ // Turn off the higher threshold for bg location access.
+ bgCurrentDrainHighThresholdByBgLocation.set(false);
+
+ // Run with bg location permission, with moderate current drain.
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
FOREGROUND_SERVICE_TYPE_NONE, 0, false,
ACCESS_BACKGROUND_LOCATION, null, null, listener, stats, uids,
- new double[]{restrictBucketHighThresholdMah - 1, 0},
+ new double[]{restrictBucketThresholdMah - 1, 0},
new double[]{0, restrictBucketThresholdMah - 1}, zeros,
true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
null, windowMs, null, null, null);
+ // Run with bg location permission, with a bit higher current drain.
+ runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
+ FOREGROUND_SERVICE_TYPE_NONE, 0, false,
+ ACCESS_BACKGROUND_LOCATION, null, null, listener, stats, uids,
+ new double[]{restrictBucketThresholdMah + 1, 0},
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
+ null, windowMs, null, null, null);
+
+ // Start over.
+ resetBgRestrictionController();
+ setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
+ mAppBatteryPolicy.reset();
+
+ // Turn on the higher threshold for bg location access.
+ bgCurrentDrainHighThresholdByBgLocation.set(true);
+
+ // Run with bg location permission, with higher current drain.
+ runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
+ FOREGROUND_SERVICE_TYPE_NONE, 0, false,
+ ACCESS_BACKGROUND_LOCATION , null, null, listener, stats, uids,
+ new double[]{restrictBucketHighThresholdMah - 1, 0},
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ true , RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
+ null, windowMs, null, null, null);
+
// Run with bg location permission, with even higher current drain.
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
FOREGROUND_SERVICE_TYPE_NONE, 0, false,
@@ -1587,6 +1791,36 @@
true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
null, windowMs, initialBg, initialFgs, initialFg);
+ // Set the policy to exempt media session and permission.
+ bgBatteryExemptionTypes.set(STATE_TYPE_MEDIA_SESSION | STATE_TYPE_PERMISSION);
+ // Start over.
+ resetBgRestrictionController();
+ setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
+ mAppBatteryPolicy.reset();
+
+ // Run with coarse location permission, with high current drain.
+ runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
+ FOREGROUND_SERVICE_TYPE_NONE, 0, false,
+ ACCESS_COARSE_LOCATION, null, null, listener, stats, uids,
+ new double[]{restrictBucketThresholdMah + 1, 0},
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
+ null, windowMs, initialBg, initialFgs, initialFg);
+
+ // Start over.
+ resetBgRestrictionController();
+ setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
+ mAppBatteryPolicy.reset();
+
+ // Run with fine location permission, with high current drain.
+ runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
+ FOREGROUND_SERVICE_TYPE_NONE, 0, false,
+ ACCESS_FINE_LOCATION, null, null, listener, stats, uids,
+ new double[]{restrictBucketThresholdMah + 1, 0},
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
+ null, windowMs, initialBg, initialFgs, initialFg);
+
// Start over.
resetBgRestrictionController();
setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
@@ -1616,6 +1850,10 @@
true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
null, windowMs, initialBg, initialFgs, initialFg);
+ // Set the policy to exempt all.
+ bgBatteryExemptionTypes.set(STATE_TYPE_MEDIA_SESSION | STATE_TYPE_FGS_MEDIA_PLAYBACK
+ | STATE_TYPE_FGS_LOCATION | STATE_TYPE_PERMISSION);
+
// Start over.
resetBgRestrictionController();
setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
@@ -1650,6 +1888,10 @@
closeIfNotNull(bgLocationMinDurationThreshold);
closeIfNotNull(bgCurrentDrainEventDurationBasedThresholdEnabled);
closeIfNotNull(bgBatteryExemptionEnabled);
+ closeIfNotNull(bgBatteryExemptionTypes);
+ closeIfNotNull(bgPermissionMonitorEnabled);
+ closeIfNotNull(bgPermissionsInMonitor);
+ closeIfNotNull(bgCurrentDrainHighThresholdByBgLocation);
}
}
@@ -1670,6 +1912,15 @@
mAppBatteryExemptionTracker.reset();
mAppBatteryPolicy.reset();
}
+ if (perm != null) {
+ doReturn(PERMISSION_GRANTED)
+ .when(mPermissionManagerServiceInternal)
+ .checkPermission(packageName, perm, UserHandle.getUserId(uid));
+ doReturn(PERMISSION_GRANTED)
+ .when(mPermissionManagerServiceInternal)
+ .checkUidPermission(uid, perm);
+ mInjector.getAppPermissionTracker().onPermissionsChanged(uid);
+ }
runExemptionTestOnce(
packageName, uid, pid, serviceType, sleepMs, stopAfterSleep,
perm, mediaControllers, topStateChanges, resetFGSTracker, false,
@@ -1719,6 +1970,15 @@
);
}
);
+ if (perm != null) {
+ doReturn(PERMISSION_DENIED)
+ .when(mPermissionManagerServiceInternal)
+ .checkPermission(packageName, perm, UserHandle.getUserId(uid));
+ doReturn(PERMISSION_DENIED)
+ .when(mPermissionManagerServiceInternal)
+ .checkUidPermission(uid, perm);
+ mInjector.getAppPermissionTracker().onPermissionsChanged(uid);
+ }
}
@Test
@@ -1932,9 +2192,12 @@
private UidBatteryConsumer mockUidBatteryConsumer(int uid, double bg, double fgs, double fg) {
UidBatteryConsumer uidConsumer = mock(UidBatteryConsumer.class);
doReturn(uid).when(uidConsumer).getUid();
- doReturn(bg).when(uidConsumer).getConsumedPower(eq(BATT_DIMEN_BG));
- doReturn(fgs).when(uidConsumer).getConsumedPower(eq(BATT_DIMEN_FGS));
- doReturn(fg).when(uidConsumer).getConsumedPower(eq(BATT_DIMEN_FG));
+ doReturn(bg).when(uidConsumer).getConsumedPower(
+ eq(BATT_DIMENS[BATTERY_USAGE_INDEX_BACKGROUND]));
+ doReturn(fgs).when(uidConsumer).getConsumedPower(
+ eq(BATT_DIMENS[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE]));
+ doReturn(fg).when(uidConsumer).getConsumedPower(
+ eq(BATT_DIMENS[BATTERY_USAGE_INDEX_FOREGROUND]));
return uidConsumer;
}
@@ -2234,8 +2497,8 @@
boolean[] isStart, long[] timestamps, double[] batteryUsage) {
final LinkedList<UidStateEventWithBattery> result = new LinkedList<>();
for (int i = 0; i < isStart.length; i++) {
- result.add(new UidStateEventWithBattery(
- isStart[i], timestamps[i], batteryUsage[i], null));
+ result.add(new UidStateEventWithBattery(isStart[i], timestamps[i],
+ new ImmutableBatteryUsage(0.0d, 0.0d, batteryUsage[i], 0.0d), null));
}
return result;
}
@@ -2281,6 +2544,11 @@
BackgroundRestrictionTest.class),
BackgroundRestrictionTest.this);
controller.addAppStateTracker(mAppBindServiceEventsTracker);
+ mAppPermissionTracker = new AppPermissionTracker(mContext, controller,
+ TestAppPermissionTrackerInjector.class.getDeclaredConstructor(
+ BackgroundRestrictionTest.class),
+ BackgroundRestrictionTest.this);
+ controller.addAppStateTracker(mAppPermissionTracker);
} catch (NoSuchMethodException e) {
// Won't happen.
}
@@ -2375,6 +2643,11 @@
AppBatteryExemptionTracker getAppBatteryExemptionTracker() {
return mAppBatteryExemptionTracker;
}
+
+ @Override
+ AppPermissionTracker getAppPermissionTracker() {
+ return mAppPermissionTracker;
+ }
}
private class TestBaseTrackerInjector<T extends BaseAppStatePolicy>
@@ -2435,6 +2708,19 @@
}
@Override
+ NotificationManagerInternal getNotificationManagerInternal() {
+ return BackgroundRestrictionTest.this.mNotificationManagerInternal;
+ }
+
+ PackageManagerInternal getPackageManagerInternal() {
+ return BackgroundRestrictionTest.this.mPackageManagerInternal;
+ }
+
+ PermissionManager getPermissionManager() {
+ return BackgroundRestrictionTest.this.mPermissionManager;
+ }
+
+ @Override
long getServiceStartForegroundTimeout() {
return 1_000; // ms
}
@@ -2464,6 +2750,10 @@
extends TestBaseTrackerInjector<AppMediaSessionPolicy> {
}
+ private class TestAppPermissionTrackerInjector
+ extends TestBaseTrackerInjector<AppPermissionPolicy> {
+ }
+
private class TestAppBroadcastEventsTrackerInjector
extends TestBaseTrackerInjector<AppBroadcastEventsPolicy> {
@Override
diff --git a/services/tests/mockingservicestests/src/com/android/server/companion/virtual/CameraAccessControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/companion/virtual/CameraAccessControllerTest.java
new file mode 100644
index 0000000..1b9cb28
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/companion/virtual/CameraAccessControllerTest.java
@@ -0,0 +1,200 @@
+/*
+ * 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.companion.virtual;
+
+import static android.hardware.camera2.CameraInjectionSession.InjectionStatusCallback.ERROR_INJECTION_UNSUPPORTED;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraInjectionSession;
+import android.hardware.camera2.CameraManager;
+import android.os.Process;
+import android.testing.TestableContext;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.server.LocalServices;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class CameraAccessControllerTest {
+ private static final String FRONT_CAMERA = "0";
+ private static final String REAR_CAMERA = "1";
+ private static final String TEST_APP_PACKAGE = "some.package";
+ private static final String OTHER_APP_PACKAGE = "other.package";
+
+ private CameraAccessController mController;
+
+ @Rule
+ public final TestableContext mContext = new TestableContext(
+ InstrumentationRegistry.getContext());
+
+ @Mock
+ private CameraManager mCameraManager;
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private VirtualDeviceManagerInternal mDeviceManagerInternal;
+ @Mock
+ private CameraAccessController.CameraAccessBlockedCallback mBlockedCallback;
+
+ private ApplicationInfo mTestAppInfo = new ApplicationInfo();
+ private ApplicationInfo mOtherAppInfo = new ApplicationInfo();
+
+ @Captor
+ ArgumentCaptor<CameraInjectionSession.InjectionStatusCallback> mInjectionCallbackCaptor;
+
+
+ @Before
+ public void setUp() throws PackageManager.NameNotFoundException {
+ MockitoAnnotations.initMocks(this);
+ mContext.addMockSystemService(CameraManager.class, mCameraManager);
+ mContext.setMockPackageManager(mPackageManager);
+ LocalServices.removeServiceForTest(VirtualDeviceManagerInternal.class);
+ LocalServices.addService(VirtualDeviceManagerInternal.class, mDeviceManagerInternal);
+ mController = new CameraAccessController(mContext, mDeviceManagerInternal,
+ mBlockedCallback);
+ mTestAppInfo.uid = Process.FIRST_APPLICATION_UID;
+ mOtherAppInfo.uid = Process.FIRST_APPLICATION_UID + 1;
+ when(mPackageManager.getApplicationInfo(eq(TEST_APP_PACKAGE), anyInt())).thenReturn(
+ mTestAppInfo);
+ when(mPackageManager.getApplicationInfo(eq(OTHER_APP_PACKAGE), anyInt())).thenReturn(
+ mOtherAppInfo);
+ mController.startObservingIfNeeded();
+ }
+
+ @Test
+ public void onCameraOpened_uidNotRunning_noCameraBlocking() throws CameraAccessException {
+ when(mDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(
+ eq(mTestAppInfo.uid))).thenReturn(false);
+ mController.onCameraOpened(FRONT_CAMERA, TEST_APP_PACKAGE);
+ verify(mCameraManager, never()).injectCamera(any(), any(), any(), any(), any());
+ }
+
+
+ @Test
+ public void onCameraOpened_uidRunning_cameraBlocked() throws CameraAccessException {
+ when(mDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(
+ eq(mTestAppInfo.uid))).thenReturn(true);
+ mController.onCameraOpened(FRONT_CAMERA, TEST_APP_PACKAGE);
+ verify(mCameraManager).injectCamera(eq(TEST_APP_PACKAGE), eq(FRONT_CAMERA), anyString(),
+ any(), any());
+ }
+
+ @Test
+ public void onCameraClosed_injectionWasActive_cameraUnblocked() throws CameraAccessException {
+ when(mDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(
+ eq(mTestAppInfo.uid))).thenReturn(true);
+ mController.onCameraOpened(FRONT_CAMERA, TEST_APP_PACKAGE);
+ verify(mCameraManager).injectCamera(eq(TEST_APP_PACKAGE), eq(FRONT_CAMERA), anyString(),
+ any(), mInjectionCallbackCaptor.capture());
+ CameraInjectionSession session = mock(CameraInjectionSession.class);
+ mInjectionCallbackCaptor.getValue().onInjectionSucceeded(session);
+
+ mController.onCameraClosed(FRONT_CAMERA);
+ verify(session).close();
+ }
+
+
+ @Test
+ public void onCameraClosed_otherCameraClosed_cameraNotUnblocked() throws CameraAccessException {
+ when(mDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(
+ eq(mTestAppInfo.uid))).thenReturn(true);
+ mController.onCameraOpened(FRONT_CAMERA, TEST_APP_PACKAGE);
+ verify(mCameraManager).injectCamera(eq(TEST_APP_PACKAGE), eq(FRONT_CAMERA), anyString(),
+ any(), mInjectionCallbackCaptor.capture());
+ CameraInjectionSession session = mock(CameraInjectionSession.class);
+ mInjectionCallbackCaptor.getValue().onInjectionSucceeded(session);
+
+ mController.onCameraClosed(REAR_CAMERA);
+ verify(session, never()).close();
+ }
+
+ @Test
+ public void onCameraClosed_twoCamerasBlocked_correctCameraUnblocked()
+ throws CameraAccessException {
+ when(mDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(
+ eq(mTestAppInfo.uid))).thenReturn(true);
+ when(mDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(
+ eq(mOtherAppInfo.uid))).thenReturn(true);
+
+ mController.onCameraOpened(FRONT_CAMERA, TEST_APP_PACKAGE);
+ mController.onCameraOpened(REAR_CAMERA, OTHER_APP_PACKAGE);
+
+ verify(mCameraManager).injectCamera(eq(TEST_APP_PACKAGE), eq(FRONT_CAMERA), anyString(),
+ any(), mInjectionCallbackCaptor.capture());
+ CameraInjectionSession frontCameraSession = mock(CameraInjectionSession.class);
+ mInjectionCallbackCaptor.getValue().onInjectionSucceeded(frontCameraSession);
+
+ verify(mCameraManager).injectCamera(eq(OTHER_APP_PACKAGE), eq(REAR_CAMERA), anyString(),
+ any(), mInjectionCallbackCaptor.capture());
+ CameraInjectionSession rearCameraSession = mock(CameraInjectionSession.class);
+ mInjectionCallbackCaptor.getValue().onInjectionSucceeded(rearCameraSession);
+
+ mController.onCameraClosed(REAR_CAMERA);
+ verify(frontCameraSession, never()).close();
+ verify(rearCameraSession).close();
+ }
+
+ @Test
+ public void onInjectionError_callbackFires() throws CameraAccessException {
+ when(mDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(
+ eq(mTestAppInfo.uid))).thenReturn(true);
+ mController.onCameraOpened(FRONT_CAMERA, TEST_APP_PACKAGE);
+ verify(mCameraManager).injectCamera(eq(TEST_APP_PACKAGE), eq(FRONT_CAMERA), anyString(),
+ any(), mInjectionCallbackCaptor.capture());
+ CameraInjectionSession session = mock(CameraInjectionSession.class);
+ mInjectionCallbackCaptor.getValue().onInjectionSucceeded(session);
+ mInjectionCallbackCaptor.getValue().onInjectionError(ERROR_INJECTION_UNSUPPORTED);
+ verify(mBlockedCallback).onCameraAccessBlocked(eq(mTestAppInfo.uid));
+ }
+
+ @Test
+ public void twoCameraAccesses_onlyOneOnVirtualDisplay_callbackFiresForCorrectUid()
+ throws CameraAccessException {
+ when(mDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(
+ eq(mTestAppInfo.uid))).thenReturn(true);
+ mController.onCameraOpened(FRONT_CAMERA, TEST_APP_PACKAGE);
+ mController.onCameraOpened(REAR_CAMERA, OTHER_APP_PACKAGE);
+
+ verify(mCameraManager).injectCamera(eq(TEST_APP_PACKAGE), eq(FRONT_CAMERA), anyString(),
+ any(), mInjectionCallbackCaptor.capture());
+ CameraInjectionSession session = mock(CameraInjectionSession.class);
+ mInjectionCallbackCaptor.getValue().onInjectionSucceeded(session);
+ mInjectionCallbackCaptor.getValue().onInjectionError(ERROR_INJECTION_UNSUPPORTED);
+ verify(mBlockedCallback).onCameraAccessBlocked(eq(mTestAppInfo.uid));
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
index f61d6ca..e4c9f97 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
@@ -23,6 +23,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -59,6 +60,10 @@
import android.os.Build;
import android.os.Looper;
import android.os.SystemClock;
+import android.telephony.CellSignalStrength;
+import android.telephony.SignalStrength;
+import android.telephony.TelephonyCallback;
+import android.telephony.TelephonyManager;
import android.util.DataUnit;
import com.android.server.LocalServices;
@@ -76,6 +81,7 @@
import java.time.Clock;
import java.time.ZoneOffset;
+import java.util.Set;
@RunWith(MockitoJUnitRunner.class)
public class ConnectivityControllerTest {
@@ -302,6 +308,427 @@
}
@Test
+ public void testStrongEnough_Cellular() {
+ mConstants.CONN_UPDATE_ALL_JOBS_MIN_INTERVAL_MS = 0;
+
+ final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+ final TelephonyManager telephonyManager = mock(TelephonyManager.class);
+ when(mContext.getSystemService(TelephonyManager.class))
+ .thenReturn(telephonyManager);
+ when(telephonyManager.createForSubscriptionId(anyInt()))
+ .thenReturn(telephonyManager);
+ final ArgumentCaptor<TelephonyCallback> signalStrengthsCaptor =
+ ArgumentCaptor.forClass(TelephonyCallback.class);
+ doNothing().when(telephonyManager)
+ .registerTelephonyCallback(any(), signalStrengthsCaptor.capture());
+ final ArgumentCaptor<NetworkCallback> callbackCaptor =
+ ArgumentCaptor.forClass(NetworkCallback.class);
+ doNothing().when(mConnManager).registerNetworkCallback(any(), callbackCaptor.capture());
+ final Network net = mock(Network.class);
+ final NetworkCapabilities caps = createCapabilitiesBuilder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_NOT_CONGESTED)
+ .setSubscriptionIds(Set.of(7357))
+ .build();
+ final JobInfo.Builder baseJobBuilder = createJob()
+ .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1),
+ DataUnit.MEBIBYTES.toBytes(1))
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
+ final JobStatus jobExp = createJobStatus(baseJobBuilder.setExpedited(true));
+ final JobStatus jobHigh = createJobStatus(
+ baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_HIGH));
+ final JobStatus jobDefEarly = createJobStatus(
+ baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_DEFAULT),
+ now - 1000, now + 100_000);
+ final JobStatus jobDefLate = createJobStatus(
+ baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_DEFAULT),
+ now - 100_000, now + 1000);
+ final JobStatus jobLow = createJobStatus(
+ baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_LOW));
+ final JobStatus jobMin = createJobStatus(
+ baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_MIN));
+ final JobStatus jobMinRunner = createJobStatus(
+ baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_MIN));
+
+ final ConnectivityController controller = new ConnectivityController(mService);
+
+ final NetworkCallback generalCallback = callbackCaptor.getValue();
+
+ when(mService.getMaxJobExecutionTimeMs(any())).thenReturn(10 * 60_000L);
+
+ when(mService.isBatteryCharging()).thenReturn(false);
+ when(mService.isBatteryNotLow()).thenReturn(false);
+ answerNetwork(generalCallback, null, null, net, caps);
+
+ final TelephonyCallback.SignalStrengthsListener signalStrengthsListener =
+ (TelephonyCallback.SignalStrengthsListener) signalStrengthsCaptor.getValue();
+
+ controller.maybeStartTrackingJobLocked(jobMinRunner, null);
+ controller.prepareForExecutionLocked(jobMinRunner);
+
+ final SignalStrength signalStrength = mock(SignalStrength.class);
+
+ when(signalStrength.getLevel()).thenReturn(
+ CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
+ signalStrengthsListener.onSignalStrengthsChanged(signalStrength);
+
+ assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
+ assertFalse(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
+ assertFalse(controller.isSatisfied(jobLow, net, caps, mConstants));
+ assertFalse(controller.isSatisfied(jobMin, net, caps, mConstants));
+ assertFalse(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
+
+ when(signalStrength.getLevel()).thenReturn(
+ CellSignalStrength.SIGNAL_STRENGTH_POOR);
+ signalStrengthsListener.onSignalStrengthsChanged(signalStrength);
+
+ assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
+ assertFalse(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
+ assertFalse(controller.isSatisfied(jobLow, net, caps, mConstants));
+ assertFalse(controller.isSatisfied(jobMin, net, caps, mConstants));
+ assertFalse(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
+
+ when(mService.isBatteryCharging()).thenReturn(true);
+ when(mService.isBatteryNotLow()).thenReturn(false);
+
+ assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
+ assertFalse(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
+ assertFalse(controller.isSatisfied(jobLow, net, caps, mConstants));
+ assertFalse(controller.isSatisfied(jobMin, net, caps, mConstants));
+ assertFalse(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
+
+ when(mService.isBatteryCharging()).thenReturn(true);
+ when(mService.isBatteryNotLow()).thenReturn(true);
+
+ assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
+ assertFalse(controller.isSatisfied(jobLow, net, caps, mConstants));
+ assertFalse(controller.isSatisfied(jobMin, net, caps, mConstants));
+ assertFalse(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
+
+ when(mService.isBatteryCharging()).thenReturn(false);
+ when(mService.isBatteryNotLow()).thenReturn(false);
+ when(signalStrength.getLevel()).thenReturn(
+ CellSignalStrength.SIGNAL_STRENGTH_MODERATE);
+ signalStrengthsListener.onSignalStrengthsChanged(signalStrength);
+
+ assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
+ assertFalse(controller.isSatisfied(jobMin, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
+
+ when(mService.isBatteryCharging()).thenReturn(false);
+ when(mService.isBatteryNotLow()).thenReturn(true);
+
+ assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
+ assertFalse(controller.isSatisfied(jobMin, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
+
+ when(mService.isBatteryCharging()).thenReturn(true);
+ when(mService.isBatteryNotLow()).thenReturn(true);
+
+ assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobMin, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
+
+ when(mService.isBatteryCharging()).thenReturn(false);
+ when(mService.isBatteryNotLow()).thenReturn(false);
+ when(signalStrength.getLevel()).thenReturn(
+ CellSignalStrength.SIGNAL_STRENGTH_GOOD);
+ signalStrengthsListener.onSignalStrengthsChanged(signalStrength);
+
+ assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobMin, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
+
+ when(mService.isBatteryCharging()).thenReturn(false);
+ when(mService.isBatteryNotLow()).thenReturn(false);
+ when(signalStrength.getLevel()).thenReturn(
+ CellSignalStrength.SIGNAL_STRENGTH_GREAT);
+ signalStrengthsListener.onSignalStrengthsChanged(signalStrength);
+
+ assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobMin, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
+ }
+
+ @Test
+ public void testStrongEnough_Cellular_CheckDisabled() {
+ mConstants.CONN_USE_CELL_SIGNAL_STRENGTH = false;
+ mConstants.CONN_UPDATE_ALL_JOBS_MIN_INTERVAL_MS = 0;
+
+ final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+ final TelephonyManager telephonyManager = mock(TelephonyManager.class);
+ when(mContext.getSystemService(TelephonyManager.class))
+ .thenReturn(telephonyManager);
+ when(telephonyManager.createForSubscriptionId(anyInt()))
+ .thenReturn(telephonyManager);
+ final ArgumentCaptor<TelephonyCallback> signalStrengthsCaptor =
+ ArgumentCaptor.forClass(TelephonyCallback.class);
+ doNothing().when(telephonyManager)
+ .registerTelephonyCallback(any(), signalStrengthsCaptor.capture());
+ final ArgumentCaptor<NetworkCallback> callbackCaptor =
+ ArgumentCaptor.forClass(NetworkCallback.class);
+ doNothing().when(mConnManager).registerNetworkCallback(any(), callbackCaptor.capture());
+ final Network net = mock(Network.class);
+ final NetworkCapabilities caps = createCapabilitiesBuilder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_NOT_CONGESTED)
+ .setSubscriptionIds(Set.of(7357))
+ .build();
+ final JobInfo.Builder baseJobBuilder = createJob()
+ .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1),
+ DataUnit.MEBIBYTES.toBytes(1))
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
+ final JobStatus jobExp = createJobStatus(baseJobBuilder.setExpedited(true));
+ final JobStatus jobHigh = createJobStatus(
+ baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_HIGH));
+ final JobStatus jobDefEarly = createJobStatus(
+ baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_DEFAULT),
+ now - 1000, now + 100_000);
+ final JobStatus jobDefLate = createJobStatus(
+ baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_DEFAULT),
+ now - 100_000, now + 1000);
+ final JobStatus jobLow = createJobStatus(
+ baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_LOW));
+ final JobStatus jobMin = createJobStatus(
+ baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_MIN));
+ final JobStatus jobMinRunner = createJobStatus(
+ baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_MIN));
+
+ final ConnectivityController controller = new ConnectivityController(mService);
+
+ final NetworkCallback generalCallback = callbackCaptor.getValue();
+
+ when(mService.getMaxJobExecutionTimeMs(any())).thenReturn(10 * 60_000L);
+
+ when(mService.isBatteryCharging()).thenReturn(false);
+ when(mService.isBatteryNotLow()).thenReturn(false);
+ answerNetwork(generalCallback, null, null, net, caps);
+
+ final TelephonyCallback.SignalStrengthsListener signalStrengthsListener =
+ (TelephonyCallback.SignalStrengthsListener) signalStrengthsCaptor.getValue();
+
+ controller.maybeStartTrackingJobLocked(jobMinRunner, null);
+ controller.prepareForExecutionLocked(jobMinRunner);
+
+ final SignalStrength signalStrength = mock(SignalStrength.class);
+
+ when(signalStrength.getLevel()).thenReturn(
+ CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
+ signalStrengthsListener.onSignalStrengthsChanged(signalStrength);
+
+ assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobMin, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
+
+ when(signalStrength.getLevel()).thenReturn(
+ CellSignalStrength.SIGNAL_STRENGTH_POOR);
+ signalStrengthsListener.onSignalStrengthsChanged(signalStrength);
+
+ assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobMin, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
+
+ when(mService.isBatteryCharging()).thenReturn(true);
+ when(mService.isBatteryNotLow()).thenReturn(false);
+
+ assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobMin, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
+
+ when(mService.isBatteryCharging()).thenReturn(true);
+ when(mService.isBatteryNotLow()).thenReturn(true);
+
+ assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobMin, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
+
+ when(mService.isBatteryCharging()).thenReturn(false);
+ when(mService.isBatteryNotLow()).thenReturn(false);
+ when(signalStrength.getLevel()).thenReturn(
+ CellSignalStrength.SIGNAL_STRENGTH_MODERATE);
+ signalStrengthsListener.onSignalStrengthsChanged(signalStrength);
+
+ assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobMin, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
+
+ when(mService.isBatteryCharging()).thenReturn(false);
+ when(mService.isBatteryNotLow()).thenReturn(true);
+
+ assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobMin, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
+
+ when(mService.isBatteryCharging()).thenReturn(true);
+ when(mService.isBatteryNotLow()).thenReturn(true);
+
+ assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobMin, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
+
+ when(mService.isBatteryCharging()).thenReturn(false);
+ when(mService.isBatteryNotLow()).thenReturn(false);
+ when(signalStrength.getLevel()).thenReturn(
+ CellSignalStrength.SIGNAL_STRENGTH_GOOD);
+ signalStrengthsListener.onSignalStrengthsChanged(signalStrength);
+
+ assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobMin, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
+
+ when(mService.isBatteryCharging()).thenReturn(false);
+ when(mService.isBatteryNotLow()).thenReturn(false);
+ when(signalStrength.getLevel()).thenReturn(
+ CellSignalStrength.SIGNAL_STRENGTH_GREAT);
+ signalStrengthsListener.onSignalStrengthsChanged(signalStrength);
+
+ assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobMin, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
+ }
+
+ @Test
+ public void testStrongEnough_Cellular_VPN() {
+ mConstants.CONN_UPDATE_ALL_JOBS_MIN_INTERVAL_MS = 0;
+
+ final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+ final TelephonyManager telephonyManager = mock(TelephonyManager.class);
+ when(mContext.getSystemService(TelephonyManager.class))
+ .thenReturn(telephonyManager);
+ when(telephonyManager.createForSubscriptionId(anyInt()))
+ .thenReturn(telephonyManager);
+ final ArgumentCaptor<TelephonyCallback> signalStrengthsCaptor =
+ ArgumentCaptor.forClass(TelephonyCallback.class);
+ doNothing().when(telephonyManager)
+ .registerTelephonyCallback(any(), signalStrengthsCaptor.capture());
+ final ArgumentCaptor<NetworkCallback> callbackCaptor =
+ ArgumentCaptor.forClass(NetworkCallback.class);
+ doNothing().when(mConnManager).registerNetworkCallback(any(), callbackCaptor.capture());
+ final Network net = mock(Network.class);
+ final NetworkCapabilities caps = createCapabilitiesBuilder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addTransportType(TRANSPORT_VPN)
+ .addCapability(NET_CAPABILITY_NOT_CONGESTED)
+ .setSubscriptionIds(Set.of(7357))
+ .build();
+ final JobInfo.Builder baseJobBuilder = createJob()
+ .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1),
+ DataUnit.MEBIBYTES.toBytes(1))
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
+ final JobStatus jobExp = createJobStatus(baseJobBuilder.setExpedited(true));
+ final JobStatus jobHigh = createJobStatus(
+ baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_HIGH));
+ final JobStatus jobDefEarly = createJobStatus(
+ baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_DEFAULT),
+ now - 1000, now + 100_000);
+ final JobStatus jobDefLate = createJobStatus(
+ baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_DEFAULT),
+ now - 100_000, now + 1000);
+ final JobStatus jobLow = createJobStatus(
+ baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_LOW));
+ final JobStatus jobMin = createJobStatus(
+ baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_MIN));
+ final JobStatus jobMinRunner = createJobStatus(
+ baseJobBuilder.setExpedited(false).setPriority(JobInfo.PRIORITY_MIN));
+
+ final ConnectivityController controller = new ConnectivityController(mService);
+
+ final NetworkCallback generalCallback = callbackCaptor.getValue();
+
+ when(mService.getMaxJobExecutionTimeMs(any())).thenReturn(10 * 60_000L);
+
+ when(mService.isBatteryCharging()).thenReturn(false);
+ when(mService.isBatteryNotLow()).thenReturn(false);
+ answerNetwork(generalCallback, null, null, net, caps);
+
+ final TelephonyCallback.SignalStrengthsListener signalStrengthsListener =
+ (TelephonyCallback.SignalStrengthsListener) signalStrengthsCaptor.getValue();
+
+ controller.maybeStartTrackingJobLocked(jobMinRunner, null);
+ controller.prepareForExecutionLocked(jobMinRunner);
+
+ final SignalStrength signalStrength = mock(SignalStrength.class);
+
+ when(signalStrength.getLevel()).thenReturn(
+ CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
+ signalStrengthsListener.onSignalStrengthsChanged(signalStrength);
+
+ // We don't restrict data via VPN over cellular.
+ assertTrue(controller.isSatisfied(jobExp, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobHigh, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefEarly, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobDefLate, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobLow, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobMin, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(jobMinRunner, net, caps, mConstants));
+ }
+
+ @Test
public void testRelaxed() throws Exception {
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
final JobInfo.Builder job = createJob()
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
index 7d42a52..0319d8d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
@@ -43,6 +43,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.when;
import android.app.job.JobInfo;
@@ -137,7 +138,7 @@
.setOverrideDeadline(12)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.build();
- when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE);
+ when(mJobSchedulerInternal.getCloudMediaProviderPackage(eq(0))).thenReturn(TEST_PACKAGE);
assertEffectiveBucketForMediaExemption(createJobStatus(triggerContentJob), false);
}
@@ -146,7 +147,7 @@
final JobInfo triggerContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT)
.addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0))
.build();
- when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE);
+ when(mJobSchedulerInternal.getCloudMediaProviderPackage(eq(0))).thenReturn(TEST_PACKAGE);
assertEffectiveBucketForMediaExemption(createJobStatus(triggerContentJob), false);
}
@@ -155,7 +156,7 @@
final JobInfo networkJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.build();
- when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE);
+ when(mJobSchedulerInternal.getCloudMediaProviderPackage(eq(0))).thenReturn(TEST_PACKAGE);
assertEffectiveBucketForMediaExemption(createJobStatus(networkJob), false);
}
@@ -165,7 +166,8 @@
.addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0))
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.build();
- when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn("not.test.package");
+ when(mJobSchedulerInternal.getCloudMediaProviderPackage(eq(0)))
+ .thenReturn("not.test.package");
assertEffectiveBucketForMediaExemption(createJobStatus(networkContentJob), false);
}
@@ -178,13 +180,25 @@
.addTriggerContentUri(new JobInfo.TriggerContentUri(nonEligibleUri, 0))
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.build();
- when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE);
+ when(mJobSchedulerInternal.getCloudMediaProviderPackage(eq(0))).thenReturn(TEST_PACKAGE);
assertEffectiveBucketForMediaExemption(createJobStatus(networkContentJob), false);
}
@Test
+ public void testMediaBackupExemption_lowPriorityJobs() {
+ when(mJobSchedulerInternal.getCloudMediaProviderPackage(eq(0))).thenReturn(TEST_PACKAGE);
+ final JobInfo.Builder jobBuilder = new JobInfo.Builder(42, TEST_JOB_COMPONENT)
+ .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0))
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
+ assertEffectiveBucketForMediaExemption(
+ createJobStatus(jobBuilder.setPriority(JobInfo.PRIORITY_LOW).build()), false);
+ assertEffectiveBucketForMediaExemption(
+ createJobStatus(jobBuilder.setPriority(JobInfo.PRIORITY_MIN).build()), false);
+ }
+
+ @Test
public void testMediaBackupExemptionGranted() {
- when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE);
+ when(mJobSchedulerInternal.getCloudMediaProviderPackage(eq(0))).thenReturn(TEST_PACKAGE);
final JobInfo imageUriJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT)
.addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0))
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index 40bd800..a0ac506 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -1794,6 +1794,98 @@
}
}
+ /**
+ * Test getTimeUntilQuotaConsumedLocked when allowed time equals the bucket window size.
+ */
+ @Test
+ public void testGetTimeUntilQuotaConsumedLocked_EdgeOfWindow_AllowedEqualsWindow() {
+ final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(now - (24 * HOUR_IN_MILLIS),
+ mQcConstants.MAX_EXECUTION_TIME_MS - 10 * MINUTE_IN_MILLIS, 5),
+ false);
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(now - (10 * MINUTE_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5),
+ false);
+
+ setDeviceConfigLong(QcConstants.KEY_ALLOWED_TIME_PER_PERIOD_EXEMPTED_MS,
+ 10 * MINUTE_IN_MILLIS);
+ setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_EXEMPTED_MS, 10 * MINUTE_IN_MILLIS);
+ // window size = allowed time, so jobs can essentially run non-stop until they reach the
+ // max execution time.
+ setStandbyBucket(EXEMPTED_INDEX);
+ synchronized (mQuotaController.mLock) {
+ assertEquals(0,
+ mQuotaController.getRemainingExecutionTimeLocked(
+ SOURCE_USER_ID, SOURCE_PACKAGE));
+ assertEquals(mQcConstants.MAX_EXECUTION_TIME_MS - 10 * MINUTE_IN_MILLIS,
+ mQuotaController.getTimeUntilQuotaConsumedLocked(
+ SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT));
+ }
+ }
+
+ /**
+ * Test getTimeUntilQuotaConsumedLocked when the determination is based within the bucket
+ * window and the session is rolling out of the window.
+ */
+ @Test
+ public void testGetTimeUntilQuotaConsumedLocked_EdgeOfWindow_BucketWindow() {
+ final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(now - (24 * HOUR_IN_MILLIS),
+ 10 * MINUTE_IN_MILLIS, 5), false);
+ setStandbyBucket(RARE_INDEX);
+ synchronized (mQuotaController.mLock) {
+ assertEquals(0,
+ mQuotaController.getRemainingExecutionTimeLocked(
+ SOURCE_USER_ID, SOURCE_PACKAGE));
+ assertEquals(10 * MINUTE_IN_MILLIS,
+ mQuotaController.getTimeUntilQuotaConsumedLocked(
+ SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT));
+ }
+
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(now - (8 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5), false);
+ setStandbyBucket(FREQUENT_INDEX);
+ synchronized (mQuotaController.mLock) {
+ assertEquals(0,
+ mQuotaController.getRemainingExecutionTimeLocked(
+ SOURCE_USER_ID, SOURCE_PACKAGE));
+ assertEquals(10 * MINUTE_IN_MILLIS,
+ mQuotaController.getTimeUntilQuotaConsumedLocked(
+ SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT));
+ }
+
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(now - (2 * HOUR_IN_MILLIS),
+ 10 * MINUTE_IN_MILLIS, 5), false);
+ setStandbyBucket(WORKING_INDEX);
+ synchronized (mQuotaController.mLock) {
+ assertEquals(0,
+ mQuotaController.getRemainingExecutionTimeLocked(
+ SOURCE_USER_ID, SOURCE_PACKAGE));
+ assertEquals(10 * MINUTE_IN_MILLIS,
+ mQuotaController.getTimeUntilQuotaConsumedLocked(
+ SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT));
+ }
+
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(now - (10 * MINUTE_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5),
+ false);
+ // ACTIVE window = allowed time, so jobs can essentially run non-stop until they reach the
+ // max execution time.
+ setStandbyBucket(ACTIVE_INDEX);
+ synchronized (mQuotaController.mLock) {
+ assertEquals(0,
+ mQuotaController.getRemainingExecutionTimeLocked(
+ SOURCE_USER_ID, SOURCE_PACKAGE));
+ assertEquals(mQcConstants.MAX_EXECUTION_TIME_MS - 30 * MINUTE_IN_MILLIS,
+ mQuotaController.getTimeUntilQuotaConsumedLocked(
+ SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT));
+ }
+ }
+
@Test
public void testIsWithinQuotaLocked_NeverApp() {
synchronized (mQuotaController.mLock) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
index b89f36f..f35986b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
@@ -230,7 +230,7 @@
val pair = createBasicAndroidPackage(STATIC_LIB_PACKAGE_NAME + "_" + 10, 10L,
staticLibrary = STATIC_LIB_NAME, staticLibraryVersion = 10L)
val parsedPackage = pair.second as ParsedPackage
- val scanRequest = ScanRequest(parsedPackage, null, null, null,
+ val scanRequest = ScanRequest(parsedPackage, null, null, null, null,
null, null, null, 0, 0, false, null, null)
val scanResult = ScanResult(scanRequest, true, null, null, false, 0, null, null, null)
@@ -329,7 +329,7 @@
val packageSetting = mRule.system()
.createBasicSettingBuilder(pair.first.parentFile, parsedPackage.hideAsFinal())
.setPkgFlags(ApplicationInfo.FLAG_SYSTEM).build()
- val scanRequest = ScanRequest(parsedPackage, null, null, null,
+ val scanRequest = ScanRequest(parsedPackage, null, null, null, null,
null, null, null, 0, 0, false, null, null)
val scanResult = ScanResult(scanRequest, true, packageSetting, null,
false, 0, null, null, listOf(testInfo))
diff --git a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
index 0b488b2..5fb3a4e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
@@ -33,6 +33,7 @@
import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -445,6 +446,48 @@
mService.getWallpaperDimAmount(), dimAmount, 0.0);
}
+ @Test
+ public void testGetAdjustedWallpaperColorsOnDimming() throws RemoteException {
+ final int testUserId = USER_SYSTEM;
+ mService.switchUser(testUserId, null);
+ mService.setWallpaperComponent(sDefaultWallpaperComponent);
+ WallpaperData wallpaper = mService.getCurrentWallpaperData(FLAG_SYSTEM, testUserId);
+
+ // Mock a wallpaper data with color hints that support dark text and dark theme
+ // but not HINT_FROM_BITMAP
+ wallpaper.primaryColors = new WallpaperColors(Color.valueOf(Color.WHITE), null, null,
+ WallpaperColors.HINT_SUPPORTS_DARK_TEXT | WallpaperColors.HINT_SUPPORTS_DARK_THEME);
+ mService.setWallpaperDimAmount(0.6f);
+ int colorHints = mService.getAdjustedWallpaperColorsOnDimming(wallpaper).getColorHints();
+ // Dimmed wallpaper not extracted from bitmap does not support dark text and dark theme
+ assertNotEquals(WallpaperColors.HINT_SUPPORTS_DARK_TEXT,
+ colorHints & WallpaperColors.HINT_SUPPORTS_DARK_TEXT);
+ assertNotEquals(WallpaperColors.HINT_SUPPORTS_DARK_THEME,
+ colorHints & WallpaperColors.HINT_SUPPORTS_DARK_THEME);
+
+ // Remove dimming
+ mService.setWallpaperDimAmount(0f);
+ colorHints = mService.getAdjustedWallpaperColorsOnDimming(wallpaper).getColorHints();
+ // Undimmed wallpaper not extracted from bitmap does support dark text and dark theme
+ assertEquals(WallpaperColors.HINT_SUPPORTS_DARK_TEXT,
+ colorHints & WallpaperColors.HINT_SUPPORTS_DARK_TEXT);
+ assertEquals(WallpaperColors.HINT_SUPPORTS_DARK_THEME,
+ colorHints & WallpaperColors.HINT_SUPPORTS_DARK_THEME);
+
+ // Mock a wallpaper data with color hints that support dark text and dark theme
+ // and was extracted from bitmap
+ wallpaper.primaryColors = new WallpaperColors(Color.valueOf(Color.WHITE), null, null,
+ WallpaperColors.HINT_SUPPORTS_DARK_TEXT | WallpaperColors.HINT_SUPPORTS_DARK_THEME
+ | WallpaperColors.HINT_FROM_BITMAP);
+ mService.setWallpaperDimAmount(0.6f);
+ colorHints = mService.getAdjustedWallpaperColorsOnDimming(wallpaper).getColorHints();
+ // Dimmed wallpaper should still support dark text and dark theme
+ assertEquals(WallpaperColors.HINT_SUPPORTS_DARK_TEXT,
+ colorHints & WallpaperColors.HINT_SUPPORTS_DARK_TEXT);
+ assertEquals(WallpaperColors.HINT_SUPPORTS_DARK_THEME,
+ colorHints & WallpaperColors.HINT_SUPPORTS_DARK_THEME);
+ }
+
// Verify that after continue switch user from userId 0 to lastUserId, the wallpaper data for
// non-current user must not bind to wallpaper service.
private void verifyNoConnectionBeforeLastUser(int lastUserId) {
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index d9f73d9..53cab9e 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -130,6 +130,19 @@
android:resource="@xml/test_account_type2_authenticator"/>
</service>
+ <service
+ android:name="com.android.server.dreams.TestDreamService"
+ android:exported="false"
+ android:label="Test Dream" >
+ <intent-filter>
+ <action android:name="android.service.dreams.DreamService" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <meta-data
+ android:name="android.service.dream"
+ android:resource="@xml/test_dream_metadata" />
+ </service>
+
<receiver android:name="com.android.server.devicepolicy.ApplicationRestrictionsTest$AdminReceiver"
android:permission="android.permission.BIND_DEVICE_ADMIN"
android:exported="true">
diff --git a/packages/SystemUI/res/layout/qs_detail_switch.xml b/services/tests/servicestests/res/xml/test_dream_metadata.xml
similarity index 62%
copy from packages/SystemUI/res/layout/qs_detail_switch.xml
copy to services/tests/servicestests/res/xml/test_dream_metadata.xml
index abb2497..aa054f1 100644
--- a/packages/SystemUI/res/layout/qs_detail_switch.xml
+++ b/services/tests/servicestests/res/xml/test_dream_metadata.xml
@@ -1,5 +1,5 @@
<!--
- ~ Copyright (C) 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,10 +14,6 @@
~ limitations under the License.
-->
-<Switch
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/toggle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:clickable="false"
- android:textAppearance="@style/TextAppearance.QS.DetailHeader" />
\ No newline at end of file
+<dream xmlns:android="http://schemas.android.com/apk/res/android"
+ android:settingsActivity="com.android.server.dreams/.TestDreamSettingsActivity"
+ android:showClockAndComplications="false" />
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 489e2f7..0000000
--- 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 6a7d298..68994e6 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/accessibility/AccessibilityInteractionControllerNodeRequestsTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInteractionControllerNodeRequestsTest.java
index 7179c60..022c137 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInteractionControllerNodeRequestsTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInteractionControllerNodeRequestsTest.java
@@ -18,8 +18,12 @@
import static android.view.accessibility.AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
-import static android.view.accessibility.AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS;
+import static android.view.accessibility.AccessibilityNodeInfo.FLAG_PREFETCH_ANCESTORS;
+import static android.view.accessibility.AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS_BREADTH_FIRST;
+import static android.view.accessibility.AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS_DEPTH_FIRST;
+import static android.view.accessibility.AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS_HYBRID;
import static android.view.accessibility.AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS;
+import static android.view.accessibility.AccessibilityNodeInfo.FLAG_PREFETCH_UNINTERRUPTIBLE;
import static android.view.accessibility.AccessibilityNodeInfo.ROOT_NODE_ID;
import static org.junit.Assert.assertEquals;
@@ -74,24 +78,37 @@
@Captor
private ArgumentCaptor<AccessibilityNodeInfo> mFindInfoCaptor;
+ @Captor
+ private ArgumentCaptor<List<AccessibilityNodeInfo>> mFindInfosCaptor;
@Captor private ArgumentCaptor<List<AccessibilityNodeInfo>> mPrefetchInfoListCaptor;
private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
private static final int MOCK_CLIENT_1_THREAD_AND_PROCESS_ID = 1;
private static final int MOCK_CLIENT_2_THREAD_AND_PROCESS_ID = 2;
- private static final String FRAME_LAYOUT_DESCRIPTION = "frameLayout";
+ private static final String ROOT_FRAME_LAYOUT_DESCRIPTION = "rootFrameLayout";
private static final String TEXT_VIEW_1_DESCRIPTION = "textView1";
private static final String TEXT_VIEW_2_DESCRIPTION = "textView2";
+ private static final String CHILD_FRAME_DESCRIPTION = "childFrameLayout";
+ private static final String TEXT_VIEW_3_DESCRIPTION = "textView3";
+ private static final String TEXT_VIEW_4_DESCRIPTION = "textView4";
+ private static final String VIRTUAL_VIEW_1_DESCRIPTION = "virtual descendant 1";
+ private static final String VIRTUAL_VIEW_2_DESCRIPTION = "virtual descendant 2";
+ private static final String VIRTUAL_VIEW_3_DESCRIPTION = "virtual descendant 3";
- private TestFrameLayout mFrameLayout;
+ private TestFrameLayout mRootFrameLayout;
+ private TestFrameLayout mChildFrameLayout;
private TestTextView mTextView1;
- private TestTextView2 mTextView2;
+ private TestTextView mTextView2;
+ private TestTextView mTextView3;
+ private TestTextView mTextView4;
private boolean mSendClient1RequestForTextAfterTextPrefetched;
private boolean mSendClient2RequestForTextAfterTextPrefetched;
private boolean mSendRequestForTextAndIncludeUnImportantViews;
private boolean mSendClient1RequestForRootAfterTextPrefetched;
+ private boolean mSendClient2RequestForTextAfterRootPrefetched;
+
private int mMockClient1InteractionId;
private int mMockClient2InteractionId;
@@ -103,23 +120,45 @@
final Context context = mInstrumentation.getTargetContext();
final ViewRootImpl viewRootImpl = new ViewRootImpl(context, context.getDisplay());
- mFrameLayout = new TestFrameLayout(context);
- mTextView1 = new TestTextView(context);
- mTextView2 = new TestTextView2(context);
+ mTextView1 = new TestTextView(context, 1, TEXT_VIEW_1_DESCRIPTION);
+ mTextView2 = new TestTextView(context, 2, TEXT_VIEW_2_DESCRIPTION);
+ mTextView3 = new TestTextView(context, 4, TEXT_VIEW_3_DESCRIPTION);
+ mTextView4 = new TestTextView(context, 5, TEXT_VIEW_4_DESCRIPTION);
- mFrameLayout.addView(mTextView1);
- mFrameLayout.addView(mTextView2);
+ mChildFrameLayout = new TestFrameLayout(context, 3,
+ CHILD_FRAME_DESCRIPTION, new ArrayList<>(List.of(mTextView4)));
+ mRootFrameLayout = new TestFrameLayout(context, 0, ROOT_FRAME_LAYOUT_DESCRIPTION,
+ new ArrayList<>(
+ List.of(mTextView1, mTextView2, mChildFrameLayout, mTextView3)));
+
+ mRootFrameLayout.addView(mTextView1);
+ mRootFrameLayout.addView(mTextView2);
+ mChildFrameLayout.addView(mTextView4);
+ mRootFrameLayout.addView(mChildFrameLayout);
+ mRootFrameLayout.addView(mTextView3);
+
+ // Layout
+ // mRootFrameLayout
+ // / | | \
+ // mTextView1 mTextView2 mChildFrameLayout mTextView3
+ // |
+ // mTextView4
// The controller retrieves views through this manager, and registration happens on
- // when attached to a window, which we don't have. We can simply reference FrameLayout
- // with ROOT_NODE_ID
+ // when attached to a window, which we don't have. We can simply reference
+ // RootFrameLayout with ROOT_NODE_ID.
AccessibilityNodeIdManager.getInstance().registerViewWithId(
mTextView1, mTextView1.getAccessibilityViewId());
AccessibilityNodeIdManager.getInstance().registerViewWithId(
mTextView2, mTextView2.getAccessibilityViewId());
-
+ AccessibilityNodeIdManager.getInstance().registerViewWithId(
+ mTextView3, mTextView3.getAccessibilityViewId());
+ AccessibilityNodeIdManager.getInstance().registerViewWithId(
+ mChildFrameLayout, mChildFrameLayout.getAccessibilityViewId());
+ AccessibilityNodeIdManager.getInstance().registerViewWithId(
+ mTextView4, mTextView4.getAccessibilityViewId());
try {
- viewRootImpl.setView(mFrameLayout, new WindowManager.LayoutParams(), null);
+ viewRootImpl.setView(mRootFrameLayout, new WindowManager.LayoutParams(), null);
} catch (WindowManager.BadTokenException e) {
// activity isn't running, we will ignore BadTokenException.
@@ -137,66 +176,79 @@
mTextView1.getAccessibilityViewId());
AccessibilityNodeIdManager.getInstance().unregisterViewWithId(
mTextView2.getAccessibilityViewId());
+ AccessibilityNodeIdManager.getInstance().unregisterViewWithId(
+ mTextView3.getAccessibilityViewId());
+ AccessibilityNodeIdManager.getInstance().unregisterViewWithId(
+ mTextView4.getAccessibilityViewId());
+ AccessibilityNodeIdManager.getInstance().unregisterViewWithId(
+ mChildFrameLayout.getAccessibilityViewId());
}
/**
* Tests a basic request for the root node with prefetch flag
- * {@link AccessibilityNodeInfo#FLAG_PREFETCH_DESCENDANTS}
+ * {@link AccessibilityNodeInfo#FLAG_PREFETCH_DESCENDANTS_HYBRID}
*
* @throws RemoteException
*/
@Test
public void testFindRootView_withOneClient_shouldReturnRootNodeAndPrefetchDescendants()
throws RemoteException {
- // Request for our FrameLayout
+ // Request for our RootFrameLayout.
sendNodeRequestToController(ROOT_NODE_ID, mMockClientCallback1,
- mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS);
+ mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS_HYBRID);
mInstrumentation.waitForIdleSync();
- // Verify we get FrameLayout
+ // Verify we get RootFrameLayout.
verify(mMockClientCallback1).setFindAccessibilityNodeInfoResult(
mFindInfoCaptor.capture(), eq(mMockClient1InteractionId));
AccessibilityNodeInfo infoSentToService = mFindInfoCaptor.getValue();
- assertEquals(FRAME_LAYOUT_DESCRIPTION, infoSentToService.getContentDescription());
+ assertEquals(ROOT_FRAME_LAYOUT_DESCRIPTION, infoSentToService.getContentDescription());
verify(mMockClientCallback1).setPrefetchAccessibilityNodeInfoResult(
mPrefetchInfoListCaptor.capture(), eq(mMockClient1InteractionId));
- // The descendants are our two TextViews
+ // The descendants are RootFrameLayout's 5 descendants.
List<AccessibilityNodeInfo> prefetchedNodes = mPrefetchInfoListCaptor.getValue();
- assertEquals(2, prefetchedNodes.size());
+ assertEquals(5, prefetchedNodes.size());
assertEquals(TEXT_VIEW_1_DESCRIPTION, prefetchedNodes.get(0).getContentDescription());
assertEquals(TEXT_VIEW_2_DESCRIPTION, prefetchedNodes.get(1).getContentDescription());
-
+ assertEquals(CHILD_FRAME_DESCRIPTION, prefetchedNodes.get(2).getContentDescription());
+ assertEquals(TEXT_VIEW_3_DESCRIPTION, prefetchedNodes.get(3).getContentDescription());
+ assertEquals(TEXT_VIEW_4_DESCRIPTION, prefetchedNodes.get(4).getContentDescription());
}
/**
- * Tests a basic request for TestTextView1's node with prefetch flag
- * {@link AccessibilityNodeInfo#FLAG_PREFETCH_SIBLINGS}
+ * Tests a basic request for TextView1's node with prefetch flag.
+ * {@link AccessibilityNodeInfo#FLAG_PREFETCH_SIBLINGS} and
+ * {@link AccessibilityNodeInfo#FLAG_PREFETCH_ANCESTORS}.
*
* @throws RemoteException
*/
@Test
- public void testFindTextView_withOneClient_shouldReturnNodeAndPrefetchedSiblings()
+ public void testFindTextView_withOneClient_shouldReturnNodeAndPrefetchedSiblingsAndParent()
throws RemoteException {
- // Request for TextView1
+ // Request for TextView1.
sendNodeRequestToController(AccessibilityNodeInfo.makeNodeId(
mTextView1.getAccessibilityViewId(), AccessibilityNodeProvider.HOST_VIEW_ID),
- mMockClientCallback1, mMockClient1InteractionId, FLAG_PREFETCH_SIBLINGS);
+ mMockClientCallback1, mMockClient1InteractionId,
+ FLAG_PREFETCH_SIBLINGS | FLAG_PREFETCH_ANCESTORS);
mInstrumentation.waitForIdleSync();
- // Verify we get TextView1
+ // Verify we get TextView1.
verify(mMockClientCallback1).setFindAccessibilityNodeInfoResult(
mFindInfoCaptor.capture(), eq(mMockClient1InteractionId));
AccessibilityNodeInfo infoSentToService = mFindInfoCaptor.getValue();
assertEquals(TEXT_VIEW_1_DESCRIPTION, infoSentToService.getContentDescription());
- // Verify the prefetched sibling of TextView1 is TextView2
+ // Verify the prefetched sibling of TextView1 is TextView2, ChildFrameLayout, and TextView3.
+ // The predecessor is RootFrameLayout.
verify(mMockClientCallback1).setPrefetchAccessibilityNodeInfoResult(
mPrefetchInfoListCaptor.capture(), eq(mMockClient1InteractionId));
- // TextView2 is the prefetched sibling
List<AccessibilityNodeInfo> prefetchedNodes = mPrefetchInfoListCaptor.getValue();
- assertEquals(1, prefetchedNodes.size());
- assertEquals(TEXT_VIEW_2_DESCRIPTION, prefetchedNodes.get(0).getContentDescription());
+ assertEquals(4, prefetchedNodes.size());
+ assertEquals(ROOT_FRAME_LAYOUT_DESCRIPTION, prefetchedNodes.get(0).getContentDescription());
+ assertEquals(TEXT_VIEW_2_DESCRIPTION, prefetchedNodes.get(1).getContentDescription());
+ assertEquals(CHILD_FRAME_DESCRIPTION, prefetchedNodes.get(2).getContentDescription());
+ assertEquals(TEXT_VIEW_3_DESCRIPTION, prefetchedNodes.get(3).getContentDescription());
}
/**
@@ -213,7 +265,8 @@
@Test
public void testFindRootAndTextNodes_withTwoClients_shouldPreventClient1Prefetch()
throws RemoteException {
- mFrameLayout.setAccessibilityDelegate(new View.AccessibilityDelegate() {
+ mSendClient2RequestForTextAfterRootPrefetched = true;
+ mRootFrameLayout.setAccessibilityDelegate(new View.AccessibilityDelegate() {
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(host, info);
@@ -221,41 +274,50 @@
mTextView1.getAccessibilityViewId(),
AccessibilityNodeProvider.HOST_VIEW_ID);
- // Enqueue a request when this node is found from a different service for
- // TextView1
+ if (mSendClient2RequestForTextAfterRootPrefetched) {
+ mSendClient2RequestForTextAfterRootPrefetched = false;
+
+ // Enqueue a request when this node is found from client 2 for TextView1.
sendNodeRequestToController(nodeId, mMockClientCallback2,
- mMockClient2InteractionId, FLAG_PREFETCH_SIBLINGS);
+ mMockClient2InteractionId,
+ FLAG_PREFETCH_SIBLINGS);
+ }
}
});
- // Client 1 request for FrameLayout
+ // Client 1 request for RootFrameLayout.
sendNodeRequestToController(ROOT_NODE_ID, mMockClientCallback1,
- mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS);
+ mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS_HYBRID);
mInstrumentation.waitForIdleSync();
- // Verify client 1 gets FrameLayout
+ // Verify client 1 gets RootFrameLayout.
verify(mMockClientCallback1).setFindAccessibilityNodeInfoResult(
mFindInfoCaptor.capture(), eq(mMockClient1InteractionId));
AccessibilityNodeInfo infoSentToService = mFindInfoCaptor.getValue();
- assertEquals(FRAME_LAYOUT_DESCRIPTION, infoSentToService.getContentDescription());
+ assertEquals(ROOT_FRAME_LAYOUT_DESCRIPTION, infoSentToService.getContentDescription());
- // The second request is put in the queue in the FrameLayout's onInitializeA11yNodeInfo,
- // meaning prefetching is interrupted and does not even begin for the first request
+ // The second request is put in the queue in the RootFrameLayout's onInitializeA11yNodeInfo,
+ // meaning prefetching is does not occur for first request.
verify(mMockClientCallback1, never())
.setPrefetchAccessibilityNodeInfoResult(anyList(), anyInt());
- // Verify client 2 gets TextView1
+ // Verify client 2 gets TextView1.
verify(mMockClientCallback2).setFindAccessibilityNodeInfoResult(
mFindInfoCaptor.capture(), eq(mMockClient2InteractionId));
infoSentToService = mFindInfoCaptor.getValue();
assertEquals(TEXT_VIEW_1_DESCRIPTION, infoSentToService.getContentDescription());
- // Verify the prefetched sibling of TextView1 is TextView2 (FLAG_PREFETCH_SIBLINGS)
+ // Verify the prefetched sibling of TextView1 is TextView2 and ChildFrameLayout
+ // (FLAG_PREFETCH_SIBLINGS). The parent, RootFrameLayout, is also retrieved. Since
+ // predecessors takes priority over siblings, RootFrameLayout is the first node in the list.
verify(mMockClientCallback2).setPrefetchAccessibilityNodeInfoResult(
mPrefetchInfoListCaptor.capture(), eq(mMockClient2InteractionId));
List<AccessibilityNodeInfo> prefetchedNodes = mPrefetchInfoListCaptor.getValue();
- assertEquals(1, prefetchedNodes.size());
- assertEquals(TEXT_VIEW_2_DESCRIPTION, prefetchedNodes.get(0).getContentDescription());
+ assertEquals(4, prefetchedNodes.size());
+ assertEquals(ROOT_FRAME_LAYOUT_DESCRIPTION, prefetchedNodes.get(0).getContentDescription());
+ assertEquals(TEXT_VIEW_2_DESCRIPTION, prefetchedNodes.get(1).getContentDescription());
+ assertEquals(CHILD_FRAME_DESCRIPTION, prefetchedNodes.get(2).getContentDescription());
+ assertEquals(TEXT_VIEW_3_DESCRIPTION, prefetchedNodes.get(3).getContentDescription());
}
/**
@@ -282,43 +344,43 @@
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(host, info);
- info.setContentDescription(TEXT_VIEW_1_DESCRIPTION);
final long nodeId = AccessibilityNodeInfo.makeNodeId(
mTextView1.getAccessibilityViewId(),
AccessibilityNodeProvider.HOST_VIEW_ID);
if (mSendClient1RequestForTextAfterTextPrefetched) {
- // Prevent a loop when processing second request
+ // Prevent a loop when processing this node's second request.
mSendClient1RequestForTextAfterTextPrefetched = false;
- // TextView1 is prefetched here after the FrameLayout is found. Now enqueue a
- // same-client request for TextView1
+ // TextView1 is prefetched here after the RootFrameLayout is found. Now enqueue
+ // a same-client request for TextView1.
sendNodeRequestToController(nodeId, mMockClientCallback1,
- ++mMockClient1InteractionId, FLAG_PREFETCH_SIBLINGS);
+ ++mMockClient1InteractionId,
+ FLAG_PREFETCH_SIBLINGS | FLAG_PREFETCH_ANCESTORS);
}
}
});
- // Client 1 requests FrameLayout
+ // Client 1 requests RootFrameLayout.
sendNodeRequestToController(ROOT_NODE_ID, mMockClientCallback1,
- mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS);
+ mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS_HYBRID);
- // Flush out all messages
+ // Flush out all messages.
mInstrumentation.waitForIdleSync();
- // When TextView1 is prefetched for FrameLayout, we put a message on the queue in
- // TextView1's onInitializeA11yNodeInfo that requests for TextView1. The service thus get
+ // When TextView1 is prefetched for RootFrameLayout, we put a message on the queue in
+ // TextView1's onInitializeA11yNodeInfo that requests for TextView1. The service thus gets
// two node results for FrameLayout and TextView1.
verify(mMockClientCallback1, times(2))
.setFindAccessibilityNodeInfoResult(mFindInfoCaptor.capture(), anyInt());
List<AccessibilityNodeInfo> foundNodes = mFindInfoCaptor.getAllValues();
- assertEquals(FRAME_LAYOUT_DESCRIPTION, foundNodes.get(0).getContentDescription());
+ assertEquals(ROOT_FRAME_LAYOUT_DESCRIPTION, foundNodes.get(0).getContentDescription());
assertEquals(TEXT_VIEW_1_DESCRIPTION, foundNodes.get(1).getContentDescription());
- // The controller will look at FrameLayout's prefetched nodes and find matching nodes in
- // pending requests. The prefetched TextView1 matches the second request. This is removed
- // from the first request's prefetch list, which is now empty. The second
- // request was removed from queue and prefetching for this request never occurred.
+ // The controller will look at RootFrameLayout's prefetched nodes and find matching nodes in
+ // pending requests. The prefetched TextView1 satisfied the second request. This is removed
+ // from the first request's prefetch list, which is now empty. The second request is removed
+ // from queue.
verify(mMockClientCallback1, never())
.setPrefetchAccessibilityNodeInfoResult(mPrefetchInfoListCaptor.capture(),
eq(mMockClient1InteractionId - 1));
@@ -347,42 +409,41 @@
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(host, info);
- info.setContentDescription(TEXT_VIEW_1_DESCRIPTION);
final long nodeId = AccessibilityNodeInfo.makeNodeId(
- mFrameLayout.getAccessibilityViewId(),
+ mRootFrameLayout.getAccessibilityViewId(),
AccessibilityNodeProvider.HOST_VIEW_ID);
if (mSendClient1RequestForRootAfterTextPrefetched) {
- // Prevent a loop when processing second request
+ // Prevent a loop when processing this node's second request.
mSendClient1RequestForRootAfterTextPrefetched = false;
// TextView1 is prefetched here after the FrameLayout is found. Now enqueue a
- // same-client request for FrameLayout
+ // same-client request for FrameLayout.
sendNodeRequestToController(nodeId, mMockClientCallback1,
- ++mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS);
+ ++mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS_HYBRID);
}
}
});
- // Client 1 requests FrameLayout
+ // Client 1 requests RootFrameLayout.
sendNodeRequestToController(ROOT_NODE_ID, mMockClientCallback1,
- mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS);
+ mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS_HYBRID);
- // Flush out all messages
+ // Flush out all messages.
mInstrumentation.waitForIdleSync();
- // When TextView1 is prefetched for FrameLayout, we put a message on the queue in
+ // When TextView1 is prefetched for RootFrameLayout, we put a message on the queue in
// TextView1's onInitializeA11yNodeInfo that requests for TextView1. The service thus gets
// two node results for FrameLayout and TextView1.
verify(mMockClientCallback1, times(2))
.setFindAccessibilityNodeInfoResult(mFindInfoCaptor.capture(), anyInt());
List<AccessibilityNodeInfo> foundNodes = mFindInfoCaptor.getAllValues();
- assertEquals(FRAME_LAYOUT_DESCRIPTION, foundNodes.get(0).getContentDescription());
- assertEquals(FRAME_LAYOUT_DESCRIPTION, foundNodes.get(1).getContentDescription());
+ assertEquals(ROOT_FRAME_LAYOUT_DESCRIPTION, foundNodes.get(0).getContentDescription());
+ assertEquals(ROOT_FRAME_LAYOUT_DESCRIPTION, foundNodes.get(1).getContentDescription());
- // The controller will look at FrameLayout's prefetched nodes and find matching nodes in
+ // The controller will look at RootFrameLayout's prefetched nodes and find matching nodes in
// pending requests. The first requested node (FrameLayout) is also checked, and this
- // satifies the second request. The second request is removed from queue and prefetching
+ // satisfies the second request. The second request is removed from queue and prefetching
// for this request never occurs.
verify(mMockClientCallback1, times(1))
.setPrefetchAccessibilityNodeInfoResult(mPrefetchInfoListCaptor.capture(),
@@ -406,7 +467,6 @@
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(host, info);
- info.setContentDescription(TEXT_VIEW_1_DESCRIPTION);
final long nodeId = AccessibilityNodeInfo.makeNodeId(
mTextView1.getAccessibilityViewId(),
AccessibilityNodeProvider.HOST_VIEW_ID);
@@ -414,30 +474,30 @@
if (mSendClient2RequestForTextAfterTextPrefetched) {
mSendClient2RequestForTextAfterTextPrefetched = false;
// TextView1 is prefetched here. Now enqueue client 2's request for
- // TextView1
+ // TextView1.
sendNodeRequestToController(nodeId, mMockClientCallback2,
mMockClient2InteractionId, FLAG_PREFETCH_SIBLINGS);
}
}
});
- // Client 1 requests FrameLayout
+ // Client 1 requests RootFrameLayout.
sendNodeRequestToController(ROOT_NODE_ID, mMockClientCallback1,
- mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS);
+ mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS_HYBRID);
mInstrumentation.waitForIdleSync();
- // Verify client 1 gets FrameLayout
+ // Verify client 1 gets RootFrameLayout.
verify(mMockClientCallback1, times(1))
.setFindAccessibilityNodeInfoResult(mFindInfoCaptor.capture(), anyInt());
- assertEquals(FRAME_LAYOUT_DESCRIPTION,
+ assertEquals(ROOT_FRAME_LAYOUT_DESCRIPTION,
mFindInfoCaptor.getValue().getContentDescription());
- // Verify client 1 doesn't have prefetched nodes
+ // Verify client 1 doesn't have prefetched nodes.
verify(mMockClientCallback1, never())
.setPrefetchAccessibilityNodeInfoResult(mPrefetchInfoListCaptor.capture(),
eq(mMockClient1InteractionId));
- // Verify client 2 gets TextView1
+ // Verify client 2 gets TextView1.
verify(mMockClientCallback2, times(1))
.setFindAccessibilityNodeInfoResult(mFindInfoCaptor.capture(), anyInt());
@@ -458,7 +518,6 @@
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(host, info);
- info.setContentDescription(TEXT_VIEW_1_DESCRIPTION);
final long nodeId = AccessibilityNodeInfo.makeNodeId(
mTextView1.getAccessibilityViewId(),
AccessibilityNodeProvider.HOST_VIEW_ID);
@@ -466,17 +525,18 @@
if (mSendRequestForTextAndIncludeUnImportantViews) {
mSendRequestForTextAndIncludeUnImportantViews = false;
// TextView1 is prefetched here for client 1. Now enqueue a request from a
- // different client that holds different fetch flags for TextView1
+ // different client that holds different fetch flags for TextView1.
sendNodeRequestToController(nodeId, mMockClientCallback2,
mMockClient2InteractionId,
- FLAG_PREFETCH_SIBLINGS | FLAG_INCLUDE_NOT_IMPORTANT_VIEWS);
+ FLAG_PREFETCH_SIBLINGS | FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
+ | FLAG_PREFETCH_ANCESTORS);
}
}
});
// Mockito does not make copies of objects when called. It holds references, so
// the captor would point to client 2's results after all requests are processed. Verify
- // prefetched node immediately
+ // prefetched node immediately.
doAnswer(invocation -> {
List<AccessibilityNodeInfo> prefetched = invocation.getArgument(0);
assertEquals(TEXT_VIEW_1_DESCRIPTION, prefetched.get(0).getContentDescription());
@@ -484,39 +544,290 @@
}).when(mMockClientCallback1).setPrefetchAccessibilityNodeInfoResult(anyList(),
eq(mMockClient1InteractionId));
- // Client 1 requests FrameLayout
+ // Client 1 requests RootFrameLayout.
sendNodeRequestToController(ROOT_NODE_ID, mMockClientCallback1,
- mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS);
+ mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS_HYBRID);
mInstrumentation.waitForIdleSync();
- // Verify client 1 gets FrameLayout
+ // Verify client 1 gets RootFrameLayout.
verify(mMockClientCallback1, times(1))
.setFindAccessibilityNodeInfoResult(mFindInfoCaptor.capture(),
eq(mMockClient1InteractionId));
- assertEquals(FRAME_LAYOUT_DESCRIPTION,
+ assertEquals(ROOT_FRAME_LAYOUT_DESCRIPTION,
mFindInfoCaptor.getValue().getContentDescription());
// Verify client 1 has prefetched results. The only prefetched node is TextView1
- // (from above doAnswer)
+ // (from above doAnswer).
verify(mMockClientCallback1, times(1))
.setPrefetchAccessibilityNodeInfoResult(mPrefetchInfoListCaptor.capture(),
eq(mMockClient1InteractionId));
- // Verify client 2 gets TextView1
+ // Verify client 2 gets TextView1.
verify(mMockClientCallback2, times(1))
.setFindAccessibilityNodeInfoResult(mFindInfoCaptor.capture(),
eq(mMockClient2InteractionId));
assertEquals(TEXT_VIEW_1_DESCRIPTION,
mFindInfoCaptor.getValue().getContentDescription());
- // Verify client 2 has TextView2 as a prefetched node
+ // Verify client 2 gets TextView1's siblings and its parent as prefetched nodes.
verify(mMockClientCallback2, times(1))
.setPrefetchAccessibilityNodeInfoResult(mPrefetchInfoListCaptor.capture(),
eq(mMockClient2InteractionId));
List<AccessibilityNodeInfo> prefetchedNode = mPrefetchInfoListCaptor.getValue();
- assertEquals(1, prefetchedNode.size());
- assertEquals(TEXT_VIEW_2_DESCRIPTION, prefetchedNode.get(0).getContentDescription());
+ assertEquals(4, prefetchedNode.size());
+ assertEquals(ROOT_FRAME_LAYOUT_DESCRIPTION, prefetchedNode.get(0).getContentDescription());
+ assertEquals(TEXT_VIEW_2_DESCRIPTION, prefetchedNode.get(1).getContentDescription());
+ assertEquals(CHILD_FRAME_DESCRIPTION, prefetchedNode.get(2).getContentDescription());
+ assertEquals(TEXT_VIEW_3_DESCRIPTION, prefetchedNode.get(3).getContentDescription());
+ }
+
+ /**
+ * Tests a request for 4 nodes using depth first traversal.
+ * Request 1: Request the root node.
+ * Request 2: When TextView4 is prefetched, send a request for the root node. Depth first
+ * traversal completes here.
+ * Out of the 5 descendants, the root frame's 3rd child (TextView3) should not be prefetched,
+ * since this was not reached by the df-traversal.
+ *
+ * Layout
+ * mRootFrameLayout
+ * / | | \
+ * mTextView1 mTextView2 mChildFrameLayout *mTextView3*
+ * |
+ * mTextView4
+ * @throws RemoteException
+ */
+ @Test
+ public void testFindRootView_depthFirstStrategy_shouldReturnRootNodeAndPrefetch4Descendants()
+ throws RemoteException {
+ mTextView4.setAccessibilityDelegate(new View.AccessibilityDelegate(){
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ final long nodeId = AccessibilityNodeInfo.makeNodeId(
+ mRootFrameLayout.getAccessibilityViewId(),
+ AccessibilityNodeProvider.HOST_VIEW_ID);
+ // This request is satisfied by first request.
+ sendNodeRequestToController(nodeId, mMockClientCallback2,
+ mMockClient2InteractionId, FLAG_PREFETCH_DESCENDANTS_HYBRID);
+
+ }
+ });
+ // Request for our RootFrameLayout.
+ sendNodeRequestToController(ROOT_NODE_ID, mMockClientCallback1,
+ mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS_DEPTH_FIRST);
+ mInstrumentation.waitForIdleSync();
+
+ // Verify we get RootFrameLayout.
+ verify(mMockClientCallback1).setFindAccessibilityNodeInfoResult(
+ mFindInfoCaptor.capture(), eq(mMockClient1InteractionId));
+ AccessibilityNodeInfo infoSentToService = mFindInfoCaptor.getValue();
+ assertEquals(ROOT_FRAME_LAYOUT_DESCRIPTION, infoSentToService.getContentDescription());
+
+ verify(mMockClientCallback1).setPrefetchAccessibilityNodeInfoResult(
+ mPrefetchInfoListCaptor.capture(), eq(mMockClient1InteractionId));
+ // Prefetch all the descendants besides TextView3.
+ List<AccessibilityNodeInfo> prefetchedNodes = mPrefetchInfoListCaptor.getValue();
+ assertEquals(4, prefetchedNodes.size());
+ assertEquals(TEXT_VIEW_1_DESCRIPTION, prefetchedNodes.get(0).getContentDescription());
+ assertEquals(TEXT_VIEW_2_DESCRIPTION, prefetchedNodes.get(1).getContentDescription());
+ assertEquals(CHILD_FRAME_DESCRIPTION, prefetchedNodes.get(2).getContentDescription());
+ assertEquals(TEXT_VIEW_4_DESCRIPTION, prefetchedNodes.get(3).getContentDescription());
+ }
+
+ /**
+ * Tests a request for 4 nodes using breadth first traversal.
+ * Request 1: Request the root node
+ * Request 2: When TextView3 is prefetched, send a request for the root node. Breadth first
+ * traversal completes here.
+ * Out of the 5 descendants, the child frame's child (TextView4) should not be prefetched, since
+ * this was not reached by the bf-traversal.
+ * Layout
+ * mRootFrameLayout
+ * / | | \
+ * mTextView1 mTextView2 mChildFrameLayout *mTextView3*
+ * |
+ * *mTextView4*
+ * @throws RemoteException
+ */
+ @Test
+ public void testFindRootView_breadthFirstStrategy_shouldReturnRootNodeAndPrefetch4Descendants()
+ throws RemoteException {
+
+ mTextView3.setAccessibilityDelegate(new View.AccessibilityDelegate(){
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ final long nodeId = AccessibilityNodeInfo.makeNodeId(
+ mRootFrameLayout.getAccessibilityViewId(),
+ AccessibilityNodeProvider.HOST_VIEW_ID);
+
+ // This request is satisfied by first request.
+ sendNodeRequestToController(nodeId, mMockClientCallback2,
+ mMockClient2InteractionId, FLAG_PREFETCH_DESCENDANTS_HYBRID);
+ }
+ });
+ // Request for our RootFrameLayout.
+ sendNodeRequestToController(ROOT_NODE_ID, mMockClientCallback1,
+ mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS_BREADTH_FIRST);
+ mInstrumentation.waitForIdleSync();
+
+ // Verify we get RootFrameLayout.
+ verify(mMockClientCallback1).setFindAccessibilityNodeInfoResult(
+ mFindInfoCaptor.capture(), eq(mMockClient1InteractionId));
+ AccessibilityNodeInfo infoSentToService = mFindInfoCaptor.getValue();
+ assertEquals(ROOT_FRAME_LAYOUT_DESCRIPTION, infoSentToService.getContentDescription());
+
+ verify(mMockClientCallback1).setPrefetchAccessibilityNodeInfoResult(
+ mPrefetchInfoListCaptor.capture(), eq(mMockClient1InteractionId));
+ // Prefetch all the descendants besides TextView4.
+ List<AccessibilityNodeInfo> prefetchedNodes = mPrefetchInfoListCaptor.getValue();
+ assertEquals(4, prefetchedNodes.size());
+ assertEquals(TEXT_VIEW_1_DESCRIPTION, prefetchedNodes.get(0).getContentDescription());
+ assertEquals(TEXT_VIEW_2_DESCRIPTION, prefetchedNodes.get(1).getContentDescription());
+ assertEquals(CHILD_FRAME_DESCRIPTION, prefetchedNodes.get(2).getContentDescription());
+ assertEquals(TEXT_VIEW_3_DESCRIPTION, prefetchedNodes.get(3).getContentDescription());
+ }
+
+ /**
+ * Tests a request that should not have prefetching interrupted.
+ * Request 1: Client 1 requests the root node
+ * Request 2: When the root node is initialized in
+ * {@link TestFrameLayout#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)},
+ * Client 2 requests TextView1's node
+ *
+ * Request 1 is not interrupted during prefetch, and its prefetched node satisfies Request 2.
+ *
+ * @throws RemoteException
+ */
+ @Test
+ public void testFindRootAndTextNodes_withNoInterruptStrategy_shouldSatisfySecondRequest()
+ throws RemoteException {
+ mRootFrameLayout.setAccessibilityDelegate(new View.AccessibilityDelegate(){
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ final long nodeId = AccessibilityNodeInfo.makeNodeId(
+ mTextView1.getAccessibilityViewId(),
+ AccessibilityNodeProvider.HOST_VIEW_ID);
+
+ // TextView1 is prefetched here after the RootFrameLayout is found. Now enqueue a
+ // same-client request for RootFrameLayout.
+ sendNodeRequestToController(nodeId, mMockClientCallback2,
+ mMockClient2InteractionId, FLAG_PREFETCH_DESCENDANTS_HYBRID);
+ }
+ });
+
+ // Client 1 request for RootFrameLayout.
+ sendNodeRequestToController(ROOT_NODE_ID, mMockClientCallback1,
+ mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS_HYBRID
+ | FLAG_PREFETCH_UNINTERRUPTIBLE);
+
+ mInstrumentation.waitForIdleSync();
+
+ // When the controller returns the nodes, it clears the sent list. Check immediately since
+ // the captor will be cleared.
+ doAnswer(invocation -> {
+ List<AccessibilityNodeInfo> nodes = invocation.getArgument(0);
+ assertEquals(ROOT_FRAME_LAYOUT_DESCRIPTION, nodes.get(0).getContentDescription());
+ assertEquals(TEXT_VIEW_2_DESCRIPTION, nodes.get(1).getContentDescription());
+ assertEquals(CHILD_FRAME_DESCRIPTION, nodes.get(2).getContentDescription());
+ assertEquals(TEXT_VIEW_3_DESCRIPTION, nodes.get(3).getContentDescription());
+ assertEquals(TEXT_VIEW_4_DESCRIPTION, nodes.get(4).getContentDescription());
+ return null;
+ }).when(mMockClientCallback1).setFindAccessibilityNodeInfosResult(
+ anyList(), eq(mMockClient1InteractionId));
+
+ verify(mMockClientCallback1, never())
+ .setPrefetchAccessibilityNodeInfoResult(anyList(), anyInt());
+
+ // Verify client 2 gets TextView1.
+ verify(mMockClientCallback2).setFindAccessibilityNodeInfoResult(
+ mFindInfoCaptor.capture(), eq(mMockClient2InteractionId));
+ AccessibilityNodeInfo infoSentToService = mFindInfoCaptor.getValue();
+ assertEquals(TEXT_VIEW_1_DESCRIPTION, infoSentToService.getContentDescription());
+ }
+
+ /**
+ * Tests a request for root node where a virtual hierarchy is prefetched.
+ *
+ * Layout
+ * mRootFrameLayout
+ * / | | \
+ * mTextView1 mTextView2 mChildFrameLayout *mTextView3*
+ * |
+ * *mTextView4*
+ * | \
+ * virtual view 1 virtual view 2
+ * |
+ * virtual view 3
+ * @throws RemoteException
+ */
+ @Test
+ public void testFindRootView_withVirtualView()
+ throws RemoteException {
+ mTextView4.setAccessibilityDelegate(new View.AccessibilityDelegate(){
+ @Override
+ public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) {
+ return new AccessibilityNodeProvider() {
+ @Override
+ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) {
+ if (virtualViewId == AccessibilityNodeProvider.HOST_VIEW_ID) {
+ AccessibilityNodeInfo node = new AccessibilityNodeInfo(host);
+ node.addChild(host, 1);
+ node.addChild(host, 2);
+ node.setContentDescription(TEXT_VIEW_4_DESCRIPTION);
+ return node;
+ } else if (virtualViewId == 1) {
+ AccessibilityNodeInfo node = new AccessibilityNodeInfo(
+ host, virtualViewId);
+ node.setParent(host);
+ node.setContentDescription(VIRTUAL_VIEW_1_DESCRIPTION);
+ node.addChild(host, 3);
+ return node;
+ } else if (virtualViewId == 2 || virtualViewId == 3) {
+ AccessibilityNodeInfo node = new AccessibilityNodeInfo(
+ host, virtualViewId);
+ node.setParent(host);
+ node.setContentDescription(virtualViewId == 2
+ ? VIRTUAL_VIEW_2_DESCRIPTION
+ : VIRTUAL_VIEW_3_DESCRIPTION);
+ return node;
+ }
+ return null;
+ }
+ };
+ }
+ });
+ // Request for our RootFrameLayout.
+ sendNodeRequestToController(ROOT_NODE_ID, mMockClientCallback1,
+ mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS_DEPTH_FIRST);
+ mInstrumentation.waitForIdleSync();
+
+ // Verify we get RootFrameLayout.
+ verify(mMockClientCallback1).setFindAccessibilityNodeInfoResult(
+ mFindInfoCaptor.capture(), eq(mMockClient1InteractionId));
+ AccessibilityNodeInfo infoSentToService = mFindInfoCaptor.getValue();
+ assertEquals(ROOT_FRAME_LAYOUT_DESCRIPTION, infoSentToService.getContentDescription());
+
+ verify(mMockClientCallback1).setPrefetchAccessibilityNodeInfoResult(
+ mPrefetchInfoListCaptor.capture(), eq(mMockClient1InteractionId));
+
+ List<AccessibilityNodeInfo> prefetchedNodes = mPrefetchInfoListCaptor.getValue();
+ assertEquals(8, prefetchedNodes.size());
+ assertEquals(TEXT_VIEW_1_DESCRIPTION, prefetchedNodes.get(0).getContentDescription());
+ assertEquals(TEXT_VIEW_2_DESCRIPTION, prefetchedNodes.get(1).getContentDescription());
+ assertEquals(CHILD_FRAME_DESCRIPTION, prefetchedNodes.get(2).getContentDescription());
+ assertEquals(TEXT_VIEW_4_DESCRIPTION, prefetchedNodes.get(3).getContentDescription());
+
+ assertEquals(VIRTUAL_VIEW_1_DESCRIPTION, prefetchedNodes.get(4).getContentDescription());
+ assertEquals(VIRTUAL_VIEW_3_DESCRIPTION, prefetchedNodes.get(5).getContentDescription());
+
+ assertEquals(VIRTUAL_VIEW_2_DESCRIPTION, prefetchedNodes.get(6).getContentDescription());
+ assertEquals(TEXT_VIEW_3_DESCRIPTION, prefetchedNodes.get(7).getContentDescription());
+
+
}
private void sendNodeRequestToController(long requestedNodeId,
@@ -536,9 +847,16 @@
}
private class TestFrameLayout extends FrameLayout {
+ private int mA11yId;
+ private String mContentDescription;
+ ArrayList<View> mChildren;
- TestFrameLayout(Context context) {
+ TestFrameLayout(Context context, int a11yId, String contentDescription,
+ ArrayList<View> children) {
super(context);
+ mA11yId = a11yId;
+ mContentDescription = contentDescription;
+ mChildren = children;
}
@Override
@@ -556,14 +874,15 @@
@Override
public int getAccessibilityViewId() {
// static id doesn't reset after tests so return the same one
- return 0;
+ return mA11yId;
}
@Override
public void addChildrenForAccessibility(ArrayList<View> outChildren) {
// ViewGroup#addChildrenForAccessbility sorting logic will switch these two
- outChildren.add(mTextView1);
- outChildren.add(mTextView2);
+ for (View view : mChildren) {
+ outChildren.add(view);
+ }
}
@Override
@@ -574,13 +893,17 @@
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
- info.setContentDescription(FRAME_LAYOUT_DESCRIPTION);
+ info.setContentDescription(mContentDescription);
}
}
private class TestTextView extends TextView {
- TestTextView(Context context) {
+ private int mA11yId;
+ private String mContentDescription;
+ TestTextView(Context context, int a11yId, String contentDescription) {
super(context);
+ mA11yId = a11yId;
+ mContentDescription = contentDescription;
}
@Override
@@ -595,7 +918,7 @@
@Override
public int getAccessibilityViewId() {
- return 1;
+ return mA11yId;
}
@Override
@@ -606,39 +929,7 @@
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
- info.setContentDescription(TEXT_VIEW_1_DESCRIPTION);
- }
- }
-
- private class TestTextView2 extends TextView {
- TestTextView2(Context context) {
- super(context);
- }
-
- @Override
- public int getWindowVisibility() {
- return VISIBLE;
- }
-
- @Override
- public boolean isShown() {
- return true;
- }
-
- @Override
- public int getAccessibilityViewId() {
- return 2;
- }
-
- @Override
- public boolean includeForAccessibility() {
- return true;
- }
-
- @Override
- public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
- super.onInitializeAccessibilityNodeInfo(info);
- info.setContentDescription(TEXT_VIEW_2_DESCRIPTION);
+ info.setContentDescription(mContentDescription);
}
}
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationProcessorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationProcessorTest.java
index c4040b4..3c2fbd9 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationProcessorTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationProcessorTest.java
@@ -27,6 +27,7 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -342,9 +343,58 @@
}
@Test
- public void setMagnificationConfig_controllingModeChangeAndAnimating_transitionConfigMode() {
+ public void setWindowModeConfig_fullScreenMode_transitionConfigMode() {
+ final int currentActivatedMode = MAGNIFICATION_MODE_FULLSCREEN;
+ final MagnificationConfig oldConfig = new MagnificationConfig.Builder()
+ .setMode(currentActivatedMode)
+ .setScale(TEST_SCALE)
+ .setCenterX(TEST_CENTER_X)
+ .setCenterY(TEST_CENTER_Y).build();
+ setMagnificationActivated(TEST_DISPLAY, oldConfig);
+ final MagnificationConfig targetConfig = new MagnificationConfig.Builder()
+ .setMode(MAGNIFICATION_MODE_WINDOW)
+ .setScale(TEST_SCALE)
+ .setCenterX(TEST_CENTER_X + 10)
+ .setCenterY(TEST_CENTER_Y + 10).build();
+
+ mMagnificationProcessor.setMagnificationConfig(TEST_DISPLAY, targetConfig, false,
+ SERVICE_ID);
+
+ verify(mMockMagnificationController).transitionMagnificationConfigMode(eq(TEST_DISPLAY),
+ eq(targetConfig), eq(false), eq(SERVICE_ID));
+ }
+
+ @Test
+ public void setConfigWithDefaultMode_fullScreenMode_expectedConfig() {
+ final MagnificationConfig oldConfig = new MagnificationConfig.Builder()
+ .setMode(MAGNIFICATION_MODE_FULLSCREEN)
+ .setScale(TEST_SCALE)
+ .setCenterX(TEST_CENTER_X)
+ .setCenterY(TEST_CENTER_Y).build();
+ setMagnificationActivated(TEST_DISPLAY, oldConfig);
+ final MagnificationConfig targetConfig = new MagnificationConfig.Builder()
+ .setScale(TEST_SCALE + 1)
+ .setCenterX(TEST_CENTER_X + 10)
+ .setCenterY(TEST_CENTER_Y + 10).build();
+
+ mMagnificationProcessor.setMagnificationConfig(TEST_DISPLAY, targetConfig, false,
+ SERVICE_ID);
+
+ verify(mMockMagnificationController, never()).transitionMagnificationConfigMode(
+ eq(TEST_DISPLAY), any(MagnificationConfig.class), eq(false), eq(SERVICE_ID));
+ final MagnificationConfig expectedConfig = new MagnificationConfig.Builder()
+ .setMode(MAGNIFICATION_MODE_FULLSCREEN)
+ .setScale(TEST_SCALE + 1)
+ .setCenterX(TEST_CENTER_X + 10)
+ .setCenterY(TEST_CENTER_Y + 10).build();
+ assertConfigEquals(expectedConfig,
+ mMagnificationProcessor.getMagnificationConfig(TEST_DISPLAY));
+ }
+
+ @Test
+ public void setWindowModeConfig_transitionToFullScreenModeWithAnimation_transitionConfigMode() {
final int currentActivatedMode = MAGNIFICATION_MODE_WINDOW;
- final int targetMode = MAGNIFICATION_MODE_FULLSCREEN;
+ final int targetMode = MAGNIFICATION_MODE_WINDOW;
final MagnificationConfig oldConfig = new MagnificationConfig.Builder()
.setMode(currentActivatedMode)
.setScale(TEST_SCALE)
@@ -356,17 +406,14 @@
.setScale(TEST_SCALE)
.setCenterX(TEST_CENTER_X + 10)
.setCenterY(TEST_CENTER_Y + 10).build();
-
// Has magnification animation running
when(mMockMagnificationController.hasDisableMagnificationCallback(TEST_DISPLAY)).thenReturn(
true);
- setMagnificationActivated(TEST_DISPLAY, newConfig);
- final MagnificationConfig result = mMagnificationProcessor.getMagnificationConfig(
- TEST_DISPLAY);
+ mMagnificationProcessor.setMagnificationConfig(TEST_DISPLAY, newConfig, false, SERVICE_ID);
+
verify(mMockMagnificationController).transitionMagnificationConfigMode(eq(TEST_DISPLAY),
eq(newConfig), anyBoolean(), anyInt());
- assertConfigEquals(newConfig, result);
}
private void setMagnificationActivated(int displayId, int configMode) {
@@ -383,7 +430,7 @@
MAGNIFICATION_MODE_WINDOW)).thenReturn(false);
mFullScreenMagnificationControllerStub.resetAndStubMethods();
mMockFullScreenMagnificationController.setScaleAndCenter(displayId, config.getScale(),
- config.getCenterX(), config.getCenterY(), true, SERVICE_ID);
+ config.getCenterX(), config.getCenterY(), false, SERVICE_ID);
} else if (config.getMode() == MAGNIFICATION_MODE_WINDOW) {
when(mMockMagnificationController.isActivated(displayId,
MAGNIFICATION_MODE_FULLSCREEN)).thenReturn(false);
@@ -429,7 +476,7 @@
};
doAnswer(enableMagnificationStubAnswer).when(
mScreenMagnificationController).setScaleAndCenter(eq(TEST_DISPLAY), anyFloat(),
- anyFloat(), anyFloat(), eq(true), eq(SERVICE_ID));
+ anyFloat(), anyFloat(), anyBoolean(), eq(SERVICE_ID));
Answer registerStubAnswer = invocation -> {
mIsRegistered = true;
@@ -444,6 +491,8 @@
};
doAnswer(unregisterStubAnswer).when(
mScreenMagnificationController).unregister(eq(TEST_DISPLAY));
+ doAnswer(unregisterStubAnswer).when(
+ mScreenMagnificationController).reset(eq(TEST_DISPLAY), anyBoolean());
}
public void resetAndStubMethods() {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
index 064b762..3fcce92 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
@@ -20,6 +20,7 @@
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
import static com.android.server.accessibility.AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID;
+import static com.android.server.wm.WindowManagerInternal.AccessibilityControllerInternal.UiChangesForAccessibilityCallbacks;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -32,9 +33,9 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -80,7 +81,6 @@
private static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY;
private static final int TEST_SERVICE_ID = 1;
- private static final Region MAGNIFICATION_REGION = new Region(0, 0, 500, 600);
private static final Rect TEST_RECT = new Rect(0, 50, 100, 51);
private static final float MAGNIFIED_CENTER_X = 100;
private static final float MAGNIFIED_CENTER_Y = 200;
@@ -109,7 +109,8 @@
private WindowMagnificationManager mWindowMagnificationManager;
private MockContentResolver mMockResolver;
private MagnificationController mMagnificationController;
- private FullScreenMagnificationControllerStubber mScreenMagnificationControllerStubber;
+ private final WindowMagnificationMgrCallbackDelegate mCallbackDelegate =
+ new WindowMagnificationMgrCallbackDelegate();
@Mock
private WindowManagerInternal mMockWindowManagerInternal;
@@ -141,17 +142,16 @@
mScaleProvider = spy(new MagnificationScaleProvider(mContext));
mWindowMagnificationManager = Mockito.spy(
new WindowMagnificationManager(mContext, globalLock,
- mock(WindowMagnificationManager.Callback.class), mTraceManager,
- mScaleProvider));
+ mCallbackDelegate, mTraceManager, mScaleProvider));
mMockConnection = new MockWindowMagnificationConnection(true);
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mScreenMagnificationControllerStubber = new FullScreenMagnificationControllerStubber(
- mScreenMagnificationController);
+ new FullScreenMagnificationControllerStubber(mScreenMagnificationController);
mMagnificationController = new MagnificationController(mService, globalLock, mContext,
mScreenMagnificationController, mWindowMagnificationManager, mScaleProvider);
mMagnificationController.setMagnificationCapabilities(
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL);
+ mCallbackDelegate.setDelegate(mMagnificationController);
}
@After
@@ -222,8 +222,10 @@
MODE_WINDOW,
mTransitionCallBack);
- mMockConnection.invokeCallbacks();
- verify(mWindowMagnificationManager).showMagnificationButton(eq(TEST_DISPLAY),
+ // The first time is triggered when window mode is activated, the second time is triggered
+ // when activating the window mode again. The third time is triggered when the transition is
+ // completed.
+ verify(mWindowMagnificationManager, times(3)).showMagnificationButton(eq(TEST_DISPLAY),
eq(MODE_WINDOW));
}
@@ -247,7 +249,8 @@
@Test
public void transitionToFullScreen_centerNotInTheBounds_magnifyBoundsCenter()
throws RemoteException {
- final Rect magnificationBounds = MAGNIFICATION_REGION.getBounds();
+ final Rect magnificationBounds =
+ FullScreenMagnificationControllerStubber.MAGNIFICATION_REGION.getBounds();
final PointF magnifiedCenter = new PointF(magnificationBounds.right + 100,
magnificationBounds.bottom + 100);
setMagnificationEnabled(MODE_WINDOW, magnifiedCenter.x, magnifiedCenter.y);
@@ -430,18 +433,21 @@
}
@Test
- public void onSourceBoundsChanged_notifyMagnificationChanged() {
- Rect rect = new Rect(0, 0, 100, 120);
- Region region = new Region(rect);
-
- mMagnificationController.onSourceBoundsChanged(TEST_DISPLAY, rect);
+ public void enableWindowMode_notifyMagnificationChanged() throws RemoteException {
+ setMagnificationEnabled(MODE_WINDOW);
final ArgumentCaptor<MagnificationConfig> configCaptor = ArgumentCaptor.forClass(
MagnificationConfig.class);
- verify(mService).notifyMagnificationChanged(eq(TEST_DISPLAY), eq(region),
+ final ArgumentCaptor<Region> regionCaptor = ArgumentCaptor.forClass(
+ Region.class);
+ verify(mService).notifyMagnificationChanged(eq(TEST_DISPLAY), regionCaptor.capture(),
configCaptor.capture());
- assertEquals(rect.exactCenterX(), configCaptor.getValue().getCenterX(), 0);
- assertEquals(rect.exactCenterY(), configCaptor.getValue().getCenterY(), 0);
+
+ final Rect actualRect = regionCaptor.getValue().getBounds();
+ final MagnificationConfig actualConfig = configCaptor.getValue();
+ assertEquals(actualRect.exactCenterX(), actualConfig.getCenterX(), 0);
+ assertEquals(actualRect.exactCenterY(), actualConfig.getCenterY(), 0);
+ assertEquals(DEFAULT_SCALE, actualConfig.getScale(), 0);
}
@Test
@@ -451,7 +457,8 @@
mMagnificationController.onAccessibilityActionPerformed(TEST_DISPLAY);
- verify(mWindowMagnificationManager).showMagnificationButton(eq(TEST_DISPLAY),
+ // The first time is triggered when window mode is activated.
+ verify(mWindowMagnificationManager, times(2)).showMagnificationButton(eq(TEST_DISPLAY),
eq(MODE_WINDOW));
}
@@ -464,7 +471,8 @@
mMagnificationController.onAccessibilityActionPerformed(TEST_DISPLAY);
- verify(mWindowMagnificationManager).removeMagnificationButton(eq(TEST_DISPLAY));
+ // The first time is triggered when window mode is activated.
+ verify(mWindowMagnificationManager, times(2)).removeMagnificationButton(eq(TEST_DISPLAY));
}
@Test
@@ -490,8 +498,7 @@
public void onRectangleOnScreenRequested_fullScreenIsActivated_fullScreenDispatchEvent() {
mMagnificationController.onFullScreenMagnificationActivationState(TEST_DISPLAY,
true);
- WindowManagerInternal.AccessibilityControllerInternal.UiChangesForAccessibilityCallbacks
- callbacks = getUiChangesForAccessibilityCallbacks();
+ UiChangesForAccessibilityCallbacks callbacks = getUiChangesForAccessibilityCallbacks();
callbacks.onRectangleOnScreenRequested(TEST_DISPLAY,
TEST_RECT.left, TEST_RECT.top, TEST_RECT.right, TEST_RECT.bottom);
@@ -508,8 +515,7 @@
true);
mMagnificationController.onFullScreenMagnificationActivationState(TEST_DISPLAY,
false);
- WindowManagerInternal.AccessibilityControllerInternal.UiChangesForAccessibilityCallbacks
- callbacks = getUiChangesForAccessibilityCallbacks();
+ UiChangesForAccessibilityCallbacks callbacks = getUiChangesForAccessibilityCallbacks();
callbacks.onRectangleOnScreenRequested(TEST_DISPLAY,
TEST_RECT.left, TEST_RECT.top, TEST_RECT.right, TEST_RECT.bottom);
@@ -522,8 +528,7 @@
@Test
public void onRectangleOnScreenRequested_NoneIsActivated_noneDispatchEvent() {
- WindowManagerInternal.AccessibilityControllerInternal.UiChangesForAccessibilityCallbacks
- callbacks = getUiChangesForAccessibilityCallbacks();
+ UiChangesForAccessibilityCallbacks callbacks = getUiChangesForAccessibilityCallbacks();
callbacks.onRectangleOnScreenRequested(TEST_DISPLAY,
TEST_RECT.left, TEST_RECT.top, TEST_RECT.right, TEST_RECT.bottom);
@@ -546,8 +551,7 @@
}
@Test
- public void
- onFullScreenMagnificationActivationState_fullScreenActivated_logFullScreenDuration() {
+ public void onFullScreenMagnificationActivationState_fullScreenEnabled_logFullScreenDuration() {
MagnificationController spyController = spy(mMagnificationController);
spyController.onFullScreenMagnificationActivationState(TEST_DISPLAY, true);
@@ -596,7 +600,8 @@
mMagnificationController.onTouchInteractionStart(TEST_DISPLAY, MODE_WINDOW);
- verify(mWindowMagnificationManager).showMagnificationButton(eq(TEST_DISPLAY),
+ // The first time is triggered when the window mode is activated.
+ verify(mWindowMagnificationManager, times(2)).showMagnificationButton(eq(TEST_DISPLAY),
eq(MODE_WINDOW));
}
@@ -607,7 +612,8 @@
mMagnificationController.onTouchInteractionEnd(TEST_DISPLAY, MODE_WINDOW);
- verify(mWindowMagnificationManager).showMagnificationButton(eq(TEST_DISPLAY),
+ // The first time is triggered when the window mode is activated.
+ verify(mWindowMagnificationManager, times(2)).showMagnificationButton(eq(TEST_DISPLAY),
eq(MODE_WINDOW));
}
@@ -639,12 +645,10 @@
}
@Test
- public void onWindowActivated_windowModeEnabledAndCapabilitiesAll_showMagnificationButton()
+ public void enableWindowMode_showMagnificationButton()
throws RemoteException {
setMagnificationEnabled(MODE_WINDOW);
- mMagnificationController.onWindowMagnificationActivationState(TEST_DISPLAY, true);
-
verify(mWindowMagnificationManager).showMagnificationButton(eq(TEST_DISPLAY),
eq(MODE_WINDOW));
}
@@ -661,18 +665,17 @@
}
@Test
- public void onWindowDeactivated_windowModeInactive_removeMagnificationButton()
+ public void disableWindowMode_windowModeInActive_removeMagnificationButton()
throws RemoteException {
setMagnificationEnabled(MODE_WINDOW);
- mWindowMagnificationManager.disableWindowMagnification(TEST_DISPLAY, false);
- mMagnificationController.onWindowMagnificationActivationState(TEST_DISPLAY, false);
+ mWindowMagnificationManager.disableWindowMagnification(TEST_DISPLAY, false);
verify(mWindowMagnificationManager).removeMagnificationButton(eq(TEST_DISPLAY));
}
@Test
- public void onFullScreenDeactivated_fullscreenModeInactive_removeMagnificationButton()
+ public void onFullScreenDeactivated_fullscreenModeInActive_removeMagnificationButton()
throws RemoteException {
setMagnificationEnabled(MODE_FULLSCREEN);
mScreenMagnificationController.setScaleAndCenter(TEST_DISPLAY,
@@ -685,7 +688,7 @@
}
@Test
- public void transitionToFullScreenMode_fullscreenModeActivated_showMagnificationButton()
+ public void transitionToFullScreenMode_fullscreenModeInActive_showMagnificationButton()
throws RemoteException {
setMagnificationEnabled(MODE_WINDOW);
@@ -698,7 +701,7 @@
}
@Test
- public void transitionToWindow_windowModeActivated_showMagnificationButton()
+ public void transitionToWindow_fullscreenModeInActive_showMagnificationButton()
throws RemoteException {
setMagnificationEnabled(MODE_FULLSCREEN);
@@ -709,7 +712,10 @@
mCallbackArgumentCaptor.capture());
mCallbackArgumentCaptor.getValue().onResult(true);
mMockConnection.invokeCallbacks();
- verify(mWindowMagnificationManager).showMagnificationButton(eq(TEST_DISPLAY),
+
+ // The first time is triggered when window mode is activated, the second time is triggered
+ // when the disable-magnification callback is triggered.
+ verify(mWindowMagnificationManager, times(2)).showMagnificationButton(eq(TEST_DISPLAY),
eq(MODE_WINDOW));
}
@@ -784,7 +790,6 @@
}
private void activateMagnifier(int mode, float centerX, float centerY) throws RemoteException {
- mScreenMagnificationControllerStubber.resetAndStubMethods();
final boolean windowMagnifying = mWindowMagnificationManager.isWindowMagnifierEnabled(
TEST_DISPLAY);
if (windowMagnifying) {
@@ -806,13 +811,20 @@
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, mode, CURRENT_USER_ID);
}
- private MagnificationConfig obtainMagnificationConfig(int mode) {
- return new MagnificationConfig.Builder().setMode(mode).setScale(DEFAULT_SCALE).setCenterX(
- MAGNIFIED_CENTER_X).setCenterY(MAGNIFIED_CENTER_Y).build();
+ private static MagnificationConfig obtainMagnificationConfig(int mode) {
+ return obtainMagnificationConfig(mode, true);
}
- private WindowManagerInternal.AccessibilityControllerInternal.UiChangesForAccessibilityCallbacks
- getUiChangesForAccessibilityCallbacks() {
+ private static MagnificationConfig obtainMagnificationConfig(int mode, boolean defaultScale) {
+ MagnificationConfig.Builder builder = new MagnificationConfig.Builder();
+ if (defaultScale) {
+ builder = builder.setScale(DEFAULT_SCALE);
+ }
+ return builder.setMode(mode).setCenterX(MAGNIFIED_CENTER_X)
+ .setCenterY(MAGNIFIED_CENTER_Y).build();
+ }
+
+ private UiChangesForAccessibilityCallbacks getUiChangesForAccessibilityCallbacks() {
ArgumentCaptor<WindowManagerInternal.AccessibilityControllerInternal
.UiChangesForAccessibilityCallbacks> captor = ArgumentCaptor.forClass(
WindowManagerInternal.AccessibilityControllerInternal
@@ -822,21 +834,65 @@
return captor.getValue();
}
+ private static class WindowMagnificationMgrCallbackDelegate implements
+ WindowMagnificationManager.Callback {
+ private WindowMagnificationManager.Callback mCallback;
+
+ public void setDelegate(WindowMagnificationManager.Callback callback) {
+ mCallback = callback;
+ }
+
+ @Override
+ public void onPerformScaleAction(int displayId, float scale) {
+ if (mCallback != null) {
+ mCallback.onPerformScaleAction(displayId, scale);
+ }
+ }
+
+ @Override
+ public void onAccessibilityActionPerformed(int displayId) {
+ if (mCallback != null) {
+ mCallback.onAccessibilityActionPerformed(displayId);
+ }
+ }
+
+ @Override
+ public void onWindowMagnificationActivationState(int displayId, boolean activated) {
+ if (mCallback != null) {
+ mCallback.onWindowMagnificationActivationState(displayId, activated);
+ }
+ }
+
+ @Override
+ public void onSourceBoundsChanged(int displayId, Rect bounds) {
+ if (mCallback != null) {
+ mCallback.onSourceBoundsChanged(displayId, bounds);
+ }
+ }
+
+ @Override
+ public void onChangeMagnificationMode(int displayId, int magnificationMode) {
+ if (mCallback != null) {
+ mCallback.onChangeMagnificationMode(displayId, magnificationMode);
+ }
+ }
+ }
+
/**
- * Stubs public methods to simulate the real beahviours.
+ * Stubs public methods to simulate the real behaviours.
*/
private static class FullScreenMagnificationControllerStubber {
+ private static final Region MAGNIFICATION_REGION = new Region(0, 0, 500, 600);
private final FullScreenMagnificationController mScreenMagnificationController;
private boolean mIsMagnifying = false;
private float mScale = 1.0f;
- private float mCenterX = 0;
- private float mCenterY = 0;
+ private float mCenterX = MAGNIFICATION_REGION.getBounds().exactCenterX();
+ private float mCenterY = MAGNIFICATION_REGION.getBounds().exactCenterY();
private int mServiceId = -1;
FullScreenMagnificationControllerStubber(
FullScreenMagnificationController screenMagnificationController) {
mScreenMagnificationController = screenMagnificationController;
- resetCenter();
stubMethods();
}
@@ -872,8 +928,7 @@
mCenterY = invocation.getArgument(3);
mServiceId = invocation.getArgument(5);
} else {
- mServiceId = -1;
- resetCenter();
+ reset();
}
return true;
};
@@ -886,26 +941,21 @@
anyFloat(), anyFloat(), anyFloat(), anyBoolean(), anyInt());
Answer resetStubAnswer = invocation -> {
- mScale = 1.0f;
- mIsMagnifying = false;
- mServiceId = -1;
- resetCenter();
+ reset();
return true;
};
doAnswer(resetStubAnswer).when(mScreenMagnificationController).reset(eq(TEST_DISPLAY),
- any());
+ any(MagnificationAnimationCallback.class));
doAnswer(resetStubAnswer).when(mScreenMagnificationController).reset(eq(TEST_DISPLAY),
anyBoolean());
}
- private void resetCenter() {
+ private void reset() {
+ mScale = 1.0f;
+ mIsMagnifying = false;
+ mServiceId = -1;
mCenterX = MAGNIFICATION_REGION.getBounds().exactCenterX();
mCenterY = MAGNIFICATION_REGION.getBounds().exactCenterY();
}
-
- public void resetAndStubMethods() {
- Mockito.reset(mScreenMagnificationController);
- stubMethods();
- }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
index 8da513b..0742c09 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
@@ -62,6 +62,7 @@
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
@@ -633,9 +634,15 @@
public void onWindowMagnificationActivationState_magnifierDisabled_notifyDeactivatedState() {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3.0f, NaN, NaN);
- mWindowMagnificationManager.disableWindowMagnification(TEST_DISPLAY, true);
+ mWindowMagnificationManager.disableWindowMagnification(TEST_DISPLAY, false);
verify(mMockCallback).onWindowMagnificationActivationState(TEST_DISPLAY, false);
+
+ Mockito.reset(mMockCallback);
+ mWindowMagnificationManager.disableWindowMagnification(TEST_DISPLAY, false);
+
+ verify(mMockCallback, never()).onWindowMagnificationActivationState(eq(TEST_DISPLAY),
+ anyBoolean());
}
private MotionEvent generatePointersDownEvent(PointF[] pointersLocation) {
diff --git a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
index e9b5b62..18e0f29 100644
--- a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
@@ -16,8 +16,23 @@
package com.android.server.am;
-import static org.junit.Assert.assertNull;
+import static android.app.ActivityManager.RESTRICTION_LEVEL_BACKGROUND_RESTRICTED;
+import static android.content.Intent.ACTION_BOOT_COMPLETED;
+import static android.content.Intent.ACTION_LOCKED_BOOT_COMPLETED;
+import static android.content.Intent.ACTION_TIME_CHANGED;
+import static com.android.server.am.BroadcastConstants.DEFER_BOOT_COMPLETED_BROADCAST_ALL;
+import static com.android.server.am.BroadcastConstants.DEFER_BOOT_COMPLETED_BROADCAST_BACKGROUND_RESTRICTED_ONLY;
+import static com.android.server.am.BroadcastConstants.DEFER_BOOT_COMPLETED_BROADCAST_NONE;
+import static com.android.server.am.BroadcastDispatcher.DeferredBootCompletedBroadcastPerUser;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+
+import android.app.ActivityManagerInternal;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
@@ -25,10 +40,14 @@
import android.os.Process;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
+import android.util.SparseArray;
import androidx.test.filters.SmallTest;
+import org.junit.Before;
import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.Collections;
@@ -44,6 +63,24 @@
@Presubmit
public class BroadcastRecordTest {
+ private static final int USER0 = UserHandle.USER_SYSTEM;
+ private static final int USER1 = USER0 + 1;
+ private static final int[] USER_LIST = new int[] {USER0, USER1};
+ private static final String PACKAGE1 = "pkg1";
+ private static final String PACKAGE2 = "pkg2";
+ private static final String PACKAGE3 = "pkg3";
+ private static final String PACKAGE4 = "pkg4";
+ private static final String[] PACKAGE_LIST = new String[] {PACKAGE1, PACKAGE2, PACKAGE3,
+ PACKAGE4};
+
+ @Mock
+ ActivityManagerInternal mActivityManagerInternal;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
@Test
public void testCleanupDisabledPackageReceivers() {
final int user0 = UserHandle.USER_SYSTEM;
@@ -61,39 +98,232 @@
// With given package:
// Send to all users, cleanup a package of all users.
- final BroadcastRecord recordAllAll = createBroadcastRecord(receiversM, UserHandle.USER_ALL);
+ final BroadcastRecord recordAllAll = createBroadcastRecord(receiversM, UserHandle.USER_ALL,
+ new Intent());
cleanupDisabledPackageReceivers(recordAllAll, pkgToCleanup, UserHandle.USER_ALL);
assertNull(verifyRemaining(recordAllAll, excludeReceivers(receiversM, pkgToCleanup, -1)));
// Send to all users, cleanup a package of one user.
- final BroadcastRecord recordAllOne = createBroadcastRecord(receiversM, UserHandle.USER_ALL);
+ final BroadcastRecord recordAllOne = createBroadcastRecord(receiversM, UserHandle.USER_ALL,
+ new Intent());
cleanupDisabledPackageReceivers(recordAllOne, pkgToCleanup, user0);
assertNull(verifyRemaining(recordAllOne,
excludeReceivers(receiversM, pkgToCleanup, user0)));
// Send to one user, cleanup a package of all users.
- final BroadcastRecord recordOneAll = createBroadcastRecord(receiversU0, user0);
+ final BroadcastRecord recordOneAll = createBroadcastRecord(receiversU0, user0,
+ new Intent());
cleanupDisabledPackageReceivers(recordOneAll, pkgToCleanup, UserHandle.USER_ALL);
assertNull(verifyRemaining(recordOneAll, excludeReceivers(receiversU0, pkgToCleanup, -1)));
// Send to one user, cleanup a package one user.
- final BroadcastRecord recordOneOne = createBroadcastRecord(receiversU0, user0);
+ final BroadcastRecord recordOneOne = createBroadcastRecord(receiversU0, user0,
+ new Intent());
cleanupDisabledPackageReceivers(recordOneOne, pkgToCleanup, user0);
assertNull(verifyRemaining(recordOneOne, excludeReceivers(receiversU0, pkgToCleanup, -1)));
// Without given package (e.g. stop user):
// Send to all users, cleanup one user.
- final BroadcastRecord recordAllM = createBroadcastRecord(receiversM, UserHandle.USER_ALL);
+ final BroadcastRecord recordAllM = createBroadcastRecord(receiversM, UserHandle.USER_ALL,
+ new Intent());
cleanupDisabledPackageReceivers(recordAllM, null /* packageName */, user1);
assertNull(verifyRemaining(recordAllM,
excludeReceivers(receiversM, null /* packageName */, user1)));
// Send to one user, cleanup one user.
- final BroadcastRecord recordU0 = createBroadcastRecord(receiversU0, user0);
+ final BroadcastRecord recordU0 = createBroadcastRecord(receiversU0, user0, new Intent());
cleanupDisabledPackageReceivers(recordU0, null /* packageName */, user0);
assertNull(verifyRemaining(recordU0, Collections.emptyList()));
}
+ // Test defer BOOT_COMPLETED and LOCKED_BOOT_COMPLETED broaddcasts.
+ @Test
+ public void testDeferBootCompletedBroadcast() {
+ testDeferBootCompletedBroadcast_defer_none(ACTION_BOOT_COMPLETED);
+ testDeferBootCompletedBroadcast_defer_all(ACTION_BOOT_COMPLETED);
+ testDeferBootCompletedBroadcast_defer_background_restricted_only(ACTION_BOOT_COMPLETED);
+ testDeferBootCompletedBroadcast_defer_none(ACTION_LOCKED_BOOT_COMPLETED);
+ testDeferBootCompletedBroadcast_defer_all(ACTION_LOCKED_BOOT_COMPLETED);
+ testDeferBootCompletedBroadcast_defer_background_restricted_only(
+ ACTION_LOCKED_BOOT_COMPLETED);
+ }
+
+ // non-BOOT_COMPLETED broadcast does not get deferred.
+ @Test
+ public void testNoDeferOtherBroadcast() {
+ // no split for non-BOOT_COMPLETED broadcasts.
+ final BroadcastRecord br = createBootCompletedBroadcastRecord(ACTION_TIME_CHANGED);
+ final int origReceiversSize = br.receivers.size();
+
+ SparseArray<BroadcastRecord> deferred = br.splitDeferredBootCompletedBroadcastLocked(
+ mActivityManagerInternal, DEFER_BOOT_COMPLETED_BROADCAST_ALL);
+ // No receivers get deferred.
+ assertEquals(0, deferred.size());
+ assertEquals(origReceiversSize, br.receivers.size());
+ }
+
+ private BroadcastRecord createBootCompletedBroadcastRecord(String action) {
+ final List<ResolveInfo> receivers = createReceiverInfos(PACKAGE_LIST, USER_LIST);
+ final BroadcastRecord br = createBroadcastRecord(receivers, UserHandle.USER_ALL,
+ new Intent(action));
+ assertEquals(PACKAGE_LIST.length * USER_LIST.length, br.receivers.size());
+ return br;
+ }
+
+ // Test type DEFER_BOOT_COMPLETED_BROADCAST_NONE, this type does not defer any receiver.
+ private void testDeferBootCompletedBroadcast_defer_none(String action) {
+ final BroadcastRecord br = createBootCompletedBroadcastRecord(action);
+ final int origReceiversSize = br.receivers.size();
+
+ SparseArray<BroadcastRecord> deferred = br.splitDeferredBootCompletedBroadcastLocked(
+ mActivityManagerInternal, DEFER_BOOT_COMPLETED_BROADCAST_NONE);
+ // No receivers get deferred.
+ assertEquals(0, deferred.size());
+ assertEquals(origReceiversSize, br.receivers.size());
+ }
+
+ // Test type DEFER_BOOT_COMPLETED_BROADCAST_ALL, this type defer all receivers.
+ private void testDeferBootCompletedBroadcast_defer_all(String action) {
+ final BroadcastRecord br = createBootCompletedBroadcastRecord(action);
+
+ SparseArray<BroadcastRecord> deferred = br.splitDeferredBootCompletedBroadcastLocked(
+ mActivityManagerInternal, DEFER_BOOT_COMPLETED_BROADCAST_ALL);
+ // original BroadcastRecord receivers list is empty now.
+ assertTrue(br.receivers.isEmpty());
+
+ assertEquals(PACKAGE_LIST.length * USER_LIST.length, deferred.size());
+ for (int i = 0; i < PACKAGE_LIST.length; i++) {
+ for (final int userId : USER_LIST) {
+ final int uid = UserHandle.getUid(userId, getAppId(i));
+ assertTrue(deferred.contains(uid));
+ assertEquals(1, deferred.get(uid).receivers.size());
+ final ResolveInfo info = (ResolveInfo) deferred.get(uid).receivers.get(0);
+ assertEquals(PACKAGE_LIST[i], info.activityInfo.applicationInfo.packageName);
+ assertEquals(uid, info.activityInfo.applicationInfo.uid);
+ }
+ }
+ }
+
+ // Test type DEFER_BOOT_COMPLETED_BROADCAST_BACKGROUND_RESTRICTED_ONLY,
+ // This type defers receiver whose app package is background restricted.
+ private void testDeferBootCompletedBroadcast_defer_background_restricted_only(String action) {
+ final BroadcastRecord br = createBootCompletedBroadcastRecord(action);
+ final int origReceiversSize = br.receivers.size();
+
+ // First half packages in PACKAGE_LIST, return BACKGROUND_RESTRICTED.
+ for (int i = 0; i < PACKAGE_LIST.length / 2; i++) {
+ for (int u = 0; u < USER_LIST.length; u++) {
+ final int uid = UserHandle.getUid(USER_LIST[u], getAppId(i));
+ doReturn(RESTRICTION_LEVEL_BACKGROUND_RESTRICTED).when(mActivityManagerInternal)
+ .getRestrictionLevel(eq(uid));
+ }
+ }
+
+ // the second half packages in PACKAGE_LIST, return not BACKGROUND_RESTRICTED.
+ for (int i = PACKAGE_LIST.length / 2; i < PACKAGE_LIST.length; i++) {
+ for (int u = 0; u < USER_LIST.length; u++) {
+ final int uid = UserHandle.getUid(USER_LIST[u], getAppId(i));
+ doReturn(RESTRICTION_LEVEL_BACKGROUND_RESTRICTED - 10).when(
+ mActivityManagerInternal).getRestrictionLevel(eq(uid));
+ }
+ }
+
+ SparseArray<BroadcastRecord> deferred = br.splitDeferredBootCompletedBroadcastLocked(
+ mActivityManagerInternal,
+ DEFER_BOOT_COMPLETED_BROADCAST_BACKGROUND_RESTRICTED_ONLY);
+ // original BroadcastRecord receivers list is half now.
+ assertEquals(origReceiversSize / 2, br.receivers.size());
+ assertEquals(origReceiversSize / 2, deferred.size());
+
+ for (int i = 0; i < PACKAGE_LIST.length / 2; i++) {
+ for (int u = 0; u < USER_LIST.length; u++) {
+ final int uid = UserHandle.getUid(USER_LIST[u], getAppId(i));
+ assertTrue(deferred.contains(uid));
+ assertEquals(1, deferred.get(uid).receivers.size());
+ final ResolveInfo info = (ResolveInfo) deferred.get(uid).receivers.get(0);
+ assertEquals(PACKAGE_LIST[i], info.activityInfo.applicationInfo.packageName);
+ assertEquals(uid, info.activityInfo.applicationInfo.uid);
+ }
+ }
+
+ for (int i = PACKAGE_LIST.length / 2; i < PACKAGE_LIST.length; i++) {
+ for (int u = 0; u < USER_LIST.length; u++) {
+ final int uid = UserHandle.getUid(USER_LIST[u], getAppId(i));
+ boolean found = false;
+ for (int r = 0; r < br.receivers.size(); r++) {
+ final ResolveInfo info = (ResolveInfo) br.receivers.get(r);
+ if (uid == info.activityInfo.applicationInfo.uid) {
+ found = true;
+ break;
+ }
+ }
+ assertTrue(found);
+ }
+ }
+ }
+
+ /**
+ * Test the class {@link BroadcastDispatcher#DeferredBootCompletedBroadcastPerUser}
+ */
+ @Test
+ public void testDeferBootCompletedBroadcast_dispatcher() {
+ testDeferBootCompletedBroadcast_dispatcher_internal(ACTION_LOCKED_BOOT_COMPLETED, false);
+ testDeferBootCompletedBroadcast_dispatcher_internal(ACTION_BOOT_COMPLETED, false);
+ testDeferBootCompletedBroadcast_dispatcher_internal(ACTION_LOCKED_BOOT_COMPLETED, true);
+ testDeferBootCompletedBroadcast_dispatcher_internal(ACTION_BOOT_COMPLETED, true);
+ }
+
+ private void testDeferBootCompletedBroadcast_dispatcher_internal(String action,
+ boolean isAllUidReady) {
+ final List<ResolveInfo> receivers = createReceiverInfos(PACKAGE_LIST, new int[] {USER0});
+ final BroadcastRecord br = createBroadcastRecord(receivers, USER0, new Intent(action));
+ assertEquals(PACKAGE_LIST.length, br.receivers.size());
+
+ SparseArray<BroadcastRecord> deferred = br.splitDeferredBootCompletedBroadcastLocked(
+ mActivityManagerInternal, DEFER_BOOT_COMPLETED_BROADCAST_ALL);
+ // original BroadcastRecord receivers list is empty now.
+ assertTrue(br.receivers.isEmpty());
+ assertEquals(PACKAGE_LIST.length, deferred.size());
+
+ DeferredBootCompletedBroadcastPerUser deferredPerUser =
+ new DeferredBootCompletedBroadcastPerUser(USER0);
+ deferredPerUser.enqueueBootCompletedBroadcasts(action, deferred);
+
+ if (action.equals(ACTION_LOCKED_BOOT_COMPLETED)) {
+ assertEquals(PACKAGE_LIST.length,
+ deferredPerUser.mDeferredLockedBootCompletedBroadcasts.size());
+ assertTrue(deferredPerUser.mLockedBootCompletedBroadcastReceived);
+ for (int i = 0; i < PACKAGE_LIST.length; i++) {
+ final int uid = UserHandle.getUid(USER0, getAppId(i));
+ if (!isAllUidReady) {
+ deferredPerUser.updateUidReady(uid);
+ }
+ BroadcastRecord d = deferredPerUser.dequeueDeferredBootCompletedBroadcast(
+ isAllUidReady);
+ final ResolveInfo info = (ResolveInfo) d.receivers.get(0);
+ assertEquals(PACKAGE_LIST[i], info.activityInfo.applicationInfo.packageName);
+ assertEquals(uid, info.activityInfo.applicationInfo.uid);
+ }
+ assertEquals(0, deferredPerUser.mUidReadyForLockedBootCompletedBroadcast.size());
+ } else if (action.equals(ACTION_BOOT_COMPLETED)) {
+ assertEquals(PACKAGE_LIST.length,
+ deferredPerUser.mDeferredBootCompletedBroadcasts.size());
+ assertTrue(deferredPerUser.mBootCompletedBroadcastReceived);
+ for (int i = 0; i < PACKAGE_LIST.length; i++) {
+ final int uid = UserHandle.getUid(USER0, getAppId(i));
+ if (!isAllUidReady) {
+ deferredPerUser.updateUidReady(uid);
+ }
+ BroadcastRecord d = deferredPerUser.dequeueDeferredBootCompletedBroadcast(
+ isAllUidReady);
+ final ResolveInfo info = (ResolveInfo) d.receivers.get(0);
+ assertEquals(PACKAGE_LIST[i], info.activityInfo.applicationInfo.packageName);
+ assertEquals(uid, info.activityInfo.applicationInfo.uid);
+ }
+ assertEquals(0, deferredPerUser.mUidReadyForBootCompletedBroadcast.size());
+ }
+ }
+
private static void cleanupDisabledPackageReceivers(BroadcastRecord record,
String packageName, int userId) {
record.cleanupDisabledPackageReceiversLocked(packageName, null /* filterByClasses */,
@@ -148,7 +378,7 @@
for (int i = 0; i < packages.length; i++) {
for (final int userId : userIds) {
receivers.add(createResolveInfo(packages[i],
- UserHandle.getUid(userId, Process.FIRST_APPLICATION_UID + i)));
+ UserHandle.getUid(userId, getAppId(i))));
}
}
return receivers;
@@ -172,10 +402,11 @@
return excludedList;
}
- private static BroadcastRecord createBroadcastRecord(List<ResolveInfo> receivers, int userId) {
+ private static BroadcastRecord createBroadcastRecord(List<ResolveInfo> receivers, int userId,
+ Intent intent) {
return new BroadcastRecord(
null /* queue */,
- new Intent(),
+ intent,
null /* callerApp */,
null /* callerPackage */,
null /* callerFeatureId */,
@@ -200,4 +431,8 @@
null /* activityStartsToken */,
false /* timeoutExempt */ );
}
+
+ private static int getAppId(int i) {
+ return Process.FIRST_APPLICATION_UID + i;
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index 69d8e89..b94b690 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -235,7 +235,8 @@
@Test
public void testAuthenticate_credentialAllowedButNotSetup_returnsNoDeviceCredential()
throws Exception {
- when(mTrustManager.isDeviceSecure(anyInt())).thenReturn(false);
+ when(mTrustManager.isDeviceSecure(anyInt(), anyInt()))
+ .thenReturn(false);
mBiometricService = new BiometricService(mContext, mInjector);
mBiometricService.onStart();
@@ -254,7 +255,8 @@
// When no biometrics are enrolled, but credentials are set up, status bar should be
// invoked right away with showAuthenticationDialog
- when(mTrustManager.isDeviceSecure(anyInt())).thenReturn(true);
+ when(mTrustManager.isDeviceSecure(anyInt(), anyInt()))
+ .thenReturn(true);
mBiometricService = new BiometricService(mContext, mInjector);
mBiometricService.onStart();
@@ -532,7 +534,8 @@
public void testAuthenticate_noBiometrics_credentialAllowed() throws Exception {
setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
when(mFaceAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(false);
- when(mTrustManager.isDeviceSecure(anyInt())).thenReturn(true);
+ when(mTrustManager.isDeviceSecure(anyInt(), anyInt()))
+ .thenReturn(true);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
true /* requireConfirmation */,
Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_WEAK);
@@ -601,7 +604,8 @@
public void testAuthenticate_no_Biometrics_noCredential() throws Exception {
setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
when(mFaceAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(false);
- when(mTrustManager.isDeviceSecure(anyInt())).thenReturn(false);
+ when(mTrustManager.isDeviceSecure(anyInt(), anyInt()))
+ .thenReturn(false);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
true /* requireConfirmation */,
@@ -872,7 +876,8 @@
@Test
public void testBiometricOrCredentialAuth_whenBiometricLockout_showsCredential()
throws Exception {
- when(mTrustManager.isDeviceSecure(anyInt())).thenReturn(true);
+ when(mTrustManager.isDeviceSecure(anyInt(), anyInt()))
+ .thenReturn(true);
setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG);
when(mFingerprintAuthenticator.getLockoutModeForUser(anyInt()))
.thenReturn(LockoutTracker.LOCKOUT_PERMANENT);
@@ -1168,13 +1173,15 @@
setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT, Authenticators.BIOMETRIC_WEAK);
// When only biometric is requested, and sensor is not strong enough
- when(mTrustManager.isDeviceSecure(anyInt())).thenReturn(false);
+ when(mTrustManager.isDeviceSecure(anyInt(), anyInt()))
+ .thenReturn(false);
int authenticators = Authenticators.BIOMETRIC_STRONG;
assertEquals(BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE,
invokeCanAuthenticate(mBiometricService, authenticators));
// When credential and biometric are requested, and sensor is not strong enough
- when(mTrustManager.isDeviceSecure(anyInt())).thenReturn(true);
+ when(mTrustManager.isDeviceSecure(anyInt(), anyInt()))
+ .thenReturn(true);
authenticators = Authenticators.BIOMETRIC_STRONG | Authenticators.DEVICE_CREDENTIAL;
assertEquals(BiometricManager.BIOMETRIC_SUCCESS,
invokeCanAuthenticate(mBiometricService, authenticators));
@@ -1186,12 +1193,14 @@
mBiometricService.onStart();
// Credential requested but not set up
- when(mTrustManager.isDeviceSecure(anyInt())).thenReturn(false);
+ when(mTrustManager.isDeviceSecure(anyInt(), anyInt()))
+ .thenReturn(false);
assertEquals(BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED,
invokeCanAuthenticate(mBiometricService, Authenticators.DEVICE_CREDENTIAL));
// Credential requested and set up
- when(mTrustManager.isDeviceSecure(anyInt())).thenReturn(true);
+ when(mTrustManager.isDeviceSecure(anyInt(), anyInt()))
+ .thenReturn(true);
assertEquals(BiometricManager.BIOMETRIC_SUCCESS,
invokeCanAuthenticate(mBiometricService, Authenticators.DEVICE_CREDENTIAL));
}
@@ -1199,7 +1208,8 @@
@Test
public void testCanAuthenticate_whenNoBiometricsEnrolled() throws Exception {
// With credential set up, test the following.
- when(mTrustManager.isDeviceSecure(anyInt())).thenReturn(true);
+ when(mTrustManager.isDeviceSecure(anyInt(), anyInt()))
+ .thenReturn(true);
setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG,
false /* enrolled */);
@@ -1218,7 +1228,8 @@
public void testCanAuthenticate_whenBiometricsNotEnabledForApps() throws Exception {
setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
when(mBiometricService.mSettingObserver.getEnabledForApps(anyInt())).thenReturn(false);
- when(mTrustManager.isDeviceSecure(anyInt())).thenReturn(true);
+ when(mTrustManager.isDeviceSecure(anyInt(), anyInt()))
+ .thenReturn(true);
// When only biometric is requested
int authenticators = Authenticators.BIOMETRIC_STRONG;
@@ -1247,7 +1258,8 @@
invokeCanAuthenticate(mBiometricService, authenticators));
// When credential and biometric are requested, and credential is set up
- when(mTrustManager.isDeviceSecure(anyInt())).thenReturn(true);
+ when(mTrustManager.isDeviceSecure(anyInt(), anyInt()))
+ .thenReturn(true);
assertEquals(BiometricManager.BIOMETRIC_SUCCESS,
invokeCanAuthenticate(mBiometricService, authenticators));
}
@@ -1394,7 +1406,8 @@
// Requesting strong and credential, when credential is setup
resetReceivers();
authenticators = Authenticators.BIOMETRIC_STRONG | Authenticators.DEVICE_CREDENTIAL;
- when(mTrustManager.isDeviceSecure(anyInt())).thenReturn(true);
+ when(mTrustManager.isDeviceSecure(anyInt(), anyInt()))
+ .thenReturn(true);
assertEquals(BiometricManager.BIOMETRIC_SUCCESS,
invokeCanAuthenticate(mBiometricService, authenticators));
requestId = invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
@@ -1527,7 +1540,8 @@
public void testWorkAuthentication_fingerprintFailsIfDisabledByDevicePolicyManager()
throws Exception {
setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG);
- when(mTrustManager.isDeviceSecure(anyInt())).thenReturn(true);
+ when(mTrustManager.isDeviceSecure(anyInt(), anyInt()))
+ .thenReturn(true);
when(mDevicePolicyManager
.getKeyguardDisabledFeatures(any() /* admin */, anyInt() /* userHandle */))
.thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java
index 5746f6f..e6acc90 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java
@@ -88,27 +88,27 @@
}
@Test
- public void testIsAoD() throws RemoteException {
+ public void testIsAod() throws RemoteException {
mListener.onDozeChanged(true);
- assertThat(mProvider.isAoD()).isTrue();
+ assertThat(mProvider.isAod()).isTrue();
mListener.onDozeChanged(false);
- assertThat(mProvider.isAoD()).isFalse();
+ assertThat(mProvider.isAod()).isFalse();
when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(false);
mListener.onDozeChanged(true);
- assertThat(mProvider.isAoD()).isFalse();
+ assertThat(mProvider.isAod()).isFalse();
mListener.onDozeChanged(false);
- assertThat(mProvider.isAoD()).isFalse();
+ assertThat(mProvider.isAod()).isFalse();
}
@Test
- public void testSubscribesToAoD() throws RemoteException {
+ public void testSubscribesToAod() throws RemoteException {
final List<Boolean> expected = ImmutableList.of(true, false, true, true, false);
final List<Boolean> actual = new ArrayList<>();
mProvider.subscribe(mOpContext, ctx -> {
assertThat(ctx).isSameInstanceAs(mOpContext);
- actual.add(ctx.isAoD);
+ actual.add(ctx.isAod);
});
for (boolean v : expected) {
@@ -178,7 +178,7 @@
assertThat(context).isSameInstanceAs(mOpContext);
assertThat(mOpContext.id).isEqualTo(0);
assertThat(mOpContext.reason).isEqualTo(OperationReason.UNKNOWN);
- assertThat(mOpContext.isAoD).isEqualTo(false);
+ assertThat(mOpContext.isAod).isEqualTo(false);
assertThat(mOpContext.isCrypto).isEqualTo(false);
for (int type : List.of(StatusBarManager.SESSION_BIOMETRIC_PROMPT,
@@ -192,7 +192,7 @@
assertThat(context).isSameInstanceAs(mOpContext);
assertThat(mOpContext.id).isEqualTo(id);
assertThat(mOpContext.reason).isEqualTo(reason(type));
- assertThat(mOpContext.isAoD).isEqualTo(aod);
+ assertThat(mOpContext.isAod).isEqualTo(aod);
assertThat(mOpContext.isCrypto).isEqualTo(false);
mSessionListener.onSessionEnded(type, InstanceId.fakeInstanceId(id));
@@ -202,7 +202,7 @@
assertThat(context).isSameInstanceAs(mOpContext);
assertThat(mOpContext.id).isEqualTo(0);
assertThat(mOpContext.reason).isEqualTo(OperationReason.UNKNOWN);
- assertThat(mOpContext.isAoD).isEqualTo(false);
+ assertThat(mOpContext.isAod).isEqualTo(false);
assertThat(mOpContext.isCrypto).isEqualTo(false);
}
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
index 3b4aece..2ae2854 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
@@ -16,6 +16,7 @@
package com.android.server.companion.virtual;
+import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.mockito.ArgumentMatchers.any;
@@ -39,6 +40,7 @@
import android.companion.AssociationInfo;
import android.companion.virtual.IVirtualDeviceActivityListener;
import android.companion.virtual.VirtualDeviceParams;
+import android.companion.virtual.audio.IAudioSessionCallback;
import android.content.Context;
import android.content.ContextWrapper;
import android.graphics.Point;
@@ -111,6 +113,8 @@
@Mock
IThermalService mIThermalServiceMock;
private PowerManager mPowerManager;
+ @Mock
+ private IAudioSessionCallback mCallback;
@Before
public void setUp() {
@@ -250,6 +254,12 @@
}
@Test
+ public void onAudioSessionStarting_noDisplay_failsSecurityException() {
+ assertThrows(SecurityException.class,
+ () -> mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mCallback));
+ }
+
+ @Test
public void createVirtualKeyboard_noPermission_failsSecurityException() {
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID);
doCallRealMethod().when(mContext).enforceCallingOrSelfPermission(
@@ -283,6 +293,22 @@
}
@Test
+ public void onAudioSessionStarting_noPermission_failsSecurityException() {
+ mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID);
+ doCallRealMethod().when(mContext).enforceCallingOrSelfPermission(
+ eq(Manifest.permission.CREATE_VIRTUAL_DEVICE), anyString());
+ assertThrows(SecurityException.class,
+ () -> mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mCallback));
+ }
+
+ @Test
+ public void onAudioSessionEnded_noPermission_failsSecurityException() {
+ doCallRealMethod().when(mContext).enforceCallingOrSelfPermission(
+ eq(Manifest.permission.CREATE_VIRTUAL_DEVICE), anyString());
+ assertThrows(SecurityException.class, () -> mDeviceImpl.onAudioSessionEnded());
+ }
+
+ @Test
public void createVirtualKeyboard_hasDisplay_obtainFileDescriptor() {
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID);
mDeviceImpl.createVirtualKeyboard(DISPLAY_ID, DEVICE_NAME, VENDOR_ID, PRODUCT_ID,
@@ -316,6 +342,25 @@
}
@Test
+ public void onAudioSessionStarting_hasVirtualAudioController() {
+ mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID);
+
+ mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mCallback);
+
+ assertThat(mDeviceImpl.getVirtualAudioControllerForTesting()).isNotNull();
+ }
+
+ @Test
+ public void onAudioSessionEnded_noVirtualAudioController() {
+ mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID);
+ mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mCallback);
+
+ mDeviceImpl.onAudioSessionEnded();
+
+ assertThat(mDeviceImpl.getVirtualAudioControllerForTesting()).isNull();
+ }
+
+ @Test
public void sendKeyEvent_noFd() {
assertThrows(
IllegalArgumentException.class,
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
new file mode 100644
index 0000000..3160272
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
@@ -0,0 +1,202 @@
+/*
+ * 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.companion.virtual.audio;
+
+import static android.media.AudioAttributes.FLAG_SECURE;
+import static android.media.AudioPlaybackConfiguration.PLAYER_STATE_STARTED;
+import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.companion.virtual.audio.IAudioSessionCallback;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.media.AudioPlaybackConfiguration;
+import android.media.AudioRecordingConfiguration;
+import android.media.MediaRecorder;
+import android.media.PlayerBase;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.util.ArraySet;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.companion.virtual.GenericWindowPolicyController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class VirtualAudioControllerTest {
+ private static final int APP1_UID = 100;
+ private static final int APP2_UID = 200;
+
+ private Context mContext;
+ private VirtualAudioController mVirtualAudioController;
+ private GenericWindowPolicyController mGenericWindowPolicyController;
+ @Mock IAudioSessionCallback mCallback;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = Mockito.spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
+ mVirtualAudioController = new VirtualAudioController(mContext);
+ mGenericWindowPolicyController = new GenericWindowPolicyController(
+ FLAG_SECURE,
+ SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
+ /* allowedUsers= */ new ArraySet<>(),
+ /* allowedActivities= */ new ArraySet<>(),
+ /* blockedActivities= */ new ArraySet<>(),
+ /* activityListener= */null,
+ /* activityBlockedCallback= */ null);
+ }
+
+ @Test
+ public void startListening_receivesCallback() throws RemoteException {
+ ArraySet<Integer> runningUids = new ArraySet<>();
+ runningUids.add(APP1_UID);
+ int[] appUids = new int[] {APP1_UID};
+
+ mVirtualAudioController.startListening(mGenericWindowPolicyController, mCallback);
+
+ mGenericWindowPolicyController.onRunningAppsChanged(runningUids);
+ verify(mCallback).onAppsNeedingAudioRoutingChanged(appUids);
+ }
+
+ @Test
+ public void stopListening_removesCallback() throws RemoteException {
+ ArraySet<Integer> runningUids = new ArraySet<>();
+ runningUids.add(APP1_UID);
+ int[] appUids = new int[] {APP1_UID};
+ mVirtualAudioController.startListening(mGenericWindowPolicyController, mCallback);
+
+ mVirtualAudioController.stopListening();
+
+ mGenericWindowPolicyController.onRunningAppsChanged(runningUids);
+ verify(mCallback, never()).onAppsNeedingAudioRoutingChanged(appUids);
+ }
+
+ @Test
+ public void onRunningAppsChanged_notifiesAudioRoutingModified() throws RemoteException {
+ mVirtualAudioController.startListening(mGenericWindowPolicyController, mCallback);
+
+ ArraySet<Integer> runningUids = new ArraySet<>();
+ runningUids.add(APP1_UID);
+ mVirtualAudioController.onRunningAppsChanged(runningUids);
+
+ int[] appUids = new int[] {APP1_UID};
+ verify(mCallback).onAppsNeedingAudioRoutingChanged(appUids);
+ }
+
+ @Test
+ public void onRunningAppsChanged_audioIsPlaying_doesNothing() throws RemoteException {
+ mVirtualAudioController.startListening(mGenericWindowPolicyController, mCallback);
+ mVirtualAudioController.addPlayingAppsForTesting(APP2_UID);
+
+ ArraySet<Integer> runningUids = new ArraySet<>();
+ runningUids.add(APP1_UID);
+ mVirtualAudioController.onRunningAppsChanged(runningUids);
+
+ int[] appUids = new int[]{APP1_UID};
+ verify(mCallback, never()).onAppsNeedingAudioRoutingChanged(appUids);
+ }
+
+ @Test
+ public void onRunningAppsChanged_lastPlayingAppRemoved_delaysReroutingAudio() {
+ ArraySet<Integer> runningUids = new ArraySet<>();
+ runningUids.add(APP1_UID);
+ runningUids.add(APP2_UID);
+ mVirtualAudioController.onRunningAppsChanged(runningUids);
+ mVirtualAudioController.addPlayingAppsForTesting(APP2_UID);
+
+ ArraySet<Integer> appUids = new ArraySet<>();
+ appUids.add(APP1_UID);
+ mVirtualAudioController.onRunningAppsChanged(appUids);
+
+ assertThat(mVirtualAudioController.hasPendingRunnable()).isTrue();
+ }
+
+ @Test
+ public void onPlaybackConfigChanged_sendsCallback() throws RemoteException {
+ mVirtualAudioController.startListening(mGenericWindowPolicyController, mCallback);
+ ArraySet<Integer> runningUids = new ArraySet<>();
+ runningUids.add(APP1_UID);
+ mVirtualAudioController.onRunningAppsChanged(runningUids);
+ List<AudioPlaybackConfiguration> configs = createPlaybackConfigurations(runningUids);
+
+ mVirtualAudioController.onPlaybackConfigChanged(configs);
+
+ verify(mCallback).onPlaybackConfigChanged(configs);
+ }
+
+ @Test
+ public void onRecordingConfigChanged_sendsCallback() throws RemoteException {
+ mVirtualAudioController.startListening(mGenericWindowPolicyController, mCallback);
+ ArraySet<Integer> runningUids = new ArraySet<>();
+ runningUids.add(APP1_UID);
+ mVirtualAudioController.onRunningAppsChanged(runningUids);
+ List<AudioRecordingConfiguration> configs = createRecordingConfigurations(runningUids);
+
+ mVirtualAudioController.onRecordingConfigChanged(configs);
+
+ verify(mCallback).onRecordingConfigChanged(configs);
+ }
+
+ private List<AudioPlaybackConfiguration> createPlaybackConfigurations(
+ ArraySet<Integer> appUids) {
+ List<AudioPlaybackConfiguration> configs = new ArrayList<>();
+ for (int appUid : appUids) {
+ PlayerBase.PlayerIdCard playerIdCard =
+ PlayerBase.PlayerIdCard.CREATOR.createFromParcel(Parcel.obtain());
+ AudioPlaybackConfiguration audioPlaybackConfiguration =
+ new AudioPlaybackConfiguration(
+ playerIdCard, /* piid= */ 1000, appUid, /* pid= */ 1000);
+ audioPlaybackConfiguration.handleStateEvent(PLAYER_STATE_STARTED, /* deviceId= */1);
+ configs.add(audioPlaybackConfiguration);
+ }
+ return configs;
+ }
+
+ private List<AudioRecordingConfiguration> createRecordingConfigurations(
+ ArraySet<Integer> appUids) {
+ List<AudioRecordingConfiguration> configs = new ArrayList<>();
+ for (int appUid : appUids) {
+ AudioRecordingConfiguration audioRecordingConfiguration =
+ new AudioRecordingConfiguration(
+ /* uid= */ appUid,
+ /* session= */ 1000,
+ MediaRecorder.AudioSource.MIC,
+ /* clientFormat= */ null,
+ /* devFormat= */ null,
+ /* patchHandle= */ 1000,
+ "com.android.example");
+ configs.add(audioRecordingConfiguration);
+ }
+ return configs;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 48e2122..fe110e5 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -55,6 +55,7 @@
import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback;
import static com.android.server.devicepolicy.DevicePolicyManagerService.ACTION_PROFILE_OFF_DEADLINE;
import static com.android.server.devicepolicy.DevicePolicyManagerService.ACTION_TURN_PROFILE_ON_NOTIFICATION;
@@ -997,7 +998,8 @@
addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
// Change the parent user's password.
- dpm.reportPasswordChanged(UserHandle.USER_SYSTEM);
+ dpm.reportPasswordChanged(new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD),
+ UserHandle.USER_SYSTEM);
// The managed profile owner should receive this broadcast.
final Intent intent = new Intent(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED);
@@ -1036,7 +1038,8 @@
addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
// Change the profile's password.
- dpm.reportPasswordChanged(MANAGED_PROFILE_USER_ID);
+ dpm.reportPasswordChanged(new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD),
+ MANAGED_PROFILE_USER_ID);
// Both the device owner and the managed profile owner should receive this broadcast.
final Intent intent = new Intent(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED);
@@ -5531,7 +5534,7 @@
reset(mContext.spiedContext);
// This should be ignored, as there is no lock screen.
- dpm.reportPasswordChanged(userHandle);
+ dpm.reportPasswordChanged(new PasswordMetrics(CREDENTIAL_TYPE_NONE), userHandle);
// No broadcast should be sent.
verify(mContext.spiedContext, times(0)).sendBroadcastAsUser(
@@ -5904,7 +5907,7 @@
when(getServices().lockSettingsInternal.getUserPasswordMetrics(userHandle))
.thenReturn(passwordMetrics);
- dpm.reportPasswordChanged(userHandle);
+ dpm.reportPasswordChanged(passwordMetrics, userHandle);
verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
MockUtils.checkIntentAction(
diff --git a/services/tests/servicestests/src/com/android/server/dreams/DreamServiceTest.java b/services/tests/servicestests/src/com/android/server/dreams/DreamServiceTest.java
new file mode 100644
index 0000000..74d2e0f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/dreams/DreamServiceTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.dreams;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.service.dreams.DreamService;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DreamServiceTest {
+ @Test
+ public void testMetadataParsing() throws PackageManager.NameNotFoundException {
+ final String testPackageName = "com.android.frameworks.servicestests";
+ final String testDreamClassName = "com.android.server.dreams.TestDreamService";
+ final String testSettingsActivity = "com.android.server.dreams/.TestDreamSettingsActivity";
+
+ final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+ final ServiceInfo si = context.getPackageManager().getServiceInfo(
+ new ComponentName(testPackageName, testDreamClassName),
+ PackageManager.ComponentInfoFlags.of(PackageManager.GET_META_DATA));
+ final DreamService.DreamMetadata metadata = DreamService.getDreamMetadata(context, si);
+
+ assertEquals(0, metadata.settingsActivity.compareTo(
+ ComponentName.unflattenFromString(testSettingsActivity)));
+ assertFalse(metadata.showComplications);
+ }
+}
diff --git a/core/java/android/app/ambientcontext/AmbientContextEventResponse.aidl b/services/tests/servicestests/src/com/android/server/dreams/TestDreamService.java
similarity index 68%
copy from core/java/android/app/ambientcontext/AmbientContextEventResponse.aidl
copy to services/tests/servicestests/src/com/android/server/dreams/TestDreamService.java
index 4dc6466..3c99a98 100644
--- a/core/java/android/app/ambientcontext/AmbientContextEventResponse.aidl
+++ b/services/tests/servicestests/src/com/android/server/dreams/TestDreamService.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 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,12 @@
* limitations under the License.
*/
-package android.app.ambientcontext;
+package com.android.server.dreams;
-parcelable AmbientContextEventResponse;
\ No newline at end of file
+import android.service.dreams.DreamService;
+
+/**
+ * Dream service implementation for unit testing.
+ */
+public class TestDreamService extends DreamService {
+}
diff --git a/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java b/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java
index f26e094..096c80b 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java
@@ -142,6 +142,7 @@
new AppInstallMetadata.Builder()
.setPackageName(packageName)
.setAppCertificates(Collections.singletonList(packageCert))
+ .setAppCertificateLineage(Collections.singletonList(packageCert))
.setVersionCode(version)
.setInstallerName("abc")
.setInstallerCertificates(Collections.singletonList("abc"))
@@ -183,6 +184,8 @@
new AppInstallMetadata.Builder()
.setPackageName(installedPackageName)
.setAppCertificates(Collections.singletonList(installedAppCertificate))
+ .setAppCertificateLineage(
+ Collections.singletonList(installedAppCertificate))
.setVersionCode(250)
.setInstallerName("abc")
.setInstallerCertificates(Collections.singletonList("abc"))
diff --git a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java
index 441cd4b..1c860ca 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java
@@ -183,6 +183,7 @@
return new AppInstallMetadata.Builder()
.setPackageName("abc")
.setAppCertificates(Collections.singletonList("abc"))
+ .setAppCertificateLineage(Collections.singletonList("abc"))
.setInstallerCertificates(Collections.singletonList("abc"))
.setInstallerName("abc")
.setVersionCode(-1)
diff --git a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java
index b271a77..5089f74 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java
@@ -49,6 +49,7 @@
new AppInstallMetadata.Builder()
.setPackageName(PACKAGE_NAME_1)
.setAppCertificates(Collections.singletonList(APP_CERTIFICATE))
+ .setAppCertificateLineage(Collections.singletonList(APP_CERTIFICATE))
.setVersionCode(2)
.build();
diff --git a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java
index 415e635..370bd80 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java
@@ -54,6 +54,7 @@
new AppInstallMetadata.Builder()
.setPackageName("ddd")
.setAppCertificates(Collections.singletonList("777"))
+ .setAppCertificateLineage(Collections.singletonList("777"))
.build();
List<RuleIndexRange> resultingIndexes =
@@ -76,6 +77,7 @@
new AppInstallMetadata.Builder()
.setPackageName("ddd")
.setAppCertificates(Arrays.asList("777", "999"))
+ .setAppCertificateLineage(Arrays.asList("777", "999"))
.build();
List<RuleIndexRange> resultingIndexes =
@@ -99,6 +101,7 @@
new AppInstallMetadata.Builder()
.setPackageName("bbb")
.setAppCertificates(Collections.singletonList("999"))
+ .setAppCertificateLineage(Collections.singletonList("999"))
.build();
List<RuleIndexRange> resultingIndexes =
@@ -121,6 +124,7 @@
new AppInstallMetadata.Builder()
.setPackageName("ccc")
.setAppCertificates(Collections.singletonList("444"))
+ .setAppCertificateLineage(Collections.singletonList("444"))
.build();
List<RuleIndexRange> resultingIndexes =
@@ -153,6 +157,7 @@
new AppInstallMetadata.Builder()
.setPackageName("ccc")
.setAppCertificates(Collections.singletonList("444"))
+ .setAppCertificateLineage(Collections.singletonList("444"))
.build();
List<RuleIndexRange> resultingIndexes =
diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java
index b878779..9ed2e88 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java
@@ -875,6 +875,11 @@
}
@Override
+ public boolean isAppCertificateLineageFormula() {
+ return false;
+ }
+
+ @Override
public boolean isInstallerFormula() {
return false;
}
diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java
index ea9e6ff..6dccdf5 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java
@@ -305,6 +305,11 @@
}
@Override
+ public boolean isAppCertificateLineageFormula() {
+ return false;
+ }
+
+ @Override
public boolean isInstallerFormula() {
return false;
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
index 67d6929..e7f4d3d 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
@@ -34,6 +34,7 @@
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
+import android.app.PropertyInvalidatedCache;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.service.gatekeeper.GateKeeperResponse;
@@ -47,6 +48,7 @@
import com.android.server.locksettings.FakeGateKeeperService.VerifyHandle;
import com.android.server.locksettings.LockSettingsStorage.CredentialHash;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -57,6 +59,11 @@
@Presubmit
@RunWith(AndroidJUnit4.class)
public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
+ @Before
+ public void disableProcessCaches() {
+ PropertyInvalidatedCache.disableForTestMode();
+ }
+
@Test
public void testCreatePasswordPrimaryUser() throws RemoteException {
testCreateCredential(PRIMARY_USER_ID, newPassword("password"));
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java
index 9c0239b..c2f94e2 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java
@@ -24,6 +24,7 @@
import static org.junit.Assert.assertEquals;
+import android.app.PropertyInvalidatedCache;
import android.app.admin.DevicePolicyManager;
import androidx.test.runner.AndroidJUnit4;
@@ -46,6 +47,11 @@
mSettings.setDeviceProvisioned(false);
}
+ @Before
+ public void disableProcessCaches() {
+ PropertyInvalidatedCache.disableForTestMode();
+ }
+
@Test
public void testFrpCredential_setPin() {
mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index c0a38b8..eae9ee7f 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -36,6 +36,7 @@
import static org.mockito.Mockito.when;
import android.app.admin.PasswordMetrics;
+import android.app.PropertyInvalidatedCache;
import android.os.RemoteException;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
@@ -49,6 +50,7 @@
import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationToken;
import com.android.server.locksettings.SyntheticPasswordManager.PasswordData;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -68,6 +70,11 @@
public static final byte[] PAYLOAD = new byte[] {1, 2, -1, -2, 55};
public static final byte[] PAYLOAD2 = new byte[] {2, 3, -2, -3, 44, 1};
+ @Before
+ public void disableProcessCaches() {
+ PropertyInvalidatedCache.disableForTestMode();
+ }
+
@Test
public void testPasswordBasedSyntheticPassword() throws RemoteException {
final int USER_ID = 10;
@@ -250,7 +257,7 @@
flushHandlerTasks();
final PasswordMetrics metric = PasswordMetrics.computeForCredential(pattern);
assertEquals(metric, mService.getUserPasswordMetrics(PRIMARY_USER_ID));
- verify(mDevicePolicyManager).reportPasswordChanged(PRIMARY_USER_ID);
+ verify(mDevicePolicyManager).reportPasswordChanged(metric, PRIMARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
pattern, PRIMARY_USER_ID, 0 /* flags */).getResponseCode());
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 a7b045f..af8ac6f 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -23,11 +23,13 @@
import static android.net.ConnectivityManager.BLOCKED_REASON_APP_STANDBY;
import static android.net.ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER;
import static android.net.ConnectivityManager.BLOCKED_REASON_DOZE;
+import static android.net.ConnectivityManager.BLOCKED_REASON_LOW_POWER_STANDBY;
import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_WIFI;
-import static android.net.INetd.FIREWALL_CHAIN_RESTRICTED;
import static android.net.INetd.FIREWALL_RULE_ALLOW;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
@@ -38,8 +40,10 @@
import static android.net.NetworkPolicyManager.ALLOWED_METERED_REASON_FOREGROUND;
import static android.net.NetworkPolicyManager.ALLOWED_METERED_REASON_SYSTEM;
import static android.net.NetworkPolicyManager.ALLOWED_REASON_FOREGROUND;
+import static android.net.NetworkPolicyManager.ALLOWED_REASON_LOW_POWER_STANDBY_ALLOWLIST;
import static android.net.NetworkPolicyManager.ALLOWED_REASON_NONE;
import static android.net.NetworkPolicyManager.ALLOWED_REASON_SYSTEM;
+import static android.net.NetworkPolicyManager.ALLOWED_REASON_TOP;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.POLICY_NONE;
@@ -200,6 +204,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
@@ -504,6 +509,7 @@
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());
@@ -1876,55 +1882,99 @@
}
@Test
+ public void testLowPowerStandbyAllowlist() throws Exception {
+ callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_TOP, 0);
+ callOnUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0);
+ callOnUidStateChanged(UID_C, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0);
+ expectHasInternetPermission(UID_A, true);
+ expectHasInternetPermission(UID_B, true);
+ expectHasInternetPermission(UID_C, true);
+
+ final NetworkPolicyManagerInternal internal = LocalServices
+ .getService(NetworkPolicyManagerInternal.class);
+
+ Map<Integer, Integer> firewallUidRules = new ArrayMap<>();
+ doAnswer(arg -> {
+ int[] uids = arg.getArgument(1);
+ int[] rules = arg.getArgument(2);
+ assertTrue(uids.length == rules.length);
+
+ for (int i = 0; i < uids.length; ++i) {
+ firewallUidRules.put(uids[i], rules[i]);
+ }
+ return null;
+ }).when(mNetworkManager).setFirewallUidRules(eq(FIREWALL_CHAIN_LOW_POWER_STANDBY),
+ any(int[].class), any(int[].class));
+
+ internal.setLowPowerStandbyAllowlist(new int[] { UID_B });
+ internal.setLowPowerStandbyActive(true);
+ assertEquals(FIREWALL_RULE_ALLOW, firewallUidRules.get(UID_A).intValue());
+ assertEquals(FIREWALL_RULE_ALLOW, firewallUidRules.get(UID_B).intValue());
+ assertFalse(mService.isUidNetworkingBlocked(UID_A, false));
+ assertFalse(mService.isUidNetworkingBlocked(UID_B, false));
+ assertTrue(mService.isUidNetworkingBlocked(UID_C, false));
+
+ internal.setLowPowerStandbyActive(false);
+ assertFalse(mService.isUidNetworkingBlocked(UID_A, false));
+ assertFalse(mService.isUidNetworkingBlocked(UID_B, false));
+ assertFalse(mService.isUidNetworkingBlocked(UID_C, false));
+ }
+
+ @Test
public void testUpdateEffectiveBlockedReasons() {
- final SparseArray<Pair<Integer, Integer>> effectiveBlockedReasons = new SparseArray<>();
- effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
- Pair.create(BLOCKED_REASON_NONE, ALLOWED_REASON_NONE));
+ final Map<Pair<Integer, Integer>, Integer> effectiveBlockedReasons = new HashMap<>();
+ effectiveBlockedReasons.put(Pair.create(BLOCKED_REASON_NONE, ALLOWED_REASON_NONE),
+ BLOCKED_REASON_NONE);
- effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
- Pair.create(BLOCKED_REASON_BATTERY_SAVER, ALLOWED_REASON_SYSTEM));
- effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
- Pair.create(BLOCKED_REASON_BATTERY_SAVER | BLOCKED_REASON_DOZE,
- ALLOWED_REASON_SYSTEM));
- effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
- Pair.create(BLOCKED_METERED_REASON_DATA_SAVER,
- ALLOWED_METERED_REASON_SYSTEM));
- effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
- Pair.create(BLOCKED_METERED_REASON_DATA_SAVER
- | BLOCKED_METERED_REASON_USER_RESTRICTED,
- ALLOWED_METERED_REASON_SYSTEM));
+ effectiveBlockedReasons.put(
+ Pair.create(BLOCKED_REASON_BATTERY_SAVER, ALLOWED_REASON_SYSTEM),
+ BLOCKED_REASON_NONE);
+ effectiveBlockedReasons.put(Pair.create(BLOCKED_REASON_BATTERY_SAVER | BLOCKED_REASON_DOZE,
+ ALLOWED_REASON_SYSTEM), BLOCKED_REASON_NONE);
+ effectiveBlockedReasons.put(
+ Pair.create(BLOCKED_METERED_REASON_DATA_SAVER, ALLOWED_METERED_REASON_SYSTEM),
+ BLOCKED_REASON_NONE);
+ effectiveBlockedReasons.put(Pair.create(BLOCKED_METERED_REASON_DATA_SAVER
+ | BLOCKED_METERED_REASON_USER_RESTRICTED,
+ ALLOWED_METERED_REASON_SYSTEM), BLOCKED_REASON_NONE);
- effectiveBlockedReasons.put(BLOCKED_METERED_REASON_DATA_SAVER,
+ effectiveBlockedReasons.put(
Pair.create(BLOCKED_REASON_BATTERY_SAVER | BLOCKED_METERED_REASON_DATA_SAVER,
- ALLOWED_REASON_SYSTEM));
- effectiveBlockedReasons.put(BLOCKED_REASON_APP_STANDBY,
+ ALLOWED_REASON_SYSTEM), BLOCKED_METERED_REASON_DATA_SAVER);
+ effectiveBlockedReasons.put(
Pair.create(BLOCKED_REASON_APP_STANDBY | BLOCKED_METERED_REASON_USER_RESTRICTED,
- ALLOWED_METERED_REASON_SYSTEM));
+ ALLOWED_METERED_REASON_SYSTEM), BLOCKED_REASON_APP_STANDBY);
- effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
- Pair.create(BLOCKED_REASON_BATTERY_SAVER, ALLOWED_REASON_FOREGROUND));
- effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
- Pair.create(BLOCKED_REASON_BATTERY_SAVER | BLOCKED_REASON_DOZE,
- ALLOWED_REASON_FOREGROUND));
- effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
- Pair.create(BLOCKED_METERED_REASON_DATA_SAVER, ALLOWED_METERED_REASON_FOREGROUND));
- effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
- Pair.create(BLOCKED_METERED_REASON_DATA_SAVER
- | BLOCKED_METERED_REASON_USER_RESTRICTED,
- ALLOWED_METERED_REASON_FOREGROUND));
- effectiveBlockedReasons.put(BLOCKED_METERED_REASON_DATA_SAVER,
+ effectiveBlockedReasons.put(
+ Pair.create(BLOCKED_REASON_BATTERY_SAVER, ALLOWED_REASON_FOREGROUND),
+ BLOCKED_REASON_NONE);
+ effectiveBlockedReasons.put(Pair.create(BLOCKED_REASON_BATTERY_SAVER | BLOCKED_REASON_DOZE,
+ ALLOWED_REASON_FOREGROUND), BLOCKED_REASON_NONE);
+ effectiveBlockedReasons.put(
+ Pair.create(BLOCKED_METERED_REASON_DATA_SAVER, ALLOWED_METERED_REASON_FOREGROUND),
+ BLOCKED_REASON_NONE);
+ effectiveBlockedReasons.put(Pair.create(BLOCKED_METERED_REASON_DATA_SAVER
+ | BLOCKED_METERED_REASON_USER_RESTRICTED,
+ ALLOWED_METERED_REASON_FOREGROUND), BLOCKED_REASON_NONE);
+ effectiveBlockedReasons.put(
Pair.create(BLOCKED_REASON_BATTERY_SAVER | BLOCKED_METERED_REASON_DATA_SAVER,
- ALLOWED_REASON_FOREGROUND));
- effectiveBlockedReasons.put(BLOCKED_REASON_BATTERY_SAVER,
- Pair.create(BLOCKED_REASON_BATTERY_SAVER
- | BLOCKED_METERED_REASON_USER_RESTRICTED,
- ALLOWED_METERED_REASON_FOREGROUND));
+ ALLOWED_REASON_FOREGROUND), BLOCKED_METERED_REASON_DATA_SAVER);
+ effectiveBlockedReasons.put(Pair.create(BLOCKED_REASON_BATTERY_SAVER
+ | BLOCKED_METERED_REASON_USER_RESTRICTED,
+ ALLOWED_METERED_REASON_FOREGROUND), BLOCKED_REASON_BATTERY_SAVER);
+
+ effectiveBlockedReasons.put(Pair.create(BLOCKED_REASON_LOW_POWER_STANDBY,
+ ALLOWED_REASON_FOREGROUND), BLOCKED_REASON_LOW_POWER_STANDBY);
+ effectiveBlockedReasons.put(Pair.create(BLOCKED_REASON_LOW_POWER_STANDBY,
+ ALLOWED_REASON_TOP), BLOCKED_REASON_NONE);
+ effectiveBlockedReasons.put(Pair.create(BLOCKED_REASON_LOW_POWER_STANDBY,
+ ALLOWED_REASON_LOW_POWER_STANDBY_ALLOWLIST), BLOCKED_REASON_NONE);
// TODO: test more combinations of blocked reasons.
- for (int i = 0; i < effectiveBlockedReasons.size(); ++i) {
- final int expectedEffectiveBlockedReasons = effectiveBlockedReasons.keyAt(i);
- final int blockedReasons = effectiveBlockedReasons.valueAt(i).first;
- final int allowedReasons = effectiveBlockedReasons.valueAt(i).second;
+ for (Map.Entry<Pair<Integer, Integer>, Integer> test : effectiveBlockedReasons.entrySet()) {
+ final int expectedEffectiveBlockedReasons = test.getValue();
+ final int blockedReasons = test.getKey().first;
+ final int allowedReasons = test.getKey().second;
final String errorMsg = "Expected="
+ blockedReasonsToString(expectedEffectiveBlockedReasons)
+ "; blockedReasons=" + blockedReasonsToString(blockedReasons)
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index 13a8f69..b72b8d2 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -30,15 +30,10 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
import android.content.pm.SigningDetails;
import android.content.pm.UserInfo;
-import com.android.server.pm.pkg.parsing.ParsingPackage;
-import com.android.server.pm.pkg.component.ParsedActivity;
-import com.android.server.pm.pkg.component.ParsedActivityImpl;
-import com.android.server.pm.pkg.component.ParsedInstrumentationImpl;
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl;
-import com.android.server.pm.pkg.component.ParsedProviderImpl;
import android.os.Build;
import android.os.Process;
import android.os.UserHandle;
@@ -53,6 +48,13 @@
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 com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.pkg.component.ParsedActivity;
+import com.android.server.pm.pkg.component.ParsedActivityImpl;
+import com.android.server.pm.pkg.component.ParsedInstrumentationImpl;
+import com.android.server.pm.pkg.component.ParsedIntentInfoImpl;
+import com.android.server.pm.pkg.component.ParsedProviderImpl;
+import com.android.server.pm.pkg.parsing.ParsingPackage;
import com.android.server.utils.WatchableTester;
import org.junit.Before;
@@ -101,6 +103,8 @@
AppsFilter.StateProvider mStateProvider;
@Mock
Executor mMockExecutor;
+ @Mock
+ PackageManagerInternal mMockPmInternal;
private ArrayMap<String, PackageSetting> mExisting = new ArrayMap<>();
@@ -222,7 +226,7 @@
public void testSystemReadyPropogates() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
appsFilter.onSystemReady();
@@ -234,7 +238,7 @@
public void testQueriesAction_FilterMatches() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
simulateAddBasicAndroid(appsFilter);
@@ -257,7 +261,7 @@
public void testQueriesProtectedAction_FilterDoesNotMatch() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
final Signature frameworkSignature = Mockito.mock(Signature.class);
@@ -306,7 +310,7 @@
public void testQueriesProvider_FilterMatches() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
simulateAddBasicAndroid(appsFilter);
@@ -331,7 +335,7 @@
public void testOnUserUpdated_FilterMatches() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -389,7 +393,7 @@
public void testQueriesDifferentProvider_Filters() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
simulateAddBasicAndroid(appsFilter);
@@ -414,7 +418,7 @@
public void testQueriesProviderWithSemiColon_FilterMatches() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -433,7 +437,7 @@
public void testQueriesAction_NoMatchingAction_Filters() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -450,7 +454,7 @@
public void testQueriesAction_NoMatchingActionFilterLowSdk_DoesntFilter() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -471,7 +475,7 @@
public void testNoQueries_Filters() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -488,7 +492,7 @@
public void testNoUsesLibrary_Filters() throws Exception {
final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock,
new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -514,7 +518,7 @@
public void testUsesLibrary_DoesntFilter() throws Exception {
final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock,
new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -541,7 +545,7 @@
public void testUsesOptionalLibrary_DoesntFilter() throws Exception {
final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock,
new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -568,7 +572,7 @@
public void testUsesLibrary_ShareUid_DoesntFilter() throws Exception {
final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock,
new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -600,7 +604,7 @@
public void testForceQueryable_SystemDoesntFilter() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -619,7 +623,7 @@
public void testForceQueryable_NonSystemFilters() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -636,7 +640,7 @@
public void testForceQueryableByDevice_SystemCaller_DoesntFilter() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{"com.some.package"},
- false, null, mMockExecutor);
+ false, null, mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -655,7 +659,7 @@
public void testSystemSignedTarget_DoesntFilter() throws CertificateException {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
appsFilter.onSystemReady();
final Signature frameworkSignature = Mockito.mock(Signature.class);
@@ -684,7 +688,7 @@
public void testForceQueryableByDevice_NonSystemCaller_Filters() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{"com.some.package"},
- false, null, mMockExecutor);
+ false, null, mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -702,7 +706,8 @@
public void testSystemQueryable_DoesntFilter() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{},
- true /* system force queryable */, null, mMockExecutor);
+ true /* system force queryable */, null, mMockExecutor,
+ mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -720,7 +725,7 @@
public void testQueriesPackage_DoesntFilter() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -739,7 +744,7 @@
.thenReturn(false);
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -756,7 +761,7 @@
public void testSystemUid_DoesntFilter() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -772,7 +777,7 @@
public void testSystemUidSecondaryUser_DoesntFilter() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -789,7 +794,7 @@
public void testNonSystemUid_NoCallingSetting_Filters() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -804,7 +809,7 @@
public void testNoTargetPackage_filters() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -862,7 +867,7 @@
return Collections.emptyMap();
}
},
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -918,7 +923,16 @@
.setOverlayTargetOverlayableName("overlayableName");
ParsingPackage actorOne = pkg("com.some.package.actor.one");
ParsingPackage actorTwo = pkg("com.some.package.actor.two");
-
+ ArraySet<PackageStateInternal> actorSharedSettingPackages = new ArraySet<>();
+ PackageSetting ps1 = getPackageSettingFromParsingPackage(actorOne, DUMMY_ACTOR_APPID,
+ null /*settingBuilder*/);
+ PackageSetting ps2 = getPackageSettingFromParsingPackage(actorTwo, DUMMY_ACTOR_APPID,
+ null /*settingBuilder*/);
+ actorSharedSettingPackages.add(ps1);
+ actorSharedSettingPackages.add(ps2);
+ when(mMockPmInternal.getSharedUserPackages(any(Integer.class))).thenReturn(
+ actorSharedSettingPackages
+ );
final AppsFilter appsFilter = new AppsFilter(
mStateProvider,
mFeatureConfigMock,
@@ -949,20 +963,18 @@
return Collections.emptyMap();
}
},
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
PackageSetting targetSetting = simulateAddPackage(appsFilter, target, DUMMY_TARGET_APPID);
SharedUserSetting actorSharedSetting = new SharedUserSetting("actorSharedUser",
targetSetting.getFlags(), targetSetting.getPrivateFlags());
+ actorSharedSetting.mAppId = 100; /* mimic a valid sharedUserSetting.mAppId */
PackageSetting overlaySetting =
simulateAddPackage(appsFilter, overlay, DUMMY_OVERLAY_APPID);
- simulateAddPackage(appsFilter, actorOne, DUMMY_ACTOR_APPID,
- null /*settingBuilder*/, actorSharedSetting);
- simulateAddPackage(appsFilter, actorTwo, DUMMY_ACTOR_APPID,
- null /*settingBuilder*/, actorSharedSetting);
-
+ simulateAddPackage(ps1, appsFilter, actorSharedSetting);
+ simulateAddPackage(ps2, appsFilter, actorSharedSetting);
// actorTwo can see both target and overlay
assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_APPID, actorSharedSetting,
@@ -975,7 +987,7 @@
public void testInitiatingApp_DoesntFilter() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -993,7 +1005,7 @@
public void testUninstalledInitiatingApp_Filters() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
@@ -1011,7 +1023,7 @@
public void testOriginatingApp_Filters() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
simulateAddBasicAndroid(appsFilter);
@@ -1036,7 +1048,7 @@
public void testInstallingApp_DoesntFilter() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
simulateAddBasicAndroid(appsFilter);
@@ -1061,7 +1073,7 @@
public void testInstrumentation_DoesntFilter() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
simulateAddBasicAndroid(appsFilter);
@@ -1090,7 +1102,7 @@
public void testWhoCanSee() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
simulateAddBasicAndroid(appsFilter);
@@ -1163,7 +1175,7 @@
public void testOnChangeReport() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
watcher.register();
simulateAddBasicAndroid(appsFilter);
@@ -1236,7 +1248,7 @@
public void testOnChangeReportedFilter() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
- mMockExecutor);
+ mMockExecutor, mMockPmInternal);
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange filter");
@@ -1292,8 +1304,15 @@
private PackageSetting simulateAddPackage(AppsFilter filter,
ParsingPackage newPkgBuilder, int appId, @Nullable WithSettingBuilder action,
@Nullable SharedUserSetting sharedUserSetting) {
- AndroidPackage newPkg = ((ParsedPackage) newPkgBuilder.hideAsParsed()).hideAsFinal();
+ final PackageSetting setting =
+ getPackageSettingFromParsingPackage(newPkgBuilder, appId, action);
+ simulateAddPackage(setting, filter, sharedUserSetting);
+ return setting;
+ }
+ private PackageSetting getPackageSettingFromParsingPackage(ParsingPackage newPkgBuilder,
+ int appId, @Nullable WithSettingBuilder action) {
+ AndroidPackage newPkg = ((ParsedPackage) newPkgBuilder.hideAsParsed()).hideAsFinal();
final PackageSettingBuilder settingBuilder = new PackageSettingBuilder()
.setPackage(newPkg)
.setAppId(appId)
@@ -1302,13 +1321,17 @@
.setPVersionCode(1L);
final PackageSetting setting =
(action == null ? settingBuilder : action.withBuilder(settingBuilder)).build();
- mExisting.put(newPkg.getPackageName(), setting);
+ return setting;
+ }
+
+ private void simulateAddPackage(PackageSetting setting, AppsFilter filter,
+ @Nullable SharedUserSetting sharedUserSetting) {
+ mExisting.put(setting.getPackageName(), setting);
if (sharedUserSetting != null) {
sharedUserSetting.addPackage(setting);
- setting.setSharedUser(sharedUserSetting);
+ setting.setSharedUserAppId(sharedUserSetting.mAppId);
}
filter.addPackage(setting);
- return setting;
}
private WithSettingBuilder withInstallSource(String initiatingPackageName,
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index ed4dee1..8873f42 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -70,6 +70,7 @@
import com.android.server.utils.Watchable;
import com.android.server.utils.WatchableTester;
import com.android.server.utils.WatchedArrayMap;
+import com.android.server.utils.WatchedArraySet;
import com.android.server.utils.Watcher;
import com.google.common.truth.Truth;
@@ -595,13 +596,13 @@
watcher.verifyNoChangeReported("getEnabled");
// Enable/Disable a component
- ArraySet<String> components = new ArraySet<String>();
+ WatchedArraySet<String> components = new WatchedArraySet<String>();
String component1 = PACKAGE_NAME_1 + "/.Component1";
components.add(component1);
ps.setDisabledComponents(components, 0);
- ArraySet<String> componentsDisabled = ps.getDisabledComponents(0);
+ WatchedArraySet<String> componentsDisabled = ps.getDisabledComponents(0);
assertThat(componentsDisabled.size(), is(1));
- assertThat(componentsDisabled.toArray()[0], is(component1));
+ assertThat(componentsDisabled.untrackedStorage().toArray()[0], is(component1));
boolean hasEnabled =
ps.getEnabledComponents(0) != null && ps.getEnabledComponents(1).size() > 0;
assertThat(hasEnabled, is(false));
@@ -704,7 +705,7 @@
null /*usesStaticLibrariesVersions*/,
null /*mimeGroups*/,
UUID.randomUUID());
- testPkgSetting01.copyPackageSetting(origPkgSetting01);
+ testPkgSetting01.copyPackageSetting(origPkgSetting01, true);
verifySettingCopy(origPkgSetting01, testPkgSetting01);
verifyUserStatesCopy(origPkgSetting01.readUserState(0),
testPkgSetting01.readUserState(0));
@@ -722,6 +723,7 @@
Settings.updatePackageSetting(
testPkgSetting01,
null /*disabledPkg*/,
+ null /*existingSharedUserSetting*/,
null /*sharedUser*/,
UPDATED_CODE_PATH /*codePath*/,
null /*legacyNativeLibraryPath*/,
@@ -757,6 +759,7 @@
Settings.updatePackageSetting(
testPkgSetting01,
null /*disabledPkg*/,
+ null /*existingSharedUserSetting*/,
null /*sharedUser*/,
UPDATED_CODE_PATH /*codePath*/,
null /*legacyNativeLibraryPath*/,
@@ -792,6 +795,7 @@
Settings.updatePackageSetting(
testPkgSetting01,
null /*disabledPkg*/,
+ null /*existingSharedUserSetting*/,
testUserSetting01 /*sharedUser*/,
UPDATED_CODE_PATH /*codePath*/,
null /*legacyNativeLibraryPath*/,
@@ -1148,8 +1152,6 @@
assertThat(origPkgSetting.getRealName(), is(testPkgSetting.getRealName()));
assertSame(origPkgSetting.getSecondaryCpuAbi(), testPkgSetting.getSecondaryCpuAbi());
assertThat(origPkgSetting.getSecondaryCpuAbi(), is(testPkgSetting.getSecondaryCpuAbi()));
- assertSame(origPkgSetting.getSharedUser(), testPkgSetting.getSharedUser());
- assertThat(origPkgSetting.getSharedUser(), is(testPkgSetting.getSharedUser()));
assertSame(origPkgSetting.getSignatures(), testPkgSetting.getSignatures());
assertThat(origPkgSetting.getSignatures(), is(testPkgSetting.getSignatures()));
assertThat(origPkgSetting.getLastModifiedTime(), is(testPkgSetting.getLastModifiedTime()));
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index 31bdec1..952200d 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -895,6 +895,7 @@
assertEquals(a.networkSecurityConfigRes, that.networkSecurityConfigRes);
assertEquals(a.taskAffinity, that.taskAffinity);
assertEquals(a.permission, that.permission);
+ assertEquals(a.getKnownActivityEmbeddingCerts(), that.getKnownActivityEmbeddingCerts());
assertEquals(a.processName, that.processName);
assertEquals(a.className, that.className);
assertEquals(a.manageSpaceActivityName, that.manageSpaceActivityName);
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
index a0edb85..4dc9612 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
@@ -39,6 +39,7 @@
import com.android.server.pm.pkg.PackageUserStateImpl;
import com.android.server.pm.pkg.SuspendParams;
+import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
@@ -238,9 +239,12 @@
PackageUserStateImpl testUserState2 =
new PackageUserStateImpl(null, testUserState1);
assertThat(testUserState1.equals(testUserState2), is(true));
- testUserState2.setSuspendParams(paramsMap2);
- // Should not be equal since suspendParams maps are different
- assertThat(testUserState1.equals(testUserState2), is(false));
+ try {
+ testUserState2.setSuspendParams(paramsMap2);
+ Assert.fail("Changing sealed snapshot of suspendParams should throw");
+ } catch (IllegalStateException e) {
+ assertThat(e.getMessage().contains("attempt to change a sealed object"), is(true));
+ }
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
index 54bfe01..9962a3c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
@@ -26,6 +26,7 @@
class ScanRequestBuilder {
private final ParsedPackage mPkg;
private AndroidPackage mOldPkg;
+ private SharedUserSetting mOldSharedUserSetting;
private SharedUserSetting mSharedUserSetting;
private PackageSetting mPkgSetting;
private PackageSetting mDisabledPkgSetting;
@@ -52,6 +53,11 @@
return this;
}
+ public ScanRequestBuilder setOldSharedUserSetting(SharedUserSetting oldSharedUserSetting) {
+ this.mOldSharedUserSetting = oldSharedUserSetting;
+ return this;
+ }
+
public ScanRequestBuilder setPkgSetting(PackageSetting pkgSetting) {
this.mPkgSetting = pkgSetting;
return this;
@@ -110,8 +116,8 @@
ScanRequest build() {
return new ScanRequest(
- mPkg, mSharedUserSetting, mOldPkg, mPkgSetting, mDisabledPkgSetting,
- mOriginalPkgSetting, mRealPkgName, mParseFlags, mScanFlags, mIsPlatformPackage,
- mUser, mCpuAbiOverride);
+ mPkg, mOldSharedUserSetting, mOldPkg, mPkgSetting, mSharedUserSetting,
+ mDisabledPkgSetting, mOriginalPkgSetting, mRealPkgName, mParseFlags, mScanFlags,
+ mIsPlatformPackage, mUser, mCpuAbiOverride);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/power/LowPowerStandbyControllerTest.java b/services/tests/servicestests/src/com/android/server/power/LowPowerStandbyControllerTest.java
index 4ae9613..00a7944 100644
--- a/services/tests/servicestests/src/com/android/server/power/LowPowerStandbyControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/LowPowerStandbyControllerTest.java
@@ -47,6 +47,7 @@
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.LocalServices;
+import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.server.testutils.OffsettableClock;
import org.junit.After;
@@ -80,6 +81,8 @@
private IPowerManager mIPowerManagerMock;
@Mock
private PowerManagerInternal mPowerManagerInternalMock;
+ @Mock
+ private NetworkPolicyManagerInternal mNetworkPolicyManagerInternal;
@Before
public void setUp() throws Exception {
@@ -90,6 +93,7 @@
PowerManager powerManager = new PowerManager(mContextSpy, mIPowerManagerMock, null, null);
when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
addLocalServiceMock(PowerManagerInternal.class, mPowerManagerInternalMock);
+ addLocalServiceMock(NetworkPolicyManagerInternal.class, mNetworkPolicyManagerInternal);
when(mIPowerManagerMock.isInteractive()).thenReturn(true);
@@ -121,6 +125,7 @@
public void tearDown() throws Exception {
LocalServices.removeServiceForTest(PowerManagerInternal.class);
LocalServices.removeServiceForTest(LowPowerStandbyControllerInternal.class);
+ LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
}
@Test
@@ -130,6 +135,7 @@
assertThat(mController.isActive()).isFalse();
verify(mPowerManagerInternalMock, never()).setLowPowerStandbyActive(anyBoolean());
+ verify(mNetworkPolicyManagerInternal, never()).setLowPowerStandbyActive(anyBoolean());
}
@Test
@@ -142,6 +148,7 @@
awaitStandbyTimeoutAlarm();
assertThat(mController.isActive()).isTrue();
verify(mPowerManagerInternalMock, times(1)).setLowPowerStandbyActive(true);
+ verify(mNetworkPolicyManagerInternal, times(1)).setLowPowerStandbyActive(true);
}
private void awaitStandbyTimeoutAlarm() {
@@ -169,6 +176,7 @@
assertThat(mController.isActive()).isFalse();
verify(mPowerManagerInternalMock, never()).setLowPowerStandbyActive(anyBoolean());
+ verify(mNetworkPolicyManagerInternal, never()).setLowPowerStandbyActive(anyBoolean());
}
@Test
@@ -182,6 +190,7 @@
assertThat(mController.isActive()).isTrue();
verify(mPowerManagerInternalMock, times(1)).setLowPowerStandbyActive(true);
+ verify(mNetworkPolicyManagerInternal, times(1)).setLowPowerStandbyActive(true);
}
@Test
@@ -197,6 +206,7 @@
assertThat(mController.isActive()).isFalse();
verify(mPowerManagerInternalMock, never()).setLowPowerStandbyActive(anyBoolean());
+ verify(mNetworkPolicyManagerInternal, never()).setLowPowerStandbyActive(anyBoolean());
}
private void verifyStandbyAlarmCancelled() {
@@ -221,6 +231,7 @@
assertThat(mController.isActive()).isFalse();
verify(mPowerManagerInternalMock, times(1)).setLowPowerStandbyActive(false);
+ verify(mNetworkPolicyManagerInternal, times(1)).setLowPowerStandbyActive(false);
}
@Test
@@ -238,6 +249,7 @@
assertThat(mController.isActive()).isFalse();
verify(mPowerManagerInternalMock, times(1)).setLowPowerStandbyActive(false);
+ verify(mNetworkPolicyManagerInternal, times(1)).setLowPowerStandbyActive(false);
}
@Test
@@ -255,6 +267,7 @@
assertThat(mController.isActive()).isTrue();
verify(mPowerManagerInternalMock, never()).setLowPowerStandbyActive(false);
+ verify(mNetworkPolicyManagerInternal, never()).setLowPowerStandbyActive(false);
}
@Test
@@ -273,6 +286,7 @@
assertThat(mController.isActive()).isTrue();
verify(mPowerManagerInternalMock, times(2)).setLowPowerStandbyActive(true);
+ verify(mNetworkPolicyManagerInternal, times(2)).setLowPowerStandbyActive(true);
}
@Test
@@ -285,6 +299,7 @@
assertThat(mController.isActive()).isFalse();
verify(mAlarmManagerMock, never()).setExact(anyInt(), anyLong(), anyString(), any(), any());
verify(mPowerManagerInternalMock, never()).setLowPowerStandbyActive(anyBoolean());
+ verify(mNetworkPolicyManagerInternal, never()).setLowPowerStandbyActive(anyBoolean());
}
@Test
@@ -350,10 +365,12 @@
service.addToAllowlist(10);
mTestLooper.dispatchAll();
verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[] {10});
+ verify(mNetworkPolicyManagerInternal).setLowPowerStandbyAllowlist(new int[] {10});
service.removeFromAllowlist(10);
mTestLooper.dispatchAll();
verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[] {});
+ verify(mNetworkPolicyManagerInternal).setLowPowerStandbyAllowlist(new int[] {});
}
@Test
@@ -366,12 +383,14 @@
assertThat(mController.isActive()).isTrue();
verify(mPowerManagerInternalMock).setLowPowerStandbyActive(true);
+ verify(mNetworkPolicyManagerInternal).setLowPowerStandbyActive(true);
mController.forceActive(false);
mTestLooper.dispatchAll();
assertThat(mController.isActive()).isFalse();
verify(mPowerManagerInternalMock).setLowPowerStandbyActive(false);
+ verify(mNetworkPolicyManagerInternal).setLowPowerStandbyActive(false);
}
private void setLowPowerStandbySupportedConfig(boolean supported) {
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 827349a..c94168c 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -87,6 +87,7 @@
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.power.PowerManagerService.BatteryReceiver;
import com.android.server.power.PowerManagerService.BinderService;
+import com.android.server.power.PowerManagerService.DockReceiver;
import com.android.server.power.PowerManagerService.Injector;
import com.android.server.power.PowerManagerService.NativeWrapper;
import com.android.server.power.PowerManagerService.UserSwitchedReceiver;
@@ -152,6 +153,7 @@
private Resources mResourcesSpy;
private OffsettableClock mClock;
private TestLooper mTestLooper;
+ private DockReceiver mDockReceiver;
private static class IntentFilterMatcher implements ArgumentMatcher<IntentFilter> {
private final IntentFilter mFilter;
@@ -337,6 +339,14 @@
argThat(new IntentFilterMatcher(usFilter)), isNull(), isA(Handler.class));
mUserSwitchedReceiver = userSwitchedCaptor.getValue();
+ // Grab the DockReceiver
+ ArgumentCaptor<DockReceiver> dockReceiverCaptor =
+ ArgumentCaptor.forClass(DockReceiver.class);
+ IntentFilter dockFilter = new IntentFilter(Intent.ACTION_DOCK_EVENT);
+ verify(mContextSpy).registerReceiver(dockReceiverCaptor.capture(),
+ argThat(new IntentFilterMatcher(dockFilter)), isNull(), isA(Handler.class));
+ mDockReceiver = dockReceiverCaptor.getValue();
+
mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
}
@@ -385,6 +395,16 @@
.thenReturn(minimumScreenOffTimeoutConfigMillis);
}
+ private void setScreenOffTimeout(int screenOffTimeoutMillis) {
+ Settings.System.putInt(mContextSpy.getContentResolver(), Settings.System.SCREEN_OFF_TIMEOUT,
+ screenOffTimeoutMillis);
+ }
+
+ private void setScreenOffTimeoutDocked(int screenOffTimeoutMillis) {
+ Settings.System.putInt(mContextSpy.getContentResolver(),
+ Settings.System.SCREEN_OFF_TIMEOUT_DOCKED, screenOffTimeoutMillis);
+ }
+
private void advanceTime(long timeMs) {
mClock.fastForward(timeMs);
mTestLooper.dispatchAll();
@@ -883,6 +903,71 @@
}
@Test
+ public void testScreenOffTimeout_goesToSleepAfterTimeout() {
+ final DisplayInfo info = new DisplayInfo();
+ info.displayGroupId = Display.DEFAULT_DISPLAY_GROUP;
+ when(mDisplayManagerInternalMock.getDisplayInfo(Display.DEFAULT_DISPLAY)).thenReturn(info);
+
+ setMinimumScreenOffTimeoutConfig(10);
+ setScreenOffTimeout(10);
+
+ createService();
+ startSystem();
+
+ mService.getBinderServiceInstance().userActivity(Display.DEFAULT_DISPLAY, mClock.now(),
+ PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ advanceTime(15);
+ assertThat(mService.getGlobalWakefulnessLocked()).isNotEqualTo(WAKEFULNESS_AWAKE);
+ }
+
+ @Test
+ public void testScreenOffTimeout_usesRegularTimeoutWhenNotDocked() {
+ final DisplayInfo info = new DisplayInfo();
+ info.displayGroupId = Display.DEFAULT_DISPLAY_GROUP;
+ when(mDisplayManagerInternalMock.getDisplayInfo(Display.DEFAULT_DISPLAY)).thenReturn(info);
+
+ setMinimumScreenOffTimeoutConfig(10);
+ setScreenOffTimeout(10);
+ setScreenOffTimeoutDocked(30);
+
+ createService();
+ startSystem();
+
+ mService.getBinderServiceInstance().userActivity(Display.DEFAULT_DISPLAY, mClock.now(),
+ PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ advanceTime(15);
+ assertThat(mService.getGlobalWakefulnessLocked()).isNotEqualTo(WAKEFULNESS_AWAKE);
+ }
+
+ @Test
+ public void testScreenOffTimeout_usesDockedTimeoutWhenDocked() {
+ final DisplayInfo info = new DisplayInfo();
+ info.displayGroupId = Display.DEFAULT_DISPLAY_GROUP;
+ when(mDisplayManagerInternalMock.getDisplayInfo(Display.DEFAULT_DISPLAY)).thenReturn(info);
+
+ setMinimumScreenOffTimeoutConfig(10);
+ setScreenOffTimeout(10);
+ setScreenOffTimeoutDocked(30);
+
+ createService();
+ startSystem();
+
+ mService.getBinderServiceInstance().userActivity(Display.DEFAULT_DISPLAY, mClock.now(),
+ PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
+ mDockReceiver.onReceive(mContextSpy,
+ new Intent(Intent.ACTION_DOCK_EVENT).putExtra(Intent.EXTRA_DOCK_STATE,
+ Intent.EXTRA_DOCK_STATE_DESK));
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ advanceTime(15);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ advanceTime(20);
+ assertThat(mService.getGlobalWakefulnessLocked()).isNotEqualTo(WAKEFULNESS_AWAKE);
+ }
+
+ @Test
public void testInattentiveSleep_goesToSleepWithWakeLock() {
final String pkg = mContextSpy.getOpPackageName();
final Binder token = new Binder();
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 32fed3b..4519890 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 @@
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 0d5b5a5..2d9903f 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 @@
@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 @@
* 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 @@
.simulateTelephonyTimeSuggestion(timeSuggestion);
long expectedSystemClockMillis =
- mScript.calculateTimeInMillisForNow(timeSuggestion.getUtcTime());
+ mScript.calculateTimeInMillisForNow(timeSuggestion.getUnixEpochTime());
mScript.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis)
.assertLatestTelephonySuggestion(slotIndex, timeSuggestion);
}
@@ -128,7 +128,7 @@
mScript.simulateTimePassing(clockIncrementMillis);
long expectedSystemClockMillis1 =
- mScript.calculateTimeInMillisForNow(timeSuggestion1.getUtcTime());
+ mScript.calculateTimeInMillisForNow(timeSuggestion1.getUnixEpochTime());
mScript.simulateTelephonyTimeSuggestion(timeSuggestion1)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1)
@@ -155,7 +155,7 @@
mScript.simulateTimePassing(clockIncrementMillis);
long expectedSystemClockMillis3 =
- mScript.calculateTimeInMillisForNow(timeSuggestion3.getUtcTime());
+ mScript.calculateTimeInMillisForNow(timeSuggestion3.getUnixEpochTime());
mScript.simulateTelephonyTimeSuggestion(timeSuggestion3)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis3)
@@ -182,8 +182,8 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
// 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 @@
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 @@
mScript.simulateTimePassing();
long expectedSystemClockMillis =
- mScript.calculateTimeInMillisForNow(telephonySuggestion.getUtcTime());
+ mScript.calculateTimeInMillisForNow(telephonySuggestion.getUnixEpochTime());
mScript.simulateTelephonyTimeSuggestion(telephonySuggestion)
.verifySystemClockWasSetAndResetCallTracking(
expectedSystemClockMillis /* expectedNetworkBroadcast */)
@@ -416,7 +417,7 @@
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 @@
mScript.simulateTimePassing();
long expectedSystemClockMillis =
- mScript.calculateTimeInMillisForNow(timeSuggestion.getUtcTime());
+ mScript.calculateTimeInMillisForNow(timeSuggestion.getUnixEpochTime());
mScript.simulateManualTimeSuggestion(timeSuggestion, true /* expectedResult */)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis);
}
@@ -457,7 +458,7 @@
mScript.simulateTimePassing();
long expectedAutoClockMillis =
- mScript.calculateTimeInMillisForNow(telephonyTimeSuggestion.getUtcTime());
+ mScript.calculateTimeInMillisForNow(telephonyTimeSuggestion.getUnixEpochTime());
mScript.simulateTelephonyTimeSuggestion(telephonyTimeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(expectedAutoClockMillis)
.assertLatestTelephonySuggestion(slotIndex, telephonyTimeSuggestion);
@@ -480,7 +481,7 @@
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 @@
mScript.simulateAutoTimeDetectionToggle();
expectedAutoClockMillis =
- mScript.calculateTimeInMillisForNow(telephonyTimeSuggestion.getUtcTime());
+ mScript.calculateTimeInMillisForNow(telephonyTimeSuggestion.getUnixEpochTime());
mScript.verifySystemClockWasSetAndResetCallTracking(expectedAutoClockMillis)
.assertLatestTelephonySuggestion(slotIndex, telephonyTimeSuggestion);
@@ -540,7 +541,7 @@
mScript.simulateTimePassing();
long expectedSystemClockMillis =
- mScript.calculateTimeInMillisForNow(timeSuggestion.getUtcTime());
+ mScript.calculateTimeInMillisForNow(timeSuggestion.getUnixEpochTime());
mScript.simulateNetworkTimeSuggestion(timeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis);
}
@@ -586,7 +587,7 @@
mScript.simulateTimePassing();
long expectedSystemClockMillis =
- mScript.calculateTimeInMillisForNow(timeSuggestion.getUtcTime());
+ mScript.calculateTimeInMillisForNow(timeSuggestion.getUnixEpochTime());
mScript.simulateGnssTimeSuggestion(timeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis);
}
@@ -617,7 +618,7 @@
mScript.simulateTimePassing();
long expectedSystemClockMillis =
- mScript.calculateTimeInMillisForNow(timeSuggestion.getUtcTime());
+ mScript.calculateTimeInMillisForNow(timeSuggestion.getUnixEpochTime());
mScript.simulateExternalTimeSuggestion(timeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis);
}
@@ -671,7 +672,8 @@
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 @@
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 @@
// 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 @@
// 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 @@
// 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 @@
mScript.simulateTimePassing(smallTimeIncrementMillis)
.simulateGnssTimeSuggestion(gnssTimeSuggestion1)
.verifySystemClockWasSetAndResetCallTracking(
- mScript.calculateTimeInMillisForNow(gnssTimeSuggestion1.getUtcTime()));
+ mScript.calculateTimeInMillisForNow(
+ gnssTimeSuggestion1.getUnixEpochTime()));
// Check internal state.
mScript.assertLatestNetworkSuggestion(null)
@@ -793,7 +797,8 @@
mScript.simulateTimePassing(smallTimeIncrementMillis)
.simulateNetworkTimeSuggestion(networkTimeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(
- mScript.calculateTimeInMillisForNow(networkTimeSuggestion.getUtcTime()));
+ mScript.calculateTimeInMillisForNow(
+ networkTimeSuggestion.getUnixEpochTime()));
// Check internal state.
mScript.assertLatestNetworkSuggestion(networkTimeSuggestion)
@@ -803,7 +808,7 @@
// 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 @@
// 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 @@
// 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 @@
mScript.simulateTimePassing(smallTimeIncrementMillis)
.simulateExternalTimeSuggestion(externalTimeSuggestion1)
.verifySystemClockWasSetAndResetCallTracking(
- mScript.calculateTimeInMillisForNow(externalTimeSuggestion1.getUtcTime()));
+ mScript.calculateTimeInMillisForNow(
+ externalTimeSuggestion1.getUnixEpochTime()));
// Check internal state.
mScript.assertLatestNetworkSuggestion(null)
@@ -896,7 +902,8 @@
mScript.simulateTimePassing(smallTimeIncrementMillis)
.simulateNetworkTimeSuggestion(networkTimeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(
- mScript.calculateTimeInMillisForNow(networkTimeSuggestion.getUtcTime()));
+ mScript.calculateTimeInMillisForNow(
+ networkTimeSuggestion.getUnixEpochTime()));
// Check internal state.
mScript.assertLatestNetworkSuggestion(networkTimeSuggestion)
@@ -906,7 +913,7 @@
// 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 @@
// 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 @@
// 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 511296a..dfcab2b 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -102,6 +102,7 @@
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
+import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AlarmManager;
@@ -241,6 +242,7 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
+@SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the service.
@RunWithLooper
public class NotificationManagerServiceTest extends UiServiceTestCase {
private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId";
@@ -1338,7 +1340,8 @@
mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
NotificationManagerService.PostNotificationRunnable runnable =
- mService.new PostNotificationRunnable(r.getKey(), SystemClock.elapsedRealtime());
+ mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
+ r.getUid(), SystemClock.elapsedRealtime());
runnable.run();
waitForIdle();
@@ -1359,7 +1362,8 @@
when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(IMPORTANCE_NONE);
NotificationManagerService.PostNotificationRunnable runnable =
- mService.new PostNotificationRunnable(r.getKey(), SystemClock.elapsedRealtime());
+ mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
+ r.getUid(), SystemClock.elapsedRealtime());
runnable.run();
waitForIdle();
@@ -3921,7 +3925,8 @@
NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, false);
mService.addEnqueuedNotification(r);
NotificationManagerService.PostNotificationRunnable runnable =
- mService.new PostNotificationRunnable(r.getKey(), SystemClock.elapsedRealtime());
+ mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
+ r.getUid(), SystemClock.elapsedRealtime());
runnable.run();
waitForIdle();
@@ -3938,7 +3943,8 @@
r = generateNotificationRecord(mTestNotificationChannel, 0, null, false);
mService.addEnqueuedNotification(r);
NotificationManagerService.PostNotificationRunnable runnable =
- mService.new PostNotificationRunnable(r.getKey(), SystemClock.elapsedRealtime());
+ mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
+ r.getUid(), SystemClock.elapsedRealtime());
runnable.run();
waitForIdle();
@@ -3954,7 +3960,8 @@
mService.addEnqueuedNotification(r);
NotificationManagerService.PostNotificationRunnable runnable =
- mService.new PostNotificationRunnable(r.getKey(), SystemClock.elapsedRealtime());
+ mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
+ r.getUid(), SystemClock.elapsedRealtime());
runnable.run();
waitForIdle();
@@ -3967,12 +3974,14 @@
r.setCriticality(CriticalNotificationExtractor.CRITICAL_LOW);
mService.addEnqueuedNotification(r);
NotificationManagerService.PostNotificationRunnable runnable =
- mService.new PostNotificationRunnable(r.getKey(), SystemClock.elapsedRealtime());
+ mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
+ r.getUid(), SystemClock.elapsedRealtime());
runnable.run();
r = generateNotificationRecord(mTestNotificationChannel, 1, null, false);
r.setCriticality(CriticalNotificationExtractor.CRITICAL);
- runnable = mService.new PostNotificationRunnable(r.getKey(), SystemClock.elapsedRealtime());
+ runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
+ r.getUid(), SystemClock.elapsedRealtime());
mService.addEnqueuedNotification(r);
runnable.run();
@@ -4006,6 +4015,63 @@
}
@Test
+ public void testMediaStyleRemote_hasPermission() throws RemoteException {
+ String deviceName = "device";
+ when(mPackageManager.checkPermission(
+ eq(android.Manifest.permission.MEDIA_CONTENT_CONTROL), any(), anyInt()))
+ .thenReturn(PERMISSION_GRANTED);
+ Notification.MediaStyle style = new Notification.MediaStyle();
+ style.setRemotePlaybackInfo(deviceName, 0, null);
+ Notification.Builder nb = new Notification.Builder(mContext,
+ mTestNotificationChannel.getId())
+ .setStyle(style);
+
+ StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
+ "testMediaStyleRemoteHasPermission", mUid, 0,
+ nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
+ NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(),
+ nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+ waitForIdle();
+
+ NotificationRecord posted = mService.findNotificationLocked(
+ PKG, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId());
+ Bundle extras = posted.getNotification().extras;
+
+ assertTrue(extras.containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE));
+ assertEquals(deviceName, extras.getString(Notification.EXTRA_MEDIA_REMOTE_DEVICE));
+ }
+
+ @Test
+ public void testMediaStyleRemote_noPermission() throws RemoteException {
+ String deviceName = "device";
+ when(mPackageManager.checkPermission(
+ eq(android.Manifest.permission.MEDIA_CONTENT_CONTROL), any(), anyInt()))
+ .thenReturn(PERMISSION_DENIED);
+ Notification.MediaStyle style = new Notification.MediaStyle();
+ style.setRemotePlaybackInfo(deviceName, 0, null);
+ Notification.Builder nb = new Notification.Builder(mContext,
+ mTestNotificationChannel.getId())
+ .setStyle(style);
+
+ StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
+ "testMediaStyleRemoteNoPermission", mUid, 0,
+ nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
+ NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(),
+ nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+ waitForIdle();
+
+ NotificationRecord posted = mService.findNotificationLocked(
+ PKG, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId());
+
+ assertFalse(posted.getNotification().extras
+ .containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE));
+ }
+
+ @Test
public void testGetNotificationCountLocked() {
String sampleTagToExclude = null;
int sampleIdToExclude = 0;
@@ -4416,6 +4482,8 @@
NotificationManagerService.PostNotificationRunnable runnable =
mService.new PostNotificationRunnable(original.getKey(),
+ original.getSbn().getPackageName(),
+ original.getUid(),
SystemClock.elapsedRealtime());
runnable.run();
waitForIdle();
@@ -4438,6 +4506,8 @@
NotificationManagerService.PostNotificationRunnable runnable =
mService.new PostNotificationRunnable(update.getKey(),
+ update.getSbn().getPackageName(),
+ update.getUid(),
SystemClock.elapsedRealtime());
runnable.run();
waitForIdle();
@@ -4659,6 +4729,59 @@
}
@Test
+ public void testAdjustmentToImportanceNone_cancelsNotification() throws Exception {
+ NotificationManagerService.WorkerHandler handler = mock(
+ NotificationManagerService.WorkerHandler.class);
+ mService.setHandler(handler);
+ when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
+ when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
+
+ // Set up notifications: r1 is adjusted, r2 is not
+ final NotificationRecord r1 = generateNotificationRecord(
+ mTestNotificationChannel, 1, null, true);
+ r1.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
+ mService.addNotification(r1);
+ final NotificationRecord r2 = generateNotificationRecord(
+ mTestNotificationChannel, 2, null, true);
+ r2.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
+ mService.addNotification(r2);
+
+ // Test an adjustment that sets importance to none (meaning it's cancelling)
+ Bundle signals1 = new Bundle();
+ signals1.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_NONE);
+ Adjustment adjustment1 = new Adjustment(
+ r1.getSbn().getPackageName(), r1.getKey(), signals1, "",
+ r1.getUser().getIdentifier());
+
+ mBinderService.applyAdjustmentFromAssistant(null, adjustment1);
+
+ // Actually apply the adjustments & recalculate importance when run
+ doAnswer(invocationOnMock -> {
+ ((NotificationRecord) invocationOnMock.getArguments()[0])
+ .applyAdjustments();
+ ((NotificationRecord) invocationOnMock.getArguments()[0])
+ .calculateImportance();
+ return null;
+ }).when(mRankingHelper).extractSignals(any(NotificationRecord.class));
+
+ // run the CancelNotificationRunnable when it happens
+ ArgumentCaptor<NotificationManagerService.CancelNotificationRunnable> captor =
+ ArgumentCaptor.forClass(
+ NotificationManagerService.CancelNotificationRunnable.class);
+
+ verify(handler, times(1)).scheduleCancelNotification(
+ captor.capture());
+
+ // Run the runnable given to the cancel notification, and see if it logs properly
+ NotificationManagerService.CancelNotificationRunnable runnable = captor.getValue();
+ runnable.run();
+ assertEquals(1, mNotificationRecordLogger.numCalls());
+ assertEquals(
+ NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_ASSISTANT,
+ mNotificationRecordLogger.event(0));
+ }
+
+ @Test
public void testEnqueuedAdjustmentAppliesAdjustments() throws Exception {
final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
mService.addEnqueuedNotification(r);
@@ -6480,7 +6603,8 @@
assertNull(update.getSbn().getNotification().getSmallIcon());
NotificationManagerService.PostNotificationRunnable runnable =
- mService.new PostNotificationRunnable(update.getKey(),
+ mService.new PostNotificationRunnable(update.getKey(), r.getSbn().getPackageName(),
+ r.getUid(),
SystemClock.elapsedRealtime());
runnable.run();
waitForIdle();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
index fec5405..d922f40 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
@@ -657,7 +657,8 @@
when(mPermissionHelper.hasPermission(anyInt())).thenReturn(false);
NotificationManagerService.PostNotificationRunnable runnable =
- mService.new PostNotificationRunnable(r.getKey(), SystemClock.elapsedRealtime());
+ mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
+ r.getUid(), SystemClock.elapsedRealtime());
runnable.run();
waitForIdle();
@@ -790,7 +791,8 @@
mService.addEnqueuedNotification(r);
NotificationManagerService.PostNotificationRunnable runnable =
- mService.new PostNotificationRunnable(r.getKey(), SystemClock.elapsedRealtime());
+ mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
+ r.getUid(), SystemClock.elapsedRealtime());
runnable.run();
waitForIdle();
@@ -806,7 +808,8 @@
r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
mService.addEnqueuedNotification(r);
- runnable = mService.new PostNotificationRunnable(r.getKey(), SystemClock.elapsedRealtime());
+ runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
+ r.getUid(), SystemClock.elapsedRealtime());
runnable.run();
waitForIdle();
@@ -822,7 +825,8 @@
r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
mService.addEnqueuedNotification(r);
- runnable = mService.new PostNotificationRunnable(r.getKey(), SystemClock.elapsedRealtime());
+ runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
+ r.getUid(), SystemClock.elapsedRealtime());
runnable.run();
waitForIdle();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
index 3b67182..b71323b 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
@@ -15,6 +15,7 @@
*/
package com.android.server.notification;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
@@ -233,8 +234,8 @@
public void testSetNotificationPermission_grantReviewRequired() throws Exception {
mPermissionHelper.setNotificationPermission("pkg", 10, true, false, true);
- verify(mPermManager).grantRuntimePermission(
- "pkg", Manifest.permission.POST_NOTIFICATIONS, 10);
+ verify(mPermManager).revokeRuntimePermission(
+ "pkg", Manifest.permission.POST_NOTIFICATIONS, 10, "PermissionHelper");
verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
FLAG_PERMISSION_REVIEW_REQUIRED, FLAG_PERMISSION_REVIEW_REQUIRED, true, 10);
}
@@ -245,10 +246,43 @@
"pkg", 10, true, false);
mPermissionHelper.setNotificationPermission(pkgPerm);
+ verify(mPermManager).revokeRuntimePermission(
+ "pkg", Manifest.permission.POST_NOTIFICATIONS, 10, "PermissionHelper");
+ verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
+ FLAG_PERMISSION_REVIEW_REQUIRED, FLAG_PERMISSION_REVIEW_REQUIRED, true, 10);
+ }
+
+ @Test
+ public void testSetNotificationPermission_pkgPerm_notUserSet_grantedByDefaultPermNotSet()
+ throws Exception {
+ when(mPermManager.getPermissionFlags(anyString(),
+ eq(Manifest.permission.POST_NOTIFICATIONS),
+ anyInt())).thenReturn(FLAG_PERMISSION_GRANTED_BY_DEFAULT);
+ PermissionHelper.PackagePermission pkgPerm = new PermissionHelper.PackagePermission(
+ "pkg", 10, true, false);
+
+ mPermissionHelper.setNotificationPermission(pkgPerm);
+ verify(mPermManager, never()).revokeRuntimePermission(
+ anyString(), anyString(), anyInt(), anyString());
+ verify(mPermManager, never()).updatePermissionFlags(
+ anyString(), anyString(), anyInt(), anyInt(), anyBoolean(), anyInt());
+ }
+
+ @Test
+ public void testSetNotificationPermission_pkgPerm_userSet_grantedByDefaultPermSet()
+ throws Exception {
+ when(mPermManager.getPermissionFlags(anyString(),
+ eq(Manifest.permission.POST_NOTIFICATIONS),
+ anyInt())).thenReturn(FLAG_PERMISSION_GRANTED_BY_DEFAULT);
+ PermissionHelper.PackagePermission pkgPerm = new PermissionHelper.PackagePermission(
+ "pkg", 10, true, true);
+
+ mPermissionHelper.setNotificationPermission(pkgPerm);
verify(mPermManager).grantRuntimePermission(
"pkg", Manifest.permission.POST_NOTIFICATIONS, 10);
verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
- FLAG_PERMISSION_REVIEW_REQUIRED, FLAG_PERMISSION_REVIEW_REQUIRED, true, 10);
+ FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_REVIEW_REQUIRED,
+ FLAG_PERMISSION_USER_SET, true, 10);
}
@Test
@@ -283,6 +317,32 @@
}
@Test
+ public void testSetNotificationPermission_SystemFixedPermNotSet() throws Exception {
+ when(mPermManager.getPermissionFlags(anyString(),
+ eq(Manifest.permission.POST_NOTIFICATIONS),
+ anyInt())).thenReturn(FLAG_PERMISSION_SYSTEM_FIXED);
+
+ mPermissionHelper.setNotificationPermission("pkg", 10, false, true);
+ verify(mPermManager, never()).revokeRuntimePermission(
+ anyString(), anyString(), anyInt(), anyString());
+ verify(mPermManager, never()).updatePermissionFlags(
+ anyString(), anyString(), anyInt(), anyInt(), anyBoolean(), anyInt());
+ }
+
+ @Test
+ public void testSetNotificationPermission_PolicyFixedPermNotSet() throws Exception {
+ when(mPermManager.getPermissionFlags(anyString(),
+ eq(Manifest.permission.POST_NOTIFICATIONS),
+ anyInt())).thenReturn(FLAG_PERMISSION_POLICY_FIXED);
+
+ mPermissionHelper.setNotificationPermission("pkg", 10, false, true);
+ verify(mPermManager, never()).revokeRuntimePermission(
+ anyString(), anyString(), anyInt(), anyString());
+ verify(mPermManager, never()).updatePermissionFlags(
+ anyString(), anyString(), anyInt(), anyInt(), anyBoolean(), anyInt());
+ }
+
+ @Test
public void testIsPermissionFixed() throws Exception {
when(mPermManager.getPermissionFlags(anyString(),
eq(Manifest.permission.POST_NOTIFICATIONS),
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index fc4ab22..8f1eed8 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -789,6 +789,73 @@
}
@Test
+ public void testReadXml_oldXml_migration_NoUid() throws Exception {
+ when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
+ mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
+ mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory);
+
+ when(mPm.getPackageUidAsUser("something", USER_SYSTEM)).thenReturn(UNKNOWN_UID);
+ String xml = "<ranking version=\"2\">\n"
+ + "<package name=\"something\" show_badge=\"true\">\n"
+ + "<channel id=\"idn\" name=\"name\" importance=\"2\"/>\n"
+ + "</package>\n"
+ + "</ranking>\n";
+ NotificationChannel idn = new NotificationChannel("idn", "name", IMPORTANCE_LOW);
+ idn.setSound(null, new AudioAttributes.Builder()
+ .setUsage(USAGE_NOTIFICATION)
+ .setContentType(CONTENT_TYPE_SONIFICATION)
+ .setFlags(0)
+ .build());
+ idn.setShowBadge(false);
+
+ loadByteArrayXml(xml.getBytes(), true, USER_SYSTEM);
+ verify(mPermissionHelper, never()).setNotificationPermission(any());
+
+ when(mPm.getPackageUidAsUser("something", USER_SYSTEM)).thenReturn(1234);
+ final ApplicationInfo app = new ApplicationInfo();
+ app.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
+ when(mPm.getApplicationInfoAsUser(eq("something"), anyInt(), anyInt())).thenReturn(app);
+
+ mHelper.onPackagesChanged(false, 0, new String[] {"something"}, new int[] {1234});
+
+
+ verify(mPermissionHelper, times(1)).setNotificationPermission(any());
+ }
+
+ @Test
+ public void testReadXml_newXml_noMigration_NoUid() throws Exception {
+ when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
+ mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
+ mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory);
+
+ when(mPm.getPackageUidAsUser("something", USER_SYSTEM)).thenReturn(UNKNOWN_UID);
+ String xml = "<ranking version=\"3\">\n"
+ + "<package name=\"something\" show_badge=\"true\">\n"
+ + "<channel id=\"idn\" name=\"name\" importance=\"2\"/>\n"
+ + "</package>\n"
+ + "</ranking>\n";
+ NotificationChannel idn = new NotificationChannel("idn", "name", IMPORTANCE_LOW);
+ idn.setSound(null, new AudioAttributes.Builder()
+ .setUsage(USAGE_NOTIFICATION)
+ .setContentType(CONTENT_TYPE_SONIFICATION)
+ .setFlags(0)
+ .build());
+ idn.setShowBadge(false);
+
+ loadByteArrayXml(xml.getBytes(), true, USER_SYSTEM);
+
+ when(mPm.getPackageUidAsUser("something", USER_SYSTEM)).thenReturn(1234);
+ final ApplicationInfo app = new ApplicationInfo();
+ app.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
+ when(mPm.getApplicationInfoAsUser(eq("something"), anyInt(), anyInt())).thenReturn(app);
+
+ mHelper.onPackagesChanged(false, 0, new String[] {"something"}, new int[] {1234});
+
+
+ verify(mPermissionHelper, never()).setNotificationPermission(any());
+ }
+
+ @Test
public void testChannelXmlForNonBackup_postMigration() throws Exception {
when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
diff --git a/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java b/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
index 00bc546..063f625 100644
--- a/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
@@ -37,7 +37,6 @@
import android.os.Process;
import android.os.SystemClock;
import android.view.KeyEvent;
-import android.view.ViewConfiguration;
import org.junit.Before;
import org.junit.Test;
@@ -75,18 +74,17 @@
@Before
public void setUp() {
mInstrumentation.runOnMainSync(() -> {
- mDetector = new SingleKeyGestureDetector();
+ mDetector = SingleKeyGestureDetector.get(mContext);
initSingleKeyGestureRules();
});
- mWaitTimeout = ViewConfiguration.getMultiPressTimeout() + 50;
- mLongPressTime = ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout() + 50;
- mVeryLongPressTime = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_veryLongPressTimeout) + 50;
+ mWaitTimeout = SingleKeyGestureDetector.MULTI_PRESS_TIMEOUT + 50;
+ mLongPressTime = SingleKeyGestureDetector.sDefaultLongPressTimeout + 50;
+ mVeryLongPressTime = SingleKeyGestureDetector.sDefaultVeryLongPressTimeout + 50;
}
private void initSingleKeyGestureRules() {
- mDetector.addRule(new SingleKeyGestureDetector.SingleKeyRule(mContext, KEYCODE_POWER,
+ mDetector.addRule(new SingleKeyGestureDetector.SingleKeyRule(KEYCODE_POWER,
KEY_LONGPRESS | KEY_VERYLONGPRESS) {
@Override
int getMaxMultiPressCount() {
@@ -124,7 +122,7 @@
}
});
- mDetector.addRule(new SingleKeyGestureDetector.SingleKeyRule(mContext, KEYCODE_BACK, 0) {
+ mDetector.addRule(new SingleKeyGestureDetector.SingleKeyRule(KEYCODE_BACK, 0) {
@Override
int getMaxMultiPressCount() {
return mMaxMultiPressCount;
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 3298d11..043bc07 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -121,6 +121,7 @@
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
+import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.PersistableBundle;
@@ -3358,6 +3359,29 @@
noProcActivity.mInputDispatchingTimeoutMillis);
}
+ @Test
+ public void testEnsureActivitiesVisibleAnotherUserTasks() {
+ // Create an activity with hierarchy:
+ // RootTask
+ // - TaskFragment
+ // - Activity
+ DisplayContent display = createNewDisplay();
+ Task rootTask = createTask(display);
+ ActivityRecord activity = createActivityRecord(rootTask);
+ final TaskFragment taskFragment = new TaskFragment(mAtm, new Binder(),
+ true /* createdByOrganizer */, true /* isEmbedded */);
+ activity.getTask().addChild(taskFragment, POSITION_TOP);
+ activity.reparent(taskFragment, POSITION_TOP);
+
+ // Ensure the activity visibility is updated even it is not shown to current user.
+ activity.mVisibleRequested = true;
+ doReturn(false).when(activity).showToCurrentUser();
+ spyOn(taskFragment);
+ doReturn(false).when(taskFragment).shouldBeVisible(any());
+ display.ensureActivitiesVisible(null, 0, false, false);
+ assertFalse(activity.mVisibleRequested);
+ }
+
private ICompatCameraControlCallback getCompatCameraControlCallback() {
return new ICompatCameraControlCallback.Stub() {
@Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index c58bf3b..c8e48a4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -75,6 +75,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManagerInternal;
+import android.content.pm.SigningDetails;
import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
@@ -84,9 +85,11 @@
import android.service.voice.IVoiceInteractionSession;
import android.util.Pair;
import android.view.Gravity;
+import android.window.TaskFragmentOrganizerToken;
import androidx.test.filters.SmallTest;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.wm.LaunchParamsController.LaunchParamsModifier;
import com.android.server.wm.utils.MockTracker;
@@ -94,6 +97,10 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
/**
* Tests for the {@link ActivityStarter} class.
*
@@ -1109,7 +1116,7 @@
}
@Test
- public void testStartActivityInner_inTaskFragment() {
+ public void testStartActivityInner_inTaskFragment_failsByDefault() {
final ActivityStarter starter = prepareStarter(0, false);
final ActivityRecord targetRecord = new ActivityBuilder(mAtm).build();
final ActivityRecord sourceRecord = new ActivityBuilder(mAtm).setCreateTask(true).build();
@@ -1130,6 +1137,97 @@
/* restrictedBgActivity */false,
/* intentGrants */null);
+ assertFalse(taskFragment.hasChild());
+ }
+
+ @Test
+ public void testStartActivityInner_inTaskFragment_allowedForSameUid() {
+ final ActivityStarter starter = prepareStarter(0, false);
+ final ActivityRecord targetRecord = new ActivityBuilder(mAtm).build();
+ final ActivityRecord sourceRecord = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ final TaskFragment taskFragment = new TaskFragment(mAtm, sourceRecord.token,
+ true /* createdByOrganizer */);
+ sourceRecord.getTask().addChild(taskFragment, POSITION_TOP);
+
+ taskFragment.setTaskFragmentOrganizer(mock(TaskFragmentOrganizerToken.class),
+ targetRecord.getUid(), "test_process_name");
+
+ starter.startActivityInner(
+ /* r */targetRecord,
+ /* sourceRecord */ sourceRecord,
+ /* voiceSession */null,
+ /* voiceInteractor */ null,
+ /* startFlags */ 0,
+ /* doResume */true,
+ /* options */null,
+ /* inTask */null,
+ /* inTaskFragment */ taskFragment,
+ /* restrictedBgActivity */false,
+ /* intentGrants */null);
+
+ assertTrue(taskFragment.hasChild());
+ }
+
+ @Test
+ public void testStartActivityInner_inTaskFragment_allowedTrustedCertUid() {
+ final ActivityStarter starter = prepareStarter(0, false);
+ final ActivityRecord targetRecord = new ActivityBuilder(mAtm).build();
+ final ActivityRecord sourceRecord = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ final TaskFragment taskFragment = new TaskFragment(mAtm, sourceRecord.token,
+ true /* createdByOrganizer */);
+ sourceRecord.getTask().addChild(taskFragment, POSITION_TOP);
+
+ taskFragment.setTaskFragmentOrganizer(mock(TaskFragmentOrganizerToken.class),
+ 12345, "test_process_name");
+ AndroidPackage androidPackage = mock(AndroidPackage.class);
+ doReturn(androidPackage).when(mMockPackageManager).getPackage(eq(12345));
+
+ Set<String> certs = new HashSet(Arrays.asList("test_cert1", "test_cert1"));
+ targetRecord.info.setKnownActivityEmbeddingCerts(certs);
+ SigningDetails signingDetails = mock(SigningDetails.class);
+ doReturn(true).when(signingDetails).hasAncestorOrSelfWithDigest(any());
+ doReturn(signingDetails).when(androidPackage).getSigningDetails();
+
+ starter.startActivityInner(
+ /* r */targetRecord,
+ /* sourceRecord */ sourceRecord,
+ /* voiceSession */null,
+ /* voiceInteractor */ null,
+ /* startFlags */ 0,
+ /* doResume */true,
+ /* options */null,
+ /* inTask */null,
+ /* inTaskFragment */ taskFragment,
+ /* restrictedBgActivity */false,
+ /* intentGrants */null);
+
+ assertTrue(taskFragment.hasChild());
+ }
+
+ @Test
+ public void testStartActivityInner_inTaskFragment_allowedForUntrustedEmbedding() {
+ final ActivityStarter starter = prepareStarter(0, false);
+ final ActivityRecord targetRecord = new ActivityBuilder(mAtm).build();
+ final ActivityRecord sourceRecord = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ final TaskFragment taskFragment = new TaskFragment(mAtm, sourceRecord.token,
+ true /* createdByOrganizer */);
+ sourceRecord.getTask().addChild(taskFragment, POSITION_TOP);
+
+ targetRecord.info.flags |= ActivityInfo.FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING;
+
+ starter.startActivityInner(
+ /* r */targetRecord,
+ /* sourceRecord */ sourceRecord,
+ /* voiceSession */null,
+ /* voiceInteractor */ null,
+ /* startFlags */ 0,
+ /* doResume */true,
+ /* options */null,
+ /* inTask */null,
+ /* inTaskFragment */ taskFragment,
+ /* restrictedBgActivity */false,
+ /* intentGrants */null);
+
assertTrue(taskFragment.hasChild());
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index fb3a626..3d89805 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -97,7 +97,7 @@
BackNavigationInfo backNavigationInfo =
mBackNavigationController.startBackNavigation(task, new StubTransaction());
assertThat(backNavigationInfo).isNotNull();
- assertThat(backNavigationInfo.getDepartingWindowContainer()).isNotNull();
+ assertThat(backNavigationInfo.getDepartingAnimationTarget()).isNotNull();
assertThat(backNavigationInfo.getScreenshotSurface()).isNotNull();
assertThat(backNavigationInfo.getScreenshotHardwareBuffer()).isNotNull();
assertThat(backNavigationInfo.getTaskWindowConfiguration()).isNotNull();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index efc9a49..9f7130e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -447,25 +447,6 @@
}
/**
- * This tests override configuration updates for display content.
- */
- @Test
- public void testDisplayOverrideConfigUpdate() {
- final Configuration currentOverrideConfig =
- mDisplayContent.getRequestedOverrideConfiguration();
-
- // Create new, slightly changed override configuration and apply it to the display.
- final Configuration newOverrideConfig = new Configuration(currentOverrideConfig);
- newOverrideConfig.densityDpi += 120;
- newOverrideConfig.fontScale += 0.3;
-
- mWm.setNewDisplayOverrideConfiguration(newOverrideConfig, mDisplayContent);
-
- // Check that override config is applied.
- assertEquals(newOverrideConfig, mDisplayContent.getRequestedOverrideConfiguration());
- }
-
- /**
* This tests global configuration updates when default display config is updated.
*/
@Test
@@ -478,7 +459,8 @@
newOverrideConfig.densityDpi += 120;
newOverrideConfig.fontScale += 0.3;
- mWm.setNewDisplayOverrideConfiguration(newOverrideConfig, defaultDisplay);
+ defaultDisplay.updateDisplayOverrideConfigurationLocked(newOverrideConfig,
+ null /* starting */, false /* deferResume */, null /* result */);
// Check that global configuration is updated, as we've updated default display's config.
Configuration globalConfig = mWm.mRoot.getConfiguration();
@@ -486,7 +468,8 @@
assertEquals(newOverrideConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
// Return back to original values.
- mWm.setNewDisplayOverrideConfiguration(currentConfig, defaultDisplay);
+ defaultDisplay.updateDisplayOverrideConfigurationLocked(currentConfig,
+ null /* starting */, false /* deferResume */, null /* result */);
globalConfig = mWm.mRoot.getConfiguration();
assertEquals(currentConfig.densityDpi, globalConfig.densityDpi);
assertEquals(currentConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 87f76fa..e091190 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -16,9 +16,6 @@
package com.android.server.wm;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
@@ -632,10 +629,11 @@
@Test
public void testAttachNavBarInSplitScreenMode() {
setupForShouldAttachNavBarDuringTransition();
- final ActivityRecord primary = createActivityRecordWithParentTask(mDefaultDisplay,
- WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD);
- final ActivityRecord secondary = createActivityRecordWithParentTask(mDefaultDisplay,
- WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD);
+ TestSplitOrganizer organizer = new TestSplitOrganizer(mAtm);
+ final ActivityRecord primary = createActivityRecordWithParentTask(
+ organizer.createTaskToPrimary(true));
+ final ActivityRecord secondary = createActivityRecordWithParentTask(
+ organizer.createTaskToSecondary(true));
final ActivityRecord homeActivity = createHomeActivity();
homeActivity.setVisibility(true);
initializeRecentsAnimationController(mController, homeActivity);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
index dcaa511..6128428 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
@@ -24,8 +24,6 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
@@ -87,7 +85,6 @@
import androidx.test.filters.SmallTest;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -499,42 +496,54 @@
assertTrue(pinnedRootTask.shouldBeVisible(null /* starting */));
}
- // TODO(b/199236198): check this is unnecessary or need to migrate after remove legacy split.
@Test
- @Ignore
public void testShouldBeVisible_SplitScreen() {
- // task not supporting split should be fullscreen for this test.
- final Task notSupportingSplitTask = createTaskForShouldBeVisibleTest(
+ // Fullscreen root task for this test.
+ final Task fullScreenRootTask = createTaskForShouldBeVisibleTest(
mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
- doReturn(false).when(notSupportingSplitTask).supportsSplitScreenWindowingMode();
- final Task splitScreenPrimary = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
- WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final Task splitScreenSecondary = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
- WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- // root task not supporting split shouldn't be visible if both halves of split-screen are
- // opaque.
+ final TestSplitOrganizer organizer = new TestSplitOrganizer(mAtm);
+ final Task splitScreenPrimary = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final Task splitScreenSecondary = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ organizer.putTaskToPrimary(splitScreenPrimary, true /* onTop */);
+ organizer.putTaskToSecondary(splitScreenSecondary, true /* onTop */);
+ splitScreenPrimary.moveToFront("testShouldBeVisible_SplitScreen");
+ splitScreenSecondary.moveToFront("testShouldBeVisible_SplitScreen");
+
+ // Fullscreen root task shouldn't be visible if both halves of split-screen are opaque.
+ doReturn(false).when(organizer.mPrimary).isTranslucent(any());
+ doReturn(false).when(organizer.mSecondary).isTranslucent(any());
doReturn(false).when(splitScreenPrimary).isTranslucent(any());
doReturn(false).when(splitScreenSecondary).isTranslucent(any());
- assertFalse(notSupportingSplitTask.shouldBeVisible(null /* starting */));
+ assertFalse(fullScreenRootTask.shouldBeVisible(null /* starting */));
+ assertTrue(organizer.mPrimary.shouldBeVisible(null /* starting */));
+ assertTrue(organizer.mSecondary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
- // root task not supporting split shouldn't be visible if one of the halves of split-screen
+ // Fullscreen root task shouldn't be visible if one of the halves of split-screen
// is translucent.
doReturn(true).when(splitScreenPrimary).isTranslucent(any());
- assertFalse(notSupportingSplitTask.shouldBeVisible(null /* starting */));
+ assertFalse(fullScreenRootTask.shouldBeVisible(null /* starting */));
+ assertTrue(organizer.mPrimary.shouldBeVisible(null /* starting */));
+ assertTrue(organizer.mSecondary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
final Task splitScreenSecondary2 = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
- WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ organizer.putTaskToSecondary(splitScreenSecondary2, true /* onTop */);
// First split-screen secondary shouldn't be visible behind another opaque split-split
// secondary.
doReturn(false).when(splitScreenSecondary2).isTranslucent(any());
+ assertTrue(organizer.mSecondary.shouldBeVisible(null /* starting */));
assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
+ assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE,
+ organizer.mSecondary.getVisibility(null /* starting */));
assertEquals(TASK_FRAGMENT_VISIBILITY_INVISIBLE,
splitScreenSecondary.getVisibility(null /* starting */));
assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE,
@@ -543,8 +552,11 @@
// First split-screen secondary should be visible behind another translucent split-screen
// secondary.
doReturn(true).when(splitScreenSecondary2).isTranslucent(any());
+ assertTrue(organizer.mSecondary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
+ assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE,
+ organizer.mSecondary.getVisibility(null /* starting */));
assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
splitScreenSecondary.getVisibility(null /* starting */));
assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE,
@@ -556,6 +568,8 @@
// Split-screen root tasks shouldn't be visible behind an opaque fullscreen root task.
doReturn(false).when(assistantRootTask).isTranslucent(any());
assertTrue(assistantRootTask.shouldBeVisible(null /* starting */));
+ assertFalse(organizer.mPrimary.shouldBeVisible(null /* starting */));
+ assertFalse(organizer.mSecondary.shouldBeVisible(null /* starting */));
assertFalse(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */));
assertFalse(splitScreenSecondary2.shouldBeVisible(null /* starting */));
@@ -571,51 +585,23 @@
// Split-screen root tasks should be visible behind a translucent fullscreen root task.
doReturn(true).when(assistantRootTask).isTranslucent(any());
assertTrue(assistantRootTask.shouldBeVisible(null /* starting */));
+ assertTrue(organizer.mPrimary.shouldBeVisible(null /* starting */));
+ assertTrue(organizer.mSecondary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE,
assistantRootTask.getVisibility(null /* starting */));
assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ organizer.mPrimary.getVisibility(null /* starting */));
+ assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ organizer.mSecondary.getVisibility(null /* starting */));
+ assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
splitScreenPrimary.getVisibility(null /* starting */));
assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
splitScreenSecondary.getVisibility(null /* starting */));
assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
splitScreenSecondary2.getVisibility(null /* starting */));
-
- // Assistant root task shouldn't be visible behind translucent split-screen root task,
- // unless it is configured to show on top of everything.
- doReturn(false).when(assistantRootTask).isTranslucent(any());
- doReturn(true).when(splitScreenPrimary).isTranslucent(any());
- doReturn(true).when(splitScreenSecondary2).isTranslucent(any());
- splitScreenSecondary2.moveToFront("testShouldBeVisible_SplitScreen");
- splitScreenPrimary.moveToFront("testShouldBeVisible_SplitScreen");
-
- if (isAssistantOnTop()) {
- assertTrue(assistantRootTask.shouldBeVisible(null /* starting */));
- assertFalse(splitScreenPrimary.shouldBeVisible(null /* starting */));
- assertFalse(splitScreenSecondary2.shouldBeVisible(null /* starting */));
- assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE,
- assistantRootTask.getVisibility(null /* starting */));
- assertEquals(TASK_FRAGMENT_VISIBILITY_INVISIBLE,
- splitScreenPrimary.getVisibility(null /* starting */));
- assertEquals(TASK_FRAGMENT_VISIBILITY_INVISIBLE,
- splitScreenSecondary.getVisibility(null /* starting */));
- assertEquals(TASK_FRAGMENT_VISIBILITY_INVISIBLE,
- splitScreenSecondary2.getVisibility(null /* starting */));
- } else {
- assertFalse(assistantRootTask.shouldBeVisible(null /* starting */));
- assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
- assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
- assertEquals(TASK_FRAGMENT_VISIBILITY_INVISIBLE,
- assistantRootTask.getVisibility(null /* starting */));
- assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE,
- splitScreenPrimary.getVisibility(null /* starting */));
- assertEquals(TASK_FRAGMENT_VISIBILITY_INVISIBLE,
- splitScreenSecondary.getVisibility(null /* starting */));
- assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE,
- splitScreenSecondary2.getVisibility(null /* starting */));
- }
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
index f573b70..e433684 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
@@ -116,7 +116,7 @@
public void testGetSnapshotMode() {
final WindowState disabledWindow = createWindow(null,
FIRST_APPLICATION_WINDOW, mDisplayContent, "disabledWindow");
- disabledWindow.mActivityRecord.setDisablePreviewScreenshots(true);
+ disabledWindow.mActivityRecord.setRecentsScreenshotEnabled(false);
assertEquals(SNAPSHOT_MODE_APP_THEME,
mWm.mTaskSnapshotController.getSnapshotMode(disabledWindow.getTask()));
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index 8b14e98..41a59eb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -870,6 +870,24 @@
final DisplayContent displayContent = createNewDisplay();
// Do not reparent activity to default display when removing the display.
doReturn(true).when(displayContent).shouldDestroyContentOnRemove();
+
+ // An animating window with mRemoveOnExit can be removed by handleCompleteDeferredRemoval
+ // once it no longer animates.
+ final WindowState exitingWindow = createWindow(null, TYPE_APPLICATION_OVERLAY,
+ displayContent, "exiting window");
+ exitingWindow.startAnimation(exitingWindow.getPendingTransaction(),
+ mock(AnimationAdapter.class), false /* hidden */,
+ SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION);
+ exitingWindow.mRemoveOnExit = true;
+ exitingWindow.handleCompleteDeferredRemoval();
+ // The animation has not finished so the window is not removed.
+ assertTrue(exitingWindow.isAnimating());
+ assertTrue(exitingWindow.isAttached());
+ exitingWindow.cancelAnimation();
+ // The window is removed because the animation is gone.
+ exitingWindow.handleCompleteDeferredRemoval();
+ assertFalse(exitingWindow.isAttached());
+
final ActivityRecord r = new TaskBuilder(mSupervisor).setCreateActivity(true)
.setDisplay(displayContent).build().getTopMostActivity();
// Add a window and make the activity animating so the removal of activity is deferred.
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index a91298f..2dfc72b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -160,8 +160,7 @@
@Test
public void testDismissKeyguardCanWakeUp() {
doReturn(true).when(mWm).checkCallingPermission(anyString(), anyString());
- spyOn(mWm.mAtmInternal);
- doReturn(true).when(mWm.mAtmInternal).isDreaming();
+ doReturn(true).when(mWm.mAtmService).isDreaming();
doNothing().when(mWm.mAtmService.mTaskSupervisor).wakeUp(anyString());
mWm.dismissKeyguard(null, "test-dismiss-keyguard");
verify(mWm.mAtmService.mTaskSupervisor).wakeUp(anyString());
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 4095728..5dbb4c5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -24,6 +24,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.os.Process.SYSTEM_UID;
import static android.view.View.VISIBLE;
import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
@@ -1531,9 +1532,16 @@
final Rect primaryBounds = new Rect();
final Rect secondaryBounds = new Rect();
- display.getBounds().splitVertically(primaryBounds, secondaryBounds);
+ if (display.getConfiguration().orientation == ORIENTATION_LANDSCAPE) {
+ display.getBounds().splitVertically(primaryBounds, secondaryBounds);
+ } else {
+ display.getBounds().splitHorizontally(primaryBounds, secondaryBounds);
+ }
mPrimary.setBounds(primaryBounds);
mSecondary.setBounds(secondaryBounds);
+
+ spyOn(mPrimary);
+ spyOn(mSecondary);
}
TestSplitOrganizer(ActivityTaskManagerService service) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index 8acd3c7..84bd983 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -45,7 +45,6 @@
import android.os.IRemoteCallback;
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
-import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SharedMemory;
@@ -278,8 +277,10 @@
mRemoteHotwordDetectionService.unbind();
LocalServices.getService(PermissionManagerServiceInternal.class)
.setHotwordDetectionServiceProvider(null);
+ if (mIdentity != null) {
+ removeServiceUidForAudioPolicy(mIdentity.getIsolatedUid());
+ }
mIdentity = null;
- updateServiceUidForAudioPolicy(Process.INVALID_UID);
mCancellationTaskFuture.cancel(/* may interrupt */ true);
if (mAudioFlinger != null) {
mAudioFlinger.unlinkToDeath(mAudioServerDeathRecipient, /* flags= */ 0);
@@ -909,17 +910,27 @@
LocalServices.getService(PermissionManagerServiceInternal.class)
.setHotwordDetectionServiceProvider(() -> uid);
mIdentity = new HotwordDetectionServiceIdentity(uid, mVoiceInteractionServiceUid);
- updateServiceUidForAudioPolicy(uid);
+ addServiceUidForAudioPolicy(uid);
}
}));
}
- private void updateServiceUidForAudioPolicy(int uid) {
+ private void addServiceUidForAudioPolicy(int uid) {
mScheduledExecutorService.execute(() -> {
- final AudioManagerInternal audioManager =
+ AudioManagerInternal audioManager =
LocalServices.getService(AudioManagerInternal.class);
if (audioManager != null) {
- audioManager.setHotwordDetectionServiceUid(uid);
+ audioManager.addAssistantServiceUid(uid);
+ }
+ });
+ }
+
+ private void removeServiceUidForAudioPolicy(int uid) {
+ mScheduledExecutorService.execute(() -> {
+ AudioManagerInternal audioManager =
+ LocalServices.getService(AudioManagerInternal.class);
+ if (audioManager != null) {
+ audioManager.removeAssistantServiceUid(uid);
}
});
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 1285a84..8cbbe94 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -263,6 +263,25 @@
}
@Override
+ public String getVoiceInteractorPackageName(IBinder callingVoiceInteractor) {
+ VoiceInteractionManagerServiceImpl impl =
+ VoiceInteractionManagerService.this.mServiceStub.mImpl;
+ if (impl == null) {
+ return null;
+ }
+ VoiceInteractionSessionConnection session =
+ impl.mActiveSession;
+ if (session == null) {
+ return null;
+ }
+ IVoiceInteractor voiceInteractor = session.mInteractor;
+ if (voiceInteractor == null || voiceInteractor.asBinder() != callingVoiceInteractor) {
+ return null;
+ }
+ return session.mSessionComponentName.getPackageName();
+ }
+
+ @Override
public HotwordDetectionServiceIdentity getHotwordDetectionServiceIdentity() {
// IMPORTANT: This is called when performing permission checks; do not lock!
diff --git a/telephony/java/android/service/euicc/EuiccService.java b/telephony/java/android/service/euicc/EuiccService.java
index 30ed7c2..8d92520 100644
--- a/telephony/java/android/service/euicc/EuiccService.java
+++ b/telephony/java/android/service/euicc/EuiccService.java
@@ -524,7 +524,10 @@
* defined in {@code RESOLVABLE_ERROR_}. A subclass should override this method. Otherwise,
* this method does nothing and returns null by default.
* @see android.telephony.euicc.EuiccManager#downloadSubscription
+ * @deprecated prefer {@link #onDownloadSubscription(int, int,
+ * DownloadableSubscription, boolean, boolean, Bundle)}
*/
+ @Deprecated
public DownloadSubscriptionResult onDownloadSubscription(int slotId,
@NonNull DownloadableSubscription subscription, boolean switchAfterDownload,
boolean forceDeactivateSim, @Nullable Bundle resolvedBundle) {
@@ -534,6 +537,37 @@
/**
* Download the given subscription.
*
+ * @param slotIndex Index of the SIM slot to use for the operation.
+ * @param portIndex Index of the port from the slot. portIndex is used when
+ * switchAfterDownload is set to {@code true}, otherwise download is port agnostic.
+ * @param subscription The subscription to download.
+ * @param switchAfterDownload If true, the subscription should be enabled upon successful
+ * download.
+ * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the
+ * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM}
+ * should be returned to allow the user to consent to this operation first.
+ * @param resolvedBundle The bundle containing information on resolved errors. It can contain
+ * a string of confirmation code for the key {@link #EXTRA_RESOLUTION_CONFIRMATION_CODE},
+ * and a boolean for key {@link #EXTRA_RESOLUTION_ALLOW_POLICY_RULES} indicating whether
+ * the user allows profile policy rules or not.
+ * @return a DownloadSubscriptionResult instance including a result code, a resolvable errors
+ * bit map, and original the card Id. The result code may be one of the predefined
+ * {@code RESULT_} constants or any implementation-specific code starting with
+ * {@link #RESULT_FIRST_USER}. The resolvable error bit map can be either 0 or values
+ * defined in {@code RESOLVABLE_ERROR_}.
+ * @see android.telephony.euicc.EuiccManager#downloadSubscription
+ */
+ @NonNull
+ public DownloadSubscriptionResult onDownloadSubscription(int slotIndex, int portIndex,
+ @NonNull DownloadableSubscription subscription, boolean switchAfterDownload,
+ boolean forceDeactivateSim, @NonNull Bundle resolvedBundle) {
+ // stub implementation, LPA needs to implement this
+ throw new UnsupportedOperationException("LPA must override onDownloadSubscription");
+ }
+
+ /**
+ * Download the given subscription.
+ *
* @param slotId ID of the SIM slot to use for the operation.
* @param subscription The subscription to download.
* @param switchAfterDownload If true, the subscription should be enabled upon successful
@@ -701,7 +735,8 @@
*/
private class IEuiccServiceWrapper extends IEuiccService.Stub {
@Override
- public void downloadSubscription(int slotId, DownloadableSubscription subscription,
+ public void downloadSubscription(int slotId, int portIndex,
+ DownloadableSubscription subscription,
boolean switchAfterDownload, boolean forceDeactivateSim, Bundle resolvedBundle,
IDownloadSubscriptionCallback callback) {
mExecutor.execute(new Runnable() {
diff --git a/telephony/java/android/service/euicc/IEuiccService.aidl b/telephony/java/android/service/euicc/IEuiccService.aidl
index 030e11a..6b0397d 100644
--- a/telephony/java/android/service/euicc/IEuiccService.aidl
+++ b/telephony/java/android/service/euicc/IEuiccService.aidl
@@ -35,9 +35,9 @@
/** @hide */
oneway interface IEuiccService {
- void downloadSubscription(int slotId, in DownloadableSubscription subscription,
- boolean switchAfterDownload, boolean forceDeactivateSim, in Bundle resolvedBundle,
- in IDownloadSubscriptionCallback callback);
+ void downloadSubscription(int slotId, int portIndex, in DownloadableSubscription subscription,
+ boolean switchAfterDownload, boolean forceDeactivateSim, in Bundle resolvedBundle,
+ in IDownloadSubscriptionCallback callback);
void getDownloadableSubscriptionMetadata(int slotId, in DownloadableSubscription subscription,
boolean forceDeactivateSim, in IGetDownloadableSubscriptionMetadataCallback callback);
void getEid(int slotId, in IGetEidCallback callback);
diff --git a/telephony/java/android/telephony/CallQuality.java b/telephony/java/android/telephony/CallQuality.java
index d77bf67..9b12ae5 100644
--- a/telephony/java/android/telephony/CallQuality.java
+++ b/telephony/java/android/telephony/CallQuality.java
@@ -86,7 +86,7 @@
private int mNumDroppedRtpPackets;
private long mMinPlayoutDelayMillis;
private long mMaxPlayoutDelayMillis;
- private int mNumRtpSidPacketsRx;
+ private int mNumRtpSidPacketsReceived;
private int mNumRtpDuplicatePackets;
/** @hide **/
@@ -110,7 +110,7 @@
mNumDroppedRtpPackets = in.readInt();
mMinPlayoutDelayMillis = in.readLong();
mMaxPlayoutDelayMillis = in.readLong();
- mNumRtpSidPacketsRx = in.readInt();
+ mNumRtpSidPacketsReceived = in.readInt();
mNumRtpDuplicatePackets = in.readInt();
}
@@ -352,8 +352,8 @@
* Returns the total number of RTP SID (Silence Insertion Descriptor) packets
* received by this device for an ongoing call
*/
- public int getNumRtpSidPacketsRx() {
- return mNumRtpSidPacketsRx;
+ public int getNumRtpSidPacketsReceived() {
+ return mNumRtpSidPacketsReceived;
}
/**
@@ -417,7 +417,7 @@
+ " numDroppedRtpPackets=" + mNumDroppedRtpPackets
+ " minPlayoutDelayMillis=" + mMinPlayoutDelayMillis
+ " maxPlayoutDelayMillis=" + mMaxPlayoutDelayMillis
- + " numRtpSidPacketsRx=" + mNumRtpSidPacketsRx
+ + " numRtpSidPacketsReceived=" + mNumRtpSidPacketsReceived
+ " numRtpDuplicatePackets=" + mNumRtpDuplicatePackets
+ "}";
}
@@ -444,7 +444,7 @@
mNumDroppedRtpPackets,
mMinPlayoutDelayMillis,
mMaxPlayoutDelayMillis,
- mNumRtpSidPacketsRx,
+ mNumRtpSidPacketsReceived,
mNumRtpDuplicatePackets);
}
@@ -479,7 +479,7 @@
&& mNumDroppedRtpPackets == s.mNumDroppedRtpPackets
&& mMinPlayoutDelayMillis == s.mMinPlayoutDelayMillis
&& mMaxPlayoutDelayMillis == s.mMaxPlayoutDelayMillis
- && mNumRtpSidPacketsRx == s.mNumRtpSidPacketsRx
+ && mNumRtpSidPacketsReceived == s.mNumRtpSidPacketsReceived
&& mNumRtpDuplicatePackets == s.mNumRtpDuplicatePackets);
}
@@ -513,7 +513,7 @@
dest.writeInt(mNumDroppedRtpPackets);
dest.writeLong(mMinPlayoutDelayMillis);
dest.writeLong(mMaxPlayoutDelayMillis);
- dest.writeInt(mNumRtpSidPacketsRx);
+ dest.writeInt(mNumRtpSidPacketsReceived);
dest.writeInt(mNumRtpDuplicatePackets);
}
@@ -562,7 +562,7 @@
private int mNumDroppedRtpPackets;
private long mMinPlayoutDelayMillis;
private long mMaxPlayoutDelayMillis;
- private int mNumRtpSidPacketsRx;
+ private int mNumRtpSidPacketsReceived;
private int mNumRtpDuplicatePackets;
/**
@@ -595,8 +595,11 @@
* @param callDuration the call duration in milliseconds
* @return The same instance of the builder.
*/
- public @NonNull Builder setCallDuration(int callDuration) {
- mCallDuration = callDuration;
+ // Newer builder includes guidelines compliant units; existing method does not.
+ @NonNull
+ @SuppressWarnings("MissingGetterMatchingBuilder")
+ public Builder setCallDurationMillis(int callDurationMillis) {
+ mCallDuration = callDurationMillis;
return this;
}
@@ -675,8 +678,11 @@
* @param averageRoundTripTime average round trip delay in milliseconds
* @return The same instance of the builder.
*/
- public @NonNull Builder setAverageRoundTripTime(int averageRoundTripTime) {
- mAverageRoundTripTime = averageRoundTripTime;
+ // Newer builder includes guidelines compliant units; existing method does not.
+ @NonNull
+ @SuppressWarnings("MissingGetterMatchingBuilder")
+ public Builder setAverageRoundTripTimeMillis(int averageRoundTripTimeMillis) {
+ mAverageRoundTripTime = averageRoundTripTimeMillis;
return this;
}
@@ -789,12 +795,12 @@
* Set the total number of RTP SID (Silence Insertion Descriptor)
* packets received by this device for an ongoing call.
*
- * @param numRtpSidPacketsRx the total number of RTP SID packets received
+ * @param numRtpSidPacketsReceived the total number of RTP SID packets received
* by this device for an ongoing call.
* @return The same instance of the builder.
*/
- public @NonNull Builder setNumRtpSidPacketsRx(int numRtpSidPacketsRx) {
- mNumRtpSidPacketsRx = numRtpSidPacketsRx;
+ public @NonNull Builder setNumRtpSidPacketsReceived(int numRtpSidPacketsReceived) {
+ mNumRtpSidPacketsReceived = numRtpSidPacketsReceived;
return this;
}
@@ -838,7 +844,7 @@
callQuality.mNumDroppedRtpPackets = mNumDroppedRtpPackets;
callQuality.mMinPlayoutDelayMillis = mMinPlayoutDelayMillis;
callQuality.mMaxPlayoutDelayMillis = mMaxPlayoutDelayMillis;
- callQuality.mNumRtpSidPacketsRx = mNumRtpSidPacketsRx;
+ callQuality.mNumRtpSidPacketsReceived = mNumRtpSidPacketsReceived;
callQuality.mNumRtpDuplicatePackets = mNumRtpDuplicatePackets;
return callQuality;
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index dbdb198..2c39863 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -3796,7 +3796,7 @@
/**
* 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";
@@ -3840,6 +3840,17 @@
"opportunistic_carrier_ids_int_array";
/**
+ * 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 at which OpportunisticNetworkService will decide whether
* the opportunistic network is good enough for internet data.
*/
@@ -4754,6 +4765,15 @@
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>
@@ -5210,7 +5230,7 @@
* <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_CALL_COMPOSER_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}
@@ -5219,39 +5239,68 @@
KEY_PREFIX + "mmtel_requires_provisioning_bundle";
/**
- * This MmTelFeature supports Voice calling (IR.92)
+ * 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 + "key_capability_type_voice_int_array";
+ KEY_PREFIX + "capability_type_voice_int_array";
/**
- * This MmTelFeature supports Video (IR.94)
+ * 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 + "key_capability_type_video_int_array";
+ KEY_PREFIX + "capability_type_video_int_array";
/**
- * This MmTelFeature supports XCAP over Ut for supplementary services. (IR.92)
+ * 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 + "key_capability_type_ut_int_array";
+ KEY_PREFIX + "capability_type_ut_int_array";
/**
- * This MmTelFeature supports SMS (IR.92)
+ * 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 + "key_capability_type_sms_int_array";
+ KEY_PREFIX + "capability_type_sms_int_array";
/**
- * This MmTelFeature supports Call Composer (section 2.4 of RCC.20)
+ * 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_CALL_COMPOSER_INT_ARRAY =
- KEY_PREFIX + "key_capability_type_call_composer_int_array";
+ 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
@@ -5274,9 +5323,14 @@
* 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 + "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
@@ -5284,9 +5338,14 @@
* 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 + "key_capability_type_presence_uce_int_array";
+ KEY_PREFIX + "capability_type_presence_uce_int_array";
private Ims() {}
@@ -5300,6 +5359,7 @@
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);
@@ -5327,16 +5387,13 @@
/**
* @see #KEY_MMTEL_REQUIRES_PROVISIONING_BUNDLE
*/
- PersistableBundle mmtel_requires_provisioning_int_array = new PersistableBundle();
defaults.putPersistableBundle(
- KEY_MMTEL_REQUIRES_PROVISIONING_BUNDLE, mmtel_requires_provisioning_int_array);
-
+ KEY_MMTEL_REQUIRES_PROVISIONING_BUNDLE, new PersistableBundle());
/**
* @see #KEY_RCS_REQUIRES_PROVISIONING_BUNDLE
*/
- PersistableBundle rcs_requires_provisioning_int_array = new PersistableBundle();
defaults.putPersistableBundle(
- KEY_RCS_REQUIRES_PROVISIONING_BUNDLE, rcs_requires_provisioning_int_array);
+ KEY_RCS_REQUIRES_PROVISIONING_BUNDLE, new PersistableBundle());
defaults.putBoolean(KEY_GRUU_ENABLED_BOOL, true);
defaults.putBoolean(KEY_SIP_OVER_IPSEC_ENABLED_BOOL, true);
@@ -8780,6 +8837,7 @@
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 */
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index ba1a6ed..613b0a6 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -7118,7 +7118,14 @@
*/
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
public boolean iccCloseLogicalChannel(int channel) {
- return iccCloseLogicalChannel(getSubId(), channel);
+ try {
+ return iccCloseLogicalChannel(getSubId(), channel);
+ } catch (IllegalStateException ex) {
+ Rlog.e(TAG, "iccCloseLogicalChannel IllegalStateException", ex);
+ } catch (IllegalArgumentException ex) {
+ Rlog.e(TAG, "iccCloseLogicalChannel IllegalArgumentException", ex);
+ }
+ return false;
}
/**
@@ -7639,7 +7646,7 @@
* {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
* app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
- * TODO: remove this one. use {@link #rebootRadio()} for reset type 1 and
+ * TODO: remove this one. use {@link #rebootModem()} for reset type 1 and
* {@link #resetRadioConfig()} for reset type 3
*
* @param resetType reset type: 1: reload NV reset, 2: erase NV reset, 3: factory NV reset
@@ -7706,6 +7713,8 @@
*
* @return {@code true} on success; {@code false} on any failure.
*
+ * @deprecated Using {@link #rebootModem()} instead.
+ *
* @hide
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
@@ -7726,6 +7735,30 @@
}
/**
+ * Generate a radio modem reset. Used for device configuration by some carriers.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ * @throws RuntimeException
+ */
+ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+ @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
+ public void rebootModem() {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony == null) {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ telephony.rebootModem(getSlotIndex());
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "rebootRadio RemoteException", ex);
+ throw ex.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
* Return an appropriate subscription ID for any situation.
*
* If this object has been created with {@link #createForSubscriptionId}, then the provided
diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java
index f614988..0a2bb3d 100644
--- a/telephony/java/android/telephony/euicc/EuiccCardManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java
@@ -118,6 +118,9 @@
/** Resets the default SM-DP+ address. */
public static final int RESET_OPTION_RESET_DEFAULT_SMDP_ADDRESS = 1 << 2;
+ /** Result code when the requested profile is not found */
+ public static final int RESULT_PROFILE_NOT_FOUND = 1;
+
/** Result code of execution with no error. */
public static final int RESULT_OK = 0;
@@ -130,9 +133,6 @@
/** Result code indicating the caller is not the active LPA. */
public static final int RESULT_CALLER_NOT_ALLOWED = -3;
- /** Result code when the requested profile is not found */
- public static final int RESULT_PROFILE_NOT_FOUND = -4;
-
/**
* Callback to receive the result of an eUICC card API.
*
@@ -223,7 +223,9 @@
}
/**
- * Requests the enabled profile for a given port on an eUicc.
+ * Requests the enabled profile for a given port on an eUicc. Callback with result code
+ * {@link RESULT_PROFILE_NOT_FOUND} and {@code NULL} EuiccProfile if there is no enabled
+ * profile on the target port.
*
* @param cardId The Id of the eUICC.
* @param portIndex The portIndex to use. The port may be active or inactive. As long as the
diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
index 0f1b369..51a3d72 100644
--- a/telephony/java/android/telephony/ims/RcsContactUceCapability.java
+++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
@@ -221,6 +221,15 @@
}
/**
+ * 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 @@
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 @@
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 @@
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 @@
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 @@
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/test-base/Android.bp b/test-base/Android.bp
index 8be7324..527159a 100644
--- a/test-base/Android.bp
+++ b/test-base/Android.bp
@@ -72,11 +72,16 @@
// 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 @@
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 fd8555c..0000000
--- 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 2a19af9..13a5dac 100644
--- a/test-runner/Android.bp
+++ b/test-runner/Android.bp
@@ -79,32 +79,6 @@
],
}
-// 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 f6f7913..0000000
--- 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/ActivityTests/src/com/google/android/test/activity/DisableScreenshotsActivity.java b/tests/ActivityTests/src/com/google/android/test/activity/DisableScreenshotsActivity.java
index fa5724e..ca909a4 100644
--- a/tests/ActivityTests/src/com/google/android/test/activity/DisableScreenshotsActivity.java
+++ b/tests/ActivityTests/src/com/google/android/test/activity/DisableScreenshotsActivity.java
@@ -30,7 +30,7 @@
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setDisablePreviewScreenshots(true);
+ setRecentsScreenshotEnabled(false);
getWindow().getDecorView().setBackgroundColor(Color.RED);
}
diff --git a/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryStatsHelperPerfTest.java b/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryStatsHelperPerfTest.java
deleted file mode 100644
index 6266cda..0000000
--- a/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryStatsHelperPerfTest.java
+++ /dev/null
@@ -1,135 +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 com.android.internal.os;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Context;
-import android.os.BatteryStats;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.perftests.utils.BenchmarkState;
-import android.perftests.utils.PerfStatusReporter;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@LargeTest
-public class BatteryStatsHelperPerfTest {
-
- @Rule
- public final PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
-
- /**
- * Measures the performance of {@link BatteryStatsHelper#getStats()}, which triggers
- * a battery stats sync on every iteration.
- */
- @Test
- public void testGetStats_forceUpdate() {
- final Context context = InstrumentationRegistry.getContext();
- final BatteryStatsHelper statsHelper = new BatteryStatsHelper(context,
- true /* collectBatteryBroadcast */);
- statsHelper.create((Bundle) null);
- statsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.myUserId());
-
- final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- while (state.keepRunning()) {
- state.pauseTiming();
- statsHelper.clearStats();
- state.resumeTiming();
-
- statsHelper.getStats();
-
- assertThat(statsHelper.getUsageList()).isNotEmpty();
- }
- }
-
- /**
- * Measures performance of the {@link BatteryStatsHelper#getStats(boolean)}, which does
- * not trigger a sync and just returns current values.
- */
- @Test
- public void testGetStats_cached() {
- final Context context = InstrumentationRegistry.getContext();
- final BatteryStatsHelper statsHelper = new BatteryStatsHelper(context,
- true /* collectBatteryBroadcast */);
- statsHelper.create((Bundle) null);
- statsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.myUserId());
-
- final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- while (state.keepRunning()) {
- state.pauseTiming();
- statsHelper.clearStats();
- state.resumeTiming();
-
- statsHelper.getStats(false /* forceUpdate */);
-
- assertThat(statsHelper.getUsageList()).isNotEmpty();
- }
- }
-
- @Test
- public void testPowerCalculation() {
- final Context context = InstrumentationRegistry.getContext();
- final BatteryStatsHelper statsHelper = new BatteryStatsHelper(context,
- true /* collectBatteryBroadcast */);
- statsHelper.create((Bundle) null);
- statsHelper.getStats();
-
- final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- while (state.keepRunning()) {
- // This will use the cached BatteryStatsObject
- statsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.myUserId());
-
- assertThat(statsHelper.getUsageList()).isNotEmpty();
- }
- }
-
- @Test
- public void testEndToEnd() {
- final Context context = InstrumentationRegistry.getContext();
- final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- while (state.keepRunning()) {
- final BatteryStatsHelper statsHelper = new BatteryStatsHelper(context,
- true /* collectBatteryBroadcast */);
- statsHelper.create((Bundle) null);
- statsHelper.clearStats();
- statsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.myUserId());
-
- state.pauseTiming();
-
- List<BatterySipper> usageList = statsHelper.getUsageList();
- double power = 0;
- for (int i = 0; i < usageList.size(); i++) {
- BatterySipper sipper = usageList.get(i);
- power += sipper.sumPower();
- }
-
- assertThat(power).isGreaterThan(0.0);
-
- state.resumeTiming();
- }
- }
-}
diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/Android.bp b/tests/Camera2Tests/SmartCamera/SimpleCamera/Android.bp
new file mode 100644
index 0000000..4fff969
--- /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 6003628..0000000
--- 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/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.bp b/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.bp
new file mode 100644
index 0000000..5edb1de
--- /dev/null
+++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.bp
@@ -0,0 +1,36 @@
+// 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-tests",
+ platform_apis: true,
+ srcs: ["src/**/*.java"],
+ 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 c23d593..0000000
--- 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 0000000..9883115
--- /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 b82ae65..0000000
--- 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/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index 294a220..a425ee0 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -142,7 +142,7 @@
@JvmStatic
fun getParams(): List<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
- .getConfigNonRotationTests(repetitions = 5)
+ .getConfigNonRotationTests(repetitions = 3)
}
}
}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
index 519bd56..a089261 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -157,7 +157,7 @@
@JvmStatic
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
- .getConfigNonRotationTests(repetitions = 5)
+ .getConfigNonRotationTests(repetitions = 3)
}
}
}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
index ca735031..8d60466 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
@@ -18,7 +18,6 @@
import android.app.Instrumentation
import android.platform.test.annotations.Presubmit
-import androidx.test.filters.FlakyTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerTestParameter
@@ -194,22 +193,4 @@
open fun launcherLayerReplacesApp() {
testSpec.replacesLayer(testApp.component, LAUNCHER_COMPONENT)
}
-
- @FlakyTest
- @Test
- fun runPresubmitAssertion() {
- flickerRule.checkPresubmitAssertions()
- }
-
- @FlakyTest
- @Test
- fun runPostsubmitAssertion() {
- flickerRule.checkPostsubmitAssertions()
- }
-
- @FlakyTest
- @Test
- fun runFlakyAssertion() {
- flickerRule.checkFlakyAssertions()
- }
-}
\ No newline at end of file
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
index c87d8e1..dd5f33f 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
@@ -170,7 +170,7 @@
@JvmStatic
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
- .getConfigNonRotationTests(repetitions = 5,
+ .getConfigNonRotationTests(repetitions = 3,
// b/190352379 (IME doesn't show on app launch in 90 degrees)
supportedRotations = listOf(Surface.ROTATION_0),
supportedNavigationModes = listOf(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
index 815ea77..5606965 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -178,7 +178,7 @@
@JvmStatic
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
- .getConfigNonRotationTests(repetitions = 5,
+ .getConfigNonRotationTests(repetitions = 3,
// b/190352379 (IME doesn't show on app launch in 90 degrees)
supportedRotations = listOf(Surface.ROTATION_0),
supportedNavigationModes = listOf(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
index 24b1598..e7a1c50 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
@@ -160,7 +160,7 @@
@JvmStatic
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
- .getConfigNonRotationTests(repetitions = 5)
+ .getConfigNonRotationTests(repetitions = 3)
}
}
}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index e5d82a1..b454f01 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -164,7 +164,7 @@
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
.getConfigNonRotationTests(
- repetitions = 5,
+ repetitions = 3,
supportedRotations = listOf(Surface.ROTATION_0),
supportedNavigationModes = listOf(
WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt
index 005c4f5..9643909 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt
@@ -140,7 +140,7 @@
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
.getConfigNonRotationTests(
- repetitions = 5,
+ repetitions = 3,
supportedRotations = listOf(Surface.ROTATION_0),
supportedNavigationModes = listOf(
WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
index 87f8ef2..8fcb4b7 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -152,7 +152,7 @@
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
.getConfigNonRotationTests(
- repetitions = 5,
+ repetitions = 3,
supportedRotations = listOf(Surface.ROTATION_0),
supportedNavigationModes = listOf(
WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
index 5e06f11..5f0176e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
@@ -238,7 +238,7 @@
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
.getConfigNonRotationTests(
- repetitions = 5,
+ repetitions = 3,
supportedRotations = listOf(Surface.ROTATION_0)
)
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
index 195af58..b5e13be 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
@@ -152,7 +152,7 @@
@JvmStatic
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
- .getConfigNonRotationTests(repetitions = 5)
+ .getConfigNonRotationTests(repetitions = 3)
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index 3a2eba1..797919b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -130,7 +130,7 @@
override fun appLayerBecomesVisible() = super.appLayerBecomesVisible_warmStart()
/** {@inheritDoc} */
- @Presubmit
+ @FlakyTest(bugId = 218624176)
@Test
override fun appWindowBecomesVisible() = super.appWindowBecomesVisible_warmStart()
@@ -149,6 +149,22 @@
super.appWindowReplacesLauncherAsTopWindow()
}
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ assumeFalse(isShellTransitionsEnabled)
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ }
+
+ /** {@inheritDoc} */
+ @FlakyTest(bugId = 218470989)
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry_shellTransit() {
+ assumeTrue(isShellTransitionsEnabled)
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ }
+
companion object {
/**
* Creates the test configurations.
@@ -160,7 +176,7 @@
@JvmStatic
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
- .getConfigNonRotationTests(repetitions = 5)
+ .getConfigNonRotationTests(repetitions = 3)
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
index 6365e7b..f75c50e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
@@ -160,7 +160,7 @@
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
.getConfigNonRotationTests(
- repetitions = 5,
+ repetitions = 3,
supportedNavigationModes =
listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY),
supportedRotations = listOf(Surface.ROTATION_0)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
index 882e128..04fdda4 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
@@ -244,7 +244,7 @@
@JvmStatic
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
- .getConfigNonRotationTests(repetitions = 5)
+ .getConfigNonRotationTests(repetitions = 3)
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
index 0a64939..5301e02 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
@@ -318,7 +318,7 @@
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
.getConfigNonRotationTests(
- repetitions = 5,
+ repetitions = 3,
supportedNavigationModes = listOf(
WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
),
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
index 42941c2..ce6a383 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
@@ -357,7 +357,7 @@
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
.getConfigNonRotationTests(
- repetitions = 5,
+ repetitions = 3,
supportedNavigationModes = listOf(
WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
),
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
index 8f2803e..1a762bf 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
@@ -333,7 +333,7 @@
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
.getConfigNonRotationTests(
- repetitions = 5,
+ repetitions = 3,
supportedNavigationModes = listOf(
WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
),
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index 3f0de7f..f603f6e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -25,11 +25,13 @@
import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.rules.WMFlickerServiceRuleForTestSpec
import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.common.FlickerComponentName
+import org.junit.Assume
import org.junit.FixMethodOrder
import org.junit.Rule
import org.junit.Test
@@ -94,24 +96,6 @@
}
}
- @FlakyTest
- @Test
- fun runPresubmitAssertion() {
- flickerRule.checkPresubmitAssertions()
- }
-
- @FlakyTest
- @Test
- fun runPostsubmitAssertion() {
- flickerRule.checkPostsubmitAssertions()
- }
-
- @FlakyTest
- @Test
- fun runFlakyAssertion() {
- flickerRule.checkFlakyAssertions()
- }
-
/**
* Windows maybe recreated when rotated. Checks that the focus does not change or if it does,
* focus returns to [testApp]
@@ -131,6 +115,7 @@
@Presubmit
@Test
fun rotationLayerAppearsAndVanishes() {
+ Assume.assumeFalse(isShellTransitionsEnabled)
testSpec.assertLayers {
this.isVisible(testApp.component)
.then()
@@ -141,6 +126,13 @@
}
}
+ @FlakyTest(bugId = 218484127)
+ @Test
+ fun rotationLayerAppearsAndVanishes_shellTransit() {
+ Assume.assumeTrue(isShellTransitionsEnabled)
+ rotationLayerAppearsAndVanishes()
+ }
+
/**
* Checks that the status bar window is visible and above the app windows in all WM
* trace entries
@@ -191,7 +183,7 @@
@JvmStatic
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
- .getConfigRotationTests(repetitions = 5)
+ .getConfigRotationTests(repetitions = 3)
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/values/styles.xml b/tests/FlickerTests/test-apps/flickerapp/res/values/styles.xml
index 746b0f4c..589df38 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/values/styles.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/values/styles.xml
@@ -16,15 +16,19 @@
-->
<resources>
- <style name="CutoutDefault">
+ <style name="DefaultTheme" parent="@android:style/Theme.DeviceDefault">
+ <item name="android:windowBackground">@android:color/darker_gray</item>
+ </style>
+
+ <style name="CutoutDefault" parent="@style/DefaultTheme">
<item name="android:windowLayoutInDisplayCutoutMode">default</item>
</style>
- <style name="CutoutShortEdges">
+ <style name="CutoutShortEdges" parent="@style/DefaultTheme">
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
</style>
- <style name="CutoutNever">
+ <style name="CutoutNever" parent="@style/DefaultTheme">
<item name="android:windowLayoutInDisplayCutoutMode">never</item>
</style>
diff --git a/tests/HandwritingIme/Android.bp b/tests/HandwritingIme/Android.bp
new file mode 100644
index 0000000..1f552bf
--- /dev/null
+++ b/tests/HandwritingIme/Android.bp
@@ -0,0 +1,35 @@
+// 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 {
+ // 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"],
+}
+
+android_test {
+ name: "HandwritingIme",
+ srcs: ["src/**/*.java"],
+ resource_dirs: ["res"],
+ certificate: "platform",
+ platform_apis: true,
+ static_libs: [
+ "androidx.core_core",
+ "androidx.appcompat_appcompat",
+ "com.google.android.material_material",
+ ],
+}
diff --git a/tests/HandwritingIme/AndroidManifest.xml b/tests/HandwritingIme/AndroidManifest.xml
new file mode 100644
index 0000000..1445d95
--- /dev/null
+++ b/tests/HandwritingIme/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (018C) 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
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.google.android.test.handwritingime">
+
+ <application android:label="Handwriting IME">
+ <service android:name=".HandwritingIme"
+ android:process=":HandwritingIme"
+ android:label="Handwriting IME"
+ android:permission="android.permission.BIND_INPUT_METHOD"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.view.InputMethod"/>
+ </intent-filter>
+ <meta-data android:name="android.view.im"
+ android:resource="@xml/ime"/>
+ </service>
+
+ </application>
+</manifest>
diff --git a/packages/SystemUI/res/layout/qs_detail_switch.xml b/tests/HandwritingIme/res/xml/ime.xml
similarity index 62%
copy from packages/SystemUI/res/layout/qs_detail_switch.xml
copy to tests/HandwritingIme/res/xml/ime.xml
index abb2497..2e84a03 100644
--- a/packages/SystemUI/res/layout/qs_detail_switch.xml
+++ b/tests/HandwritingIme/res/xml/ime.xml
@@ -1,5 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 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,10 +15,6 @@
~ limitations under the License.
-->
-<Switch
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/toggle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:clickable="false"
- android:textAppearance="@style/TextAppearance.QS.DetailHeader" />
\ No newline at end of file
+<!-- Configuration info for an input method -->
+<input-method xmlns:android="http://schemas.android.com/apk/res/android"
+ android:supportsStylusHandwriting="true"/>
\ No newline at end of file
diff --git a/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java b/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java
new file mode 100644
index 0000000..18f9623
--- /dev/null
+++ b/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java
@@ -0,0 +1,111 @@
+/*
+ * 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.google.android.test.handwritingime;
+
+import android.annotation.Nullable;
+import android.inputmethodservice.InputMethodService;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.FrameLayout;
+import android.widget.Toast;
+
+import java.util.Random;
+
+public class HandwritingIme extends InputMethodService {
+
+ public static final int HEIGHT_DP = 100;
+
+ private Window mInkWindow;
+ private InkView mInk;
+
+ static final String TAG = "HandwritingIme";
+
+ interface HandwritingFinisher {
+ void finish();
+ }
+
+ interface StylusListener {
+ void onStylusEvent(MotionEvent me);
+ }
+
+ final class StylusConsumer implements StylusListener {
+ @Override
+ public void onStylusEvent(MotionEvent me) {
+ HandwritingIme.this.onStylusEvent(me);
+ }
+ }
+
+ final class HandwritingFinisherImpl implements HandwritingFinisher {
+
+ HandwritingFinisherImpl() {}
+
+ @Override
+ public void finish() {
+ finishStylusHandwriting();
+ Log.d(TAG, "HandwritingIme called finishStylusHandwriting() ");
+ }
+ }
+
+ private void onStylusEvent(@Nullable MotionEvent event) {
+ // TODO Hookup recognizer here
+ if (event.getAction() == MotionEvent.ACTION_UP) {
+ sendKeyChar((char) (56 + new Random().nextInt(66)));
+ }
+ }
+
+ @Override
+ public View onCreateInputView() {
+ Log.d(TAG, "onCreateInputView");
+ final ViewGroup view = new FrameLayout(this);
+ final View inner = new View(this);
+ final float density = getResources().getDisplayMetrics().density;
+ final int height = (int) (HEIGHT_DP * density);
+ view.setPadding(0, 0, 0, 0);
+ view.addView(inner, new FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT, height));
+ inner.setBackgroundColor(0xff0110fe); // blue
+
+ return view;
+ }
+
+ public void onPrepareStylusHandwriting() {
+ Log.d(TAG, "onPrepareStylusHandwriting ");
+ if (mInk == null) {
+ mInk = new InkView(this, new HandwritingFinisherImpl(), new StylusConsumer());
+ }
+ }
+
+ @Override
+ public boolean onStartStylusHandwriting() {
+ Log.d(TAG, "onStartStylusHandwriting ");
+ Toast.makeText(this, "START HW", Toast.LENGTH_SHORT).show();
+ mInkWindow = getStylusHandwritingWindow();
+ mInkWindow.setContentView(mInk, mInk.getLayoutParams());
+ return true;
+ }
+
+ @Override
+ public void onFinishStylusHandwriting() {
+ Log.d(TAG, "onFinishStylusHandwriting ");
+ Toast.makeText(this, "Finish HW", Toast.LENGTH_SHORT).show();
+ // Free-up
+ ((ViewGroup) mInk.getParent()).removeView(mInk);
+ mInk = null;
+ }
+}
diff --git a/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java b/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java
new file mode 100644
index 0000000..4ffdc92
--- /dev/null
+++ b/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java
@@ -0,0 +1,164 @@
+/*
+ * 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.google.android.test.handwritingime;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Insets;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+import android.view.WindowMetrics;
+
+class InkView extends View {
+ private static final long FINISH_TIMEOUT = 2500;
+ private final HandwritingIme.HandwritingFinisher mHwCanceller;
+ private final HandwritingIme.StylusConsumer mConsumer;
+ private Paint mPaint;
+ private Path mPath;
+ private float mX, mY;
+ private static final float STYLUS_MOVE_TOLERANCE = 1;
+ private Runnable mFinishRunnable;
+
+ InkView(Context context, HandwritingIme.HandwritingFinisher hwController,
+ HandwritingIme.StylusConsumer consumer) {
+ super(context);
+ mHwCanceller = hwController;
+ mConsumer = consumer;
+
+ mPaint = new Paint();
+ mPaint.setAntiAlias(true);
+ mPaint.setDither(true);
+ mPaint.setColor(Color.GREEN);
+ mPaint.setStyle(Paint.Style.STROKE);
+ mPaint.setStrokeJoin(Paint.Join.ROUND);
+ mPaint.setStrokeCap(Paint.Cap.ROUND);
+ mPaint.setStrokeWidth(14);
+
+ mPath = new Path();
+
+ WindowManager wm = context.getSystemService(WindowManager.class);
+ WindowMetrics metrics = wm.getCurrentWindowMetrics();
+ Insets insets = metrics.getWindowInsets()
+ .getInsetsIgnoringVisibility(WindowInsets.Type.systemBars());
+ setLayoutParams(new ViewGroup.LayoutParams(
+ metrics.getBounds().width() - insets.left - insets.right,
+ metrics.getBounds().height() - insets.top - insets.bottom));
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ canvas.drawPath(mPath, mPaint);
+ canvas.drawARGB(20, 255, 50, 50);
+ }
+
+ private void stylusStart(float x, float y) {
+ mPath.moveTo(x, y);
+ mX = x;
+ mY = y;
+ }
+
+ private void stylusMove(float x, float y) {
+ float dx = Math.abs(x - mX);
+ float dy = Math.abs(y - mY);
+ if (mPath.isEmpty()) {
+ stylusStart(x, y);
+ }
+ if (dx >= STYLUS_MOVE_TOLERANCE || dy >= STYLUS_MOVE_TOLERANCE) {
+ mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
+ mX = x;
+ mY = y;
+ }
+ }
+
+ private void stylusFinish() {
+ mPath.lineTo(mX, mY);
+ // TODO: support offscreen? e.g. mCanvas.drawPath(mPath, mPaint);
+ mPath.reset();
+ mX = 0;
+ mY = 0;
+
+ }
+
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (event.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS) {
+ mConsumer.onStylusEvent(event);
+ android.util.Log.w(HandwritingIme.TAG, "INK touch onStylusEvent " + event);
+ float x = event.getX();
+ float y = event.getY();
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ cancelTimer();
+ stylusStart(x, y);
+ invalidate();
+ break;
+ case MotionEvent.ACTION_MOVE:
+ stylusMove(x, y);
+ invalidate();
+ break;
+
+ case MotionEvent.ACTION_UP:
+ scheduleTimer();
+ break;
+
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private void cancelTimer() {
+ if (mFinishRunnable != null) {
+ if (getHandler() != null) {
+ getHandler().removeCallbacks(mFinishRunnable);
+ }
+ mFinishRunnable = null;
+ }
+ if (getHandler() != null) {
+ getHandler().removeCallbacksAndMessages(null);
+ }
+ }
+
+ private void scheduleTimer() {
+ cancelTimer();
+ if (getHandler() != null) {
+ postDelayed(getFinishRunnable(), FINISH_TIMEOUT);
+ }
+ }
+
+ private Runnable getFinishRunnable() {
+ mFinishRunnable = () -> {
+ android.util.Log.e(HandwritingIme.TAG, "Hw view timer finishHandwriting ");
+ mHwCanceller.finish();
+ stylusFinish();
+ mPath.reset();
+ invalidate();
+ };
+
+ return mFinishRunnable;
+ }
+
+}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index bb4866f..4cddcfe 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -171,9 +171,8 @@
@Test
public void testRollbackApexWithApkCrashing_Phase1_Install() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
- int sessionId = Install.single(TEST_APEX_WITH_APK_V2_CRASHING).setStaged()
+ Install.single(TEST_APEX_WITH_APK_V2_CRASHING).setStaged()
.setEnableRollback().commit();
- InstallUtils.waitForSessionReady(sessionId);
}
/**
diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp
index 7906f09..cce0dde 100644
--- a/tests/StagedInstallTest/Android.bp
+++ b/tests/StagedInstallTest/Android.bp
@@ -62,6 +62,7 @@
":TestAppAv1",
":test.rebootless_apex_v1",
":test.rebootless_apex_v2",
+ ":test_com.android.server",
],
test_suites: ["general-tests"],
test_config: "StagedInstallInternalTest.xml",
diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
index 426f3be..7490d3f 100644
--- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
@@ -17,7 +17,6 @@
package com.android.tests.stagedinstallinternal;
import static com.android.cts.install.lib.InstallUtils.getPackageInstaller;
-import static com.android.cts.install.lib.InstallUtils.waitForSessionReady;
import static com.android.cts.shim.lib.ShimPackage.SHIM_APEX_PACKAGE_NAME;
import static com.google.common.truth.Truth.assertThat;
@@ -35,6 +34,7 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.ApplicationInfoFlags;
import android.content.pm.StagedApexInfo;
import android.os.IBinder;
import android.os.ServiceManager;
@@ -80,6 +80,8 @@
TEST_APEX_PACKAGE_NAME, 1, /*isApex=*/true,
"apex.apexd_test_classpath.apex");
+ private static final String TEST_APEX_SYSTEM_SERVER_PACKAGE_NAME = "test_com.android.server";
+
private File mTestStateFile = new File(
InstrumentationRegistry.getInstrumentation().getContext().getFilesDir(),
"stagedinstall_state");
@@ -458,7 +460,6 @@
assertThat(result).hasLength(0);
// Stage an apex
int sessionId = Install.single(APEX_V2).setStaged().commit();
- waitForSessionReady(sessionId);
result = getPackageManagerNative().getStagedApexModuleNames();
assertThat(result).hasLength(1);
assertThat(result).isEqualTo(new String[]{SHIM_APEX_PACKAGE_NAME});
@@ -475,7 +476,6 @@
assertThat(result).isNull();
// Stage an apex
int sessionId = Install.single(TEST_APEX_CLASSPATH).setStaged().commit();
- waitForSessionReady(sessionId);
// Query proper module name
result = getPackageManagerNative().getStagedApexInfo(TEST_APEX_PACKAGE_NAME);
assertThat(result.moduleName).isEqualTo(TEST_APEX_PACKAGE_NAME);
@@ -483,6 +483,16 @@
InstallUtils.openPackageInstallerSession(sessionId).abandon();
}
+ @Test
+ public void testGetAppInfo_flagTestOnlyIsSet() throws Exception {
+ final PackageManager pm =
+ InstrumentationRegistry.getInstrumentation().getContext().getPackageManager();
+ final ApplicationInfo info = pm.getApplicationInfo(TEST_APEX_SYSTEM_SERVER_PACKAGE_NAME,
+ ApplicationInfoFlags.of(PackageManager.MATCH_APEX));
+ assertThat(info).isNotNull();
+ assertThat((info.flags & ApplicationInfo.FLAG_TEST_ONLY) != 0).isTrue();
+ }
+
public static class MockStagedApexObserver extends IStagedApexObserver.Stub {
@Override
public void onApexStaged(ApexStagedEvent event) {
@@ -499,7 +509,6 @@
// Stage an apex and verify observer was called
int sessionId = Install.single(APEX_V2).setStaged().commit();
- waitForSessionReady(sessionId);
ArgumentCaptor<ApexStagedEvent> captor = ArgumentCaptor.forClass(ApexStagedEvent.class);
verify(observer, timeout(5000)).onApexStaged(captor.capture());
assertThat(captor.getValue().stagedApexModuleNames).isEqualTo(
diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
index f06fa81e..f60b4d6 100644
--- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
@@ -62,6 +62,7 @@
private static final String APK_A = "TestAppAv1.apk";
private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test";
private static final String APEXD_TEST_APEX = "apex.apexd_test.apex";
+ private static final String FAKE_APEX_SYSTEM_SERVER_APEX = "test_com.android.server.apex";
private static final String TEST_VENDOR_APEX_ALLOW_LIST =
"/vendor/etc/sysconfig/test-vendor-apex-allow-list.xml";
@@ -513,6 +514,18 @@
}
@Test
+ @LargeTest
+ public void testGetAppInfo_flagTestOnlyIsSet() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ pushTestApex(FAKE_APEX_SYSTEM_SERVER_APEX);
+ getDevice().reboot();
+
+ runPhase("testGetAppInfo_flagTestOnlyIsSet");
+ }
+
+ @Test
public void testStagedApexObserver() throws Exception {
assumeTrue("Device does not support updating APEX",
mHostUtils.isApexUpdateSupported());
diff --git a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
index 824f91e..15a6afc 100644
--- a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
+++ b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
@@ -62,6 +62,7 @@
"android.view.PendingInsetsControllerTest",
"android.window.", // all tests under the package.
"android.app.activity.ActivityThreadTest",
+ "android.app.activity.RegisterComponentCallbacksTest"
};
public FrameworksTestsFilter(Bundle testArgs) {
diff --git a/tools/streaming_proto/Android.bp b/tools/streaming_proto/Android.bp
index 1ec83a3..b18bdff 100644
--- a/tools/streaming_proto/Android.bp
+++ b/tools/streaming_proto/Android.bp
@@ -69,7 +69,6 @@
"test/**/*.proto",
],
proto: {
- plugin: "javastream",
+ type: "stream",
},
- static_libs: ["libprotobuf-java-lite"],
}
diff --git a/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java b/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
index d3eb8e0..9604475 100644
--- a/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
+++ b/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
@@ -1269,18 +1269,19 @@
* support the NL80211_CMD_REG_CHANGED (otherwise it will find out on its own). The wificond
* updates in internal state in response to this Country Code update.
*
- * @return true on success, false otherwise.
+ * @param newCountryCode new country code. An ISO-3166-alpha2 country code which is 2-Character
+ * alphanumeric.
*/
- public boolean notifyCountryCodeChanged() {
- try {
- if (mWificond != null) {
- mWificond.notifyCountryCodeChanged();
- return true;
- }
- } catch (RemoteException e1) {
- Log.e(TAG, "Failed to notify country code changed due to remote exception");
+ public void notifyCountryCodeChanged(@Nullable String newCountryCode) {
+ if (mWificond == null) {
+ new RemoteException("Wificond service doesn't exist!").rethrowFromSystemServer();
}
- return false;
+ try {
+ mWificond.notifyCountryCodeChanged();
+ Log.i(TAG, "Receive country code change to " + newCountryCode);
+ } catch (RemoteException re) {
+ re.rethrowFromSystemServer();
+ }
}
/**
diff --git a/wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java b/wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java
index 4032a7b..a750696 100644
--- a/wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java
@@ -1143,17 +1143,17 @@
@Test
public void testNotifyCountryCodeChanged() throws Exception {
doNothing().when(mWificond).notifyCountryCodeChanged();
- assertTrue(mWificondControl.notifyCountryCodeChanged());
+ mWificondControl.notifyCountryCodeChanged(TEST_COUNTRY_CODE);
verify(mWificond).notifyCountryCodeChanged();
}
/**
* Tests notifyCountryCodeChanged with RemoteException
*/
- @Test
+ @Test(expected = RuntimeException.class)
public void testNotifyCountryCodeChangedRemoteException() throws Exception {
doThrow(new RemoteException()).when(mWificond).notifyCountryCodeChanged();
- assertFalse(mWificondControl.notifyCountryCodeChanged());
+ mWificondControl.notifyCountryCodeChanged(TEST_COUNTRY_CODE);
verify(mWificond).notifyCountryCodeChanged();
}