Merge "Remote authenticator settings layout." into main
diff --git a/Android.bp b/Android.bp
index 861f95f..e3f68e1 100644
--- a/Android.bp
+++ b/Android.bp
@@ -55,6 +55,7 @@
],
srcs: ["src/**/*.java", "src/**/*.kt"],
+ use_resource_processor: true,
resource_dirs: [
"res",
"res-export", // for external usage
@@ -136,6 +137,7 @@
],
static_libs: ["Settings-core"],
uses_libs: ["org.apache.http.legacy"],
+ use_resource_processor: true,
resource_dirs: [],
optimize: {
proguard_flags_files: ["proguard.flags"],
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 79a7171..a8adf7c 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -33,6 +33,7 @@
<uses-permission android:name="android.permission.HARDWARE_TEST" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
+ <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED" />
<uses-permission android:name="android.permission.QUERY_AUDIO_STATE" />
<uses-permission android:name="android.permission.MASTER_CLEAR" />
<uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH" />
@@ -4681,6 +4682,16 @@
</activity>
<activity
+ android:name=".wifi.dpp.WifiDppConfiguratorAuthActivity"
+ android:theme="@style/Transparent"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.settings.WIFI_DPP_CONFIGURATOR_AUTH_QR_CODE_GENERATOR"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+ </activity>
+
+ <activity
android:name=".wifi.dpp.WifiDppEnrolleeActivity"
android:exported="true">
<intent-filter>
diff --git a/res/drawable-night/ic_app_aspect_ratio_16_9.xml b/res/drawable-night/ic_app_aspect_ratio_16_9.xml
new file mode 100644
index 0000000..069003e
--- /dev/null
+++ b/res/drawable-night/ic_app_aspect_ratio_16_9.xml
@@ -0,0 +1,66 @@
+<!--
+ ~ Copyright (C) 2023 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="412dp"
+ android:height="300dp"
+ android:viewportWidth="412"
+ android:viewportHeight="300">
+ <group>
+ <clip-path
+ android:pathData="M0,0h412v300h-412z"/>
+ <path
+ android:pathData="M384.18,300H27.82C12.53,300 0,287.17 0,271.52V28.48C0,12.83 12.53,0 27.82,0H384.29C399.47,0 412,12.83 412,28.48V271.63C412,287.17 399.47,300 384.18,300Z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M321.83,134.76V134C322.96,133.96 323.87,132.78 323.87,131.32V116.86C323.87,115.4 322.96,114.22 321.83,114.18V58.55C321.83,52.85 317.2,48.22 311.49,48.22H213.79C211.62,48.22 209.49,48.77 207.6,49.82C206.71,50.18 205.73,50.18 204.85,49.83L204.81,49.82C202.92,48.77 200.79,48.22 198.62,48.22H101.22C95.51,48.22 90.88,52.85 90.88,58.55V242.05C90.88,247.76 95.51,252.38 101.22,252.38H198.84C201,252.38 203.13,251.83 205.03,250.78C205.86,250.45 206.78,250.44 207.63,250.73L207.73,250.78C209.62,251.83 213.04,252.38 215.2,252.38H311.49C317.2,252.38 321.83,247.76 321.83,242.05V181.69C322.96,181.65 323.87,180.47 323.87,179.01V152.1C323.87,150.65 322.96,149.46 321.83,149.43V134.76ZM319.45,242.43C319.45,246.61 315.67,250.01 311.49,250.01H101.22C97.04,250.01 93.26,246.61 93.26,242.43V58.55C93.26,54.38 97.04,50.6 101.22,50.6H311.49C315.67,50.6 319.45,54.38 319.45,58.55V242.43Z"
+ android:fillColor="#80868B"/>
+ <path
+ android:pathData="M155,53L259,53A4,4 0,0 1,263 57L263,243A4,4 0,0 1,259 247L155,247A4,4 0,0 1,151 243L151,57A4,4 0,0 1,155 53z"
+ android:fillColor="#669DF6"/>
+ <path
+ android:pathData="M157,57L257,57A2,2 0,0 1,259 59L259,241A2,2 0,0 1,257 243L157,243A2,2 0,0 1,155 241L155,59A2,2 0,0 1,157 57z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M171.48,237H161V226.42"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#669DF6"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M161,237L176,222"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#669DF6"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M242.52,63L253,63L253,73.58"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#669DF6"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M253,63L238,78"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#669DF6"
+ android:strokeLineCap="round"/>
+ </group>
+</vector>
diff --git a/res/drawable-night/ic_app_aspect_ratio_3_2.xml b/res/drawable-night/ic_app_aspect_ratio_3_2.xml
new file mode 100644
index 0000000..22c0969
--- /dev/null
+++ b/res/drawable-night/ic_app_aspect_ratio_3_2.xml
@@ -0,0 +1,66 @@
+<!--
+ ~ Copyright (C) 2023 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="412dp"
+ android:height="300dp"
+ android:viewportWidth="412"
+ android:viewportHeight="300">
+ <group>
+ <clip-path
+ android:pathData="M0,0h412v300h-412z"/>
+ <path
+ android:pathData="M384.18,300H27.82C12.53,300 0,287.17 0,271.52V28.48C0,12.83 12.53,0 27.82,0H384.29C399.47,0 412,12.83 412,28.48V271.63C412,287.17 399.47,300 384.18,300Z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M321.83,134.76V134C322.96,133.96 323.87,132.78 323.87,131.32V116.86C323.87,115.4 322.96,114.22 321.83,114.18V58.55C321.83,52.85 317.2,48.22 311.49,48.22H213.79C211.62,48.22 209.49,48.77 207.6,49.82C206.71,50.18 205.73,50.18 204.85,49.83L204.81,49.82C202.92,48.77 200.79,48.22 198.62,48.22H101.22C95.51,48.22 90.88,52.85 90.88,58.55V242.05C90.88,247.76 95.51,252.38 101.22,252.38H198.84C201,252.38 203.13,251.83 205.03,250.78C205.86,250.45 206.78,250.44 207.63,250.73L207.73,250.78C209.62,251.83 213.04,252.38 215.2,252.38H311.49C317.2,252.38 321.83,247.76 321.83,242.05V181.69C322.96,181.65 323.87,180.47 323.87,179.01V152.1C323.87,150.65 322.96,149.46 321.83,149.43V134.76ZM319.45,242.43C319.45,246.61 315.67,250.01 311.49,250.01H101.22C97.04,250.01 93.26,246.61 93.26,242.43V58.55C93.26,54.38 97.04,50.6 101.22,50.6H311.49C315.67,50.6 319.45,54.38 319.45,58.55V242.43Z"
+ android:fillColor="#80868B"/>
+ <path
+ android:pathData="M144,53L268,53A4,4 0,0 1,272 57L272,243A4,4 0,0 1,268 247L144,247A4,4 0,0 1,140 243L140,57A4,4 0,0 1,144 53z"
+ android:fillColor="#669DF6"/>
+ <path
+ android:pathData="M146,57L266,57A2,2 0,0 1,268 59L268,241A2,2 0,0 1,266 243L146,243A2,2 0,0 1,144 241L144,59A2,2 0,0 1,146 57z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M160.48,237H150V226.42"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#669DF6"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M150,237L165,222"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#669DF6"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M251.52,63L262,63L262,73.58"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#669DF6"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M262,63L247,78"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#669DF6"
+ android:strokeLineCap="round"/>
+ </group>
+</vector>
diff --git a/res/drawable-night/ic_app_aspect_ratio_4_3.xml b/res/drawable-night/ic_app_aspect_ratio_4_3.xml
new file mode 100644
index 0000000..0238311
--- /dev/null
+++ b/res/drawable-night/ic_app_aspect_ratio_4_3.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 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="412dp"
+ android:height="300dp"
+ android:viewportWidth="412"
+ android:viewportHeight="300">
+ <group>
+ <clip-path
+ android:pathData="M0,0h412v300h-412z"/>
+ <path
+ android:pathData="M384.18,300H27.82C12.53,300 0,287.17 0,271.52V28.48C0,12.83 12.53,0 27.82,0H384.29C399.47,0 412,12.83 412,28.48V271.63C412,287.17 399.47,300 384.18,300Z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M321.83,134.76V134C322.96,133.96 323.87,132.78 323.87,131.32V116.86C323.87,115.4 322.96,114.22 321.83,114.18V58.55C321.83,52.85 317.2,48.22 311.49,48.22H213.79C211.62,48.22 209.49,48.77 207.6,49.82C206.71,50.18 205.73,50.18 204.85,49.83L204.81,49.82C202.92,48.77 200.79,48.22 198.62,48.22H101.22C95.51,48.22 90.88,52.85 90.88,58.55V242.05C90.88,247.76 95.51,252.38 101.22,252.38H198.84C201,252.38 203.13,251.83 205.03,250.78C205.86,250.45 206.78,250.44 207.63,250.73L207.73,250.78C209.62,251.83 213.04,252.38 215.2,252.38H311.49C317.2,252.38 321.83,247.76 321.83,242.05V181.69C322.96,181.65 323.87,180.47 323.87,179.01V152.1C323.87,150.65 322.96,149.46 321.83,149.43V134.76ZM319.45,242.43C319.45,246.61 315.67,250.01 311.49,250.01H101.22C97.04,250.01 93.26,246.61 93.26,242.43V58.55C93.26,54.38 97.04,50.6 101.22,50.6H311.49C315.67,50.6 319.45,54.38 319.45,58.55V242.43Z"
+ android:fillColor="#80868B"/>
+ <path
+ android:pathData="M136,53L276,53A4,4 0,0 1,280 57L280,243A4,4 0,0 1,276 247L136,247A4,4 0,0 1,132 243L132,57A4,4 0,0 1,136 53z"
+ android:fillColor="#669DF6"/>
+ <path
+ android:pathData="M138,57L274,57A2,2 0,0 1,276 59L276,241A2,2 0,0 1,274 243L138,243A2,2 0,0 1,136 241L136,59A2,2 0,0 1,138 57z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M152.48,237H142V226.42"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#669DF6"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M142,237L157,222"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#669DF6"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M259.52,63L270,63L270,73.58"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#669DF6"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M270,63L255,78"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#669DF6"
+ android:strokeLineCap="round"/>
+ </group>
+</vector>
diff --git a/res/drawable-night/ic_app_aspect_ratio_display_size.xml b/res/drawable-night/ic_app_aspect_ratio_display_size.xml
new file mode 100644
index 0000000..91626d7
--- /dev/null
+++ b/res/drawable-night/ic_app_aspect_ratio_display_size.xml
@@ -0,0 +1,66 @@
+<!--
+ ~ Copyright (C) 2023 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="412dp"
+ android:height="300dp"
+ android:viewportWidth="412"
+ android:viewportHeight="300">
+ <group>
+ <clip-path
+ android:pathData="M0,0h412v300h-412z"/>
+ <path
+ android:pathData="M384.18,300H27.82C12.53,300 0,287.17 0,271.52V28.48C0,12.83 12.53,0 27.82,0H384.29C399.47,0 412,12.83 412,28.48V271.63C412,287.17 399.47,300 384.18,300Z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M321.83,134.76V134C322.96,133.96 323.87,132.78 323.87,131.32V116.86C323.87,115.4 322.96,114.22 321.83,114.18V58.55C321.83,52.85 317.2,48.22 311.49,48.22H213.79C211.62,48.22 209.49,48.77 207.6,49.82C206.71,50.18 205.73,50.18 204.85,49.83L204.81,49.82C202.92,48.77 200.79,48.22 198.62,48.22H101.22C95.51,48.22 90.88,52.85 90.88,58.55V242.05C90.88,247.76 95.51,252.38 101.22,252.38H198.84C201,252.38 203.13,251.83 205.03,250.78C205.86,250.45 206.78,250.44 207.63,250.73L207.73,250.78C209.62,251.83 213.04,252.38 215.2,252.38H311.49C317.2,252.38 321.83,247.76 321.83,242.05V181.69C322.96,181.65 323.87,180.47 323.87,179.01V152.1C323.87,150.65 322.96,149.46 321.83,149.43V134.76ZM319.45,242.43C319.45,246.61 315.67,250.01 311.49,250.01H101.22C97.04,250.01 93.26,246.61 93.26,242.43V58.55C93.26,54.38 97.04,50.6 101.22,50.6H311.49C315.67,50.6 319.45,54.38 319.45,58.55V242.43Z"
+ android:fillColor="#80868B"/>
+ <path
+ android:pathData="M128,53L284,53A4,4 0,0 1,288 57L288,243A4,4 0,0 1,284 247L128,247A4,4 0,0 1,124 243L124,57A4,4 0,0 1,128 53z"
+ android:fillColor="#669DF6"/>
+ <path
+ android:pathData="M130,57L282,57A2,2 0,0 1,284 59L284,241A2,2 0,0 1,282 243L130,243A2,2 0,0 1,128 241L128,59A2,2 0,0 1,130 57z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M144.48,237H134V226.42"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#669DF6"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M134,237L149,222"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#669DF6"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M267.52,63L278,63L278,73.58"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#669DF6"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M278,63L263,78"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#669DF6"
+ android:strokeLineCap="round"/>
+ </group>
+</vector>
diff --git a/res/drawable-night/ic_app_aspect_ratio_fullscreen.xml b/res/drawable-night/ic_app_aspect_ratio_fullscreen.xml
new file mode 100644
index 0000000..aecc8f0
--- /dev/null
+++ b/res/drawable-night/ic_app_aspect_ratio_fullscreen.xml
@@ -0,0 +1,66 @@
+<!--
+ ~ Copyright (C) 2023 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="412dp"
+ android:height="300dp"
+ android:viewportWidth="412"
+ android:viewportHeight="300">
+ <group>
+ <clip-path
+ android:pathData="M0,0h412v300h-412z"/>
+ <path
+ android:pathData="M384.18,300H27.82C12.53,300 0,287.17 0,271.52V28.48C0,12.83 12.53,0 27.82,0H384.29C399.47,0 412,12.83 412,28.48V271.63C412,287.17 399.47,300 384.18,300Z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M321.83,134.76V134C322.96,133.96 323.87,132.78 323.87,131.32V116.86C323.87,115.4 322.96,114.22 321.83,114.18V58.55C321.83,52.85 317.2,48.22 311.49,48.22H213.79C211.62,48.22 209.49,48.77 207.6,49.82C206.71,50.18 205.73,50.18 204.85,49.83L204.81,49.82C202.92,48.77 200.79,48.22 198.62,48.22H101.22C95.51,48.22 90.88,52.85 90.88,58.55V242.05C90.88,247.76 95.51,252.38 101.22,252.38H198.84C201,252.38 203.13,251.83 205.03,250.78C205.86,250.45 206.78,250.44 207.63,250.73L207.73,250.78C209.62,251.83 213.04,252.38 215.2,252.38H311.49C317.2,252.38 321.83,247.76 321.83,242.05V181.69C322.96,181.65 323.87,180.47 323.87,179.01V152.1C323.87,150.65 322.96,149.46 321.83,149.43V134.76ZM319.45,242.43C319.45,246.61 315.67,250.01 311.49,250.01H101.22C97.04,250.01 93.26,246.61 93.26,242.43V58.55C93.26,54.38 97.04,50.6 101.22,50.6H311.49C315.67,50.6 319.45,54.38 319.45,58.55V242.43Z"
+ android:fillColor="#80868B"/>
+ <path
+ android:pathData="M100,53L312,53A4,4 0,0 1,316 57L316,243A4,4 0,0 1,312 247L100,247A4,4 0,0 1,96 243L96,57A4,4 0,0 1,100 53z"
+ android:fillColor="#669DF6"/>
+ <path
+ android:pathData="M102,57L310,57A2,2 0,0 1,312 59L312,241A2,2 0,0 1,310 243L102,243A2,2 0,0 1,100 241L100,59A2,2 0,0 1,102 57z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M116.48,237H106V226.42"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#669DF6"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M106,237L121,222"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#669DF6"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M295.52,63L306,63L306,73.58"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#669DF6"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M306,63L291,78"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#669DF6"
+ android:strokeLineCap="round"/>
+ </group>
+</vector>
diff --git a/res/drawable-night/ic_app_aspect_ratio_half_screen.xml b/res/drawable-night/ic_app_aspect_ratio_half_screen.xml
new file mode 100644
index 0000000..af533ea
--- /dev/null
+++ b/res/drawable-night/ic_app_aspect_ratio_half_screen.xml
@@ -0,0 +1,66 @@
+<!--
+ ~ Copyright (C) 2023 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="412dp"
+ android:height="300dp"
+ android:viewportWidth="412"
+ android:viewportHeight="300">
+ <group>
+ <clip-path
+ android:pathData="M0,0h412v300h-412z"/>
+ <path
+ android:pathData="M384.18,300H27.82C12.53,300 0,287.17 0,271.52V28.48C0,12.83 12.53,0 27.82,0H384.29C399.47,0 412,12.83 412,28.48V271.63C412,287.17 399.47,300 384.18,300Z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M321.83,134.76V134C322.96,133.96 323.87,132.78 323.87,131.32V116.86C323.87,115.4 322.96,114.22 321.83,114.18V58.55C321.83,52.85 317.2,48.22 311.49,48.22H213.79C211.62,48.22 209.49,48.77 207.6,49.82C206.71,50.18 205.73,50.18 204.85,49.83L204.81,49.82C202.92,48.77 200.79,48.22 198.62,48.22H101.22C95.51,48.22 90.88,52.85 90.88,58.55V242.05C90.88,247.76 95.51,252.38 101.22,252.38H198.84C201,252.38 203.13,251.83 205.03,250.78C205.86,250.45 206.78,250.44 207.63,250.73L207.73,250.78C209.62,251.83 213.04,252.38 215.2,252.38H311.49C317.2,252.38 321.83,247.76 321.83,242.05V181.69C322.96,181.65 323.87,180.47 323.87,179.01V152.1C323.87,150.65 322.96,149.46 321.83,149.43V134.76ZM319.45,242.43C319.45,246.61 315.67,250.01 311.49,250.01H101.22C97.04,250.01 93.26,246.61 93.26,242.43V58.55C93.26,54.38 97.04,50.6 101.22,50.6H311.49C315.67,50.6 319.45,54.38 319.45,58.55V242.43Z"
+ android:fillColor="#80868B"/>
+ <path
+ android:pathData="M148,53L264,53A4,4 0,0 1,268 57L268,243A4,4 0,0 1,264 247L148,247A4,4 0,0 1,144 243L144,57A4,4 0,0 1,148 53z"
+ android:fillColor="#669DF6"/>
+ <path
+ android:pathData="M150,57L262,57A2,2 0,0 1,264 59L264,241A2,2 0,0 1,262 243L150,243A2,2 0,0 1,148 241L148,59A2,2 0,0 1,150 57z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M164.48,237H154V226.42"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#669DF6"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M154,237L169,222"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#669DF6"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M247.52,63L258,63L258,73.58"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#669DF6"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M258,63L243,78"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#669DF6"
+ android:strokeLineCap="round"/>
+ </group>
+</vector>
diff --git a/res/drawable/battery_tips_all_rounded_bg_ripple.xml b/res/drawable/battery_tips_all_rounded_bg_ripple.xml
new file mode 100644
index 0000000..3180570
--- /dev/null
+++ b/res/drawable/battery_tips_all_rounded_bg_ripple.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2023 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.
+ -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:attr/colorControlHighlight">
+ <item android:drawable="@drawable/battery_tips_all_rounded_bg"/>
+</ripple>
\ No newline at end of file
diff --git a/res/drawable/ic_app_aspect_ratio_16_9.xml b/res/drawable/ic_app_aspect_ratio_16_9.xml
new file mode 100644
index 0000000..2300f3d
--- /dev/null
+++ b/res/drawable/ic_app_aspect_ratio_16_9.xml
@@ -0,0 +1,66 @@
+<!--
+ ~ Copyright (C) 2023 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="412dp"
+ android:height="300dp"
+ android:viewportWidth="412"
+ android:viewportHeight="300">
+ <group>
+ <clip-path
+ android:pathData="M0,0h412v300h-412z"/>
+ <path
+ android:pathData="M384.18,300H27.82C12.53,300 0,287.17 0,271.52V28.48C0,12.83 12.53,0 27.82,0H384.29C399.47,0 412,12.83 412,28.48V271.63C412,287.17 399.47,300 384.18,300Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M321.83,134.76V134C322.96,133.96 323.87,132.78 323.87,131.32V116.86C323.87,115.4 322.96,114.22 321.83,114.18V58.55C321.83,52.85 317.2,48.22 311.49,48.22H213.79C211.62,48.22 209.49,48.77 207.6,49.82C206.71,50.18 205.73,50.18 204.84,49.83L204.81,49.82C202.92,48.77 200.79,48.22 198.62,48.22H101.22C95.51,48.22 90.88,52.85 90.88,58.55V242.05C90.88,247.76 95.51,252.38 101.22,252.38H198.84C201,252.38 203.13,251.83 205.03,250.78C205.86,250.45 206.78,250.44 207.63,250.73L207.73,250.78C209.62,251.83 213.04,252.38 215.2,252.38H311.49C317.2,252.38 321.83,247.76 321.83,242.05V181.69C322.96,181.65 323.87,180.47 323.87,179.01V152.1C323.87,150.65 322.96,149.46 321.83,149.43V134.76ZM319.45,242.43C319.45,246.61 315.67,250.01 311.49,250.01H101.21C97.04,250.01 93.26,246.61 93.26,242.43V58.55C93.26,54.38 97.04,50.6 101.21,50.6H311.49C315.67,50.6 319.45,54.38 319.45,58.55V242.43Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M155,53L259,53A4,4 0,0 1,263 57L263,243A4,4 0,0 1,259 247L155,247A4,4 0,0 1,151 243L151,57A4,4 0,0 1,155 53z"
+ android:fillColor="#1A73E8"/>
+ <path
+ android:pathData="M157,57L257,57A2,2 0,0 1,259 59L259,241A2,2 0,0 1,257 243L157,243A2,2 0,0 1,155 241L155,59A2,2 0,0 1,157 57z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M171.48,237H161V226.42"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#1A73E8"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M161,237L176,222"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#1A73E8"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M242.52,63L253,63L253,73.58"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#1A73E8"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M253,63L238,78"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#1A73E8"
+ android:strokeLineCap="round"/>
+ </group>
+</vector>
diff --git a/res/drawable/ic_app_aspect_ratio_3_2.xml b/res/drawable/ic_app_aspect_ratio_3_2.xml
new file mode 100644
index 0000000..b28bdd4
--- /dev/null
+++ b/res/drawable/ic_app_aspect_ratio_3_2.xml
@@ -0,0 +1,66 @@
+<!--
+ ~ Copyright (C) 2023 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="412dp"
+ android:height="300dp"
+ android:viewportWidth="412"
+ android:viewportHeight="300">
+ <group>
+ <clip-path
+ android:pathData="M0,0h412v300h-412z"/>
+ <path
+ android:pathData="M384.18,300H27.82C12.53,300 0,287.17 0,271.52V28.48C0,12.83 12.53,0 27.82,0H384.29C399.47,0 412,12.83 412,28.48V271.63C412,287.17 399.47,300 384.18,300Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M321.83,134.76V134C322.96,133.96 323.87,132.78 323.87,131.32V116.86C323.87,115.4 322.96,114.22 321.83,114.18V58.55C321.83,52.85 317.2,48.22 311.49,48.22H213.79C211.62,48.22 209.49,48.77 207.6,49.82C206.71,50.18 205.73,50.18 204.84,49.83L204.81,49.82C202.92,48.77 200.79,48.22 198.62,48.22H101.22C95.51,48.22 90.88,52.85 90.88,58.55V242.05C90.88,247.76 95.51,252.38 101.22,252.38H198.84C201,252.38 203.13,251.83 205.03,250.78C205.86,250.45 206.78,250.44 207.63,250.73L207.73,250.78C209.62,251.83 213.04,252.38 215.2,252.38H311.49C317.2,252.38 321.83,247.76 321.83,242.05V181.69C322.96,181.65 323.87,180.47 323.87,179.01V152.1C323.87,150.65 322.96,149.46 321.83,149.43V134.76ZM319.45,242.43C319.45,246.61 315.67,250.01 311.49,250.01H101.21C97.04,250.01 93.26,246.61 93.26,242.43V58.55C93.26,54.38 97.04,50.6 101.21,50.6H311.49C315.67,50.6 319.45,54.38 319.45,58.55V242.43Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M144,53L268,53A4,4 0,0 1,272 57L272,243A4,4 0,0 1,268 247L144,247A4,4 0,0 1,140 243L140,57A4,4 0,0 1,144 53z"
+ android:fillColor="#1A73E8"/>
+ <path
+ android:pathData="M146,57L266,57A2,2 0,0 1,268 59L268,241A2,2 0,0 1,266 243L146,243A2,2 0,0 1,144 241L144,59A2,2 0,0 1,146 57z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M160.48,237H150V226.42"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#1A73E8"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M150,237L165,222"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#1A73E8"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M251.52,63L262,63L262,73.58"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#1A73E8"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M262,63L247,78"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#1A73E8"
+ android:strokeLineCap="round"/>
+ </group>
+</vector>
diff --git a/res/drawable/ic_app_aspect_ratio_4_3.xml b/res/drawable/ic_app_aspect_ratio_4_3.xml
new file mode 100644
index 0000000..ba875e9
--- /dev/null
+++ b/res/drawable/ic_app_aspect_ratio_4_3.xml
@@ -0,0 +1,66 @@
+<!--
+ ~ Copyright (C) 2023 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="412dp"
+ android:height="300dp"
+ android:viewportWidth="412"
+ android:viewportHeight="300">
+ <group>
+ <clip-path
+ android:pathData="M0,0h412v300h-412z"/>
+ <path
+ android:pathData="M384.18,300H27.82C12.53,300 0,287.17 0,271.52V28.48C0,12.83 12.53,0 27.82,0H384.29C399.47,0 412,12.83 412,28.48V271.63C412,287.17 399.47,300 384.18,300Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M321.83,134.76V134C322.96,133.96 323.87,132.78 323.87,131.32V116.86C323.87,115.4 322.96,114.22 321.83,114.18V58.55C321.83,52.85 317.2,48.22 311.49,48.22H213.79C211.62,48.22 209.49,48.77 207.6,49.82C206.71,50.18 205.73,50.18 204.84,49.83L204.81,49.82C202.92,48.77 200.79,48.22 198.62,48.22H101.22C95.51,48.22 90.88,52.85 90.88,58.55V242.05C90.88,247.76 95.51,252.38 101.22,252.38H198.84C201,252.38 203.13,251.83 205.03,250.78C205.86,250.45 206.78,250.44 207.63,250.73L207.73,250.78C209.62,251.83 213.04,252.38 215.2,252.38H311.49C317.2,252.38 321.83,247.76 321.83,242.05V181.69C322.96,181.65 323.87,180.47 323.87,179.01V152.1C323.87,150.65 322.96,149.46 321.83,149.43V134.76ZM319.45,242.43C319.45,246.61 315.67,250.01 311.49,250.01H101.21C97.04,250.01 93.26,246.61 93.26,242.43V58.55C93.26,54.38 97.04,50.6 101.21,50.6H311.49C315.67,50.6 319.45,54.38 319.45,58.55V242.43Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M136,53L276,53A4,4 0,0 1,280 57L280,243A4,4 0,0 1,276 247L136,247A4,4 0,0 1,132 243L132,57A4,4 0,0 1,136 53z"
+ android:fillColor="#1A73E8"/>
+ <path
+ android:pathData="M138,57L274,57A2,2 0,0 1,276 59L276,241A2,2 0,0 1,274 243L138,243A2,2 0,0 1,136 241L136,59A2,2 0,0 1,138 57z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M152.48,237H142V226.42"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#1A73E8"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M142,237L157,222"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#1A73E8"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M259.52,63L270,63L270,73.58"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#1A73E8"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M270,63L255,78"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#1A73E8"
+ android:strokeLineCap="round"/>
+ </group>
+</vector>
diff --git a/res/drawable/ic_app_aspect_ratio_display_size.xml b/res/drawable/ic_app_aspect_ratio_display_size.xml
new file mode 100644
index 0000000..1122395
--- /dev/null
+++ b/res/drawable/ic_app_aspect_ratio_display_size.xml
@@ -0,0 +1,66 @@
+<!--
+ ~ Copyright (C) 2023 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="412dp"
+ android:height="300dp"
+ android:viewportWidth="412"
+ android:viewportHeight="300">
+ <group>
+ <clip-path
+ android:pathData="M0,0h412v300h-412z"/>
+ <path
+ android:pathData="M384.18,300H27.82C12.53,300 0,287.17 0,271.52V28.48C0,12.83 12.53,0 27.82,0H384.29C399.47,0 412,12.83 412,28.48V271.63C412,287.17 399.47,300 384.18,300Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M321.83,134.76V134C322.96,133.96 323.87,132.78 323.87,131.32V116.86C323.87,115.4 322.96,114.22 321.83,114.18V58.55C321.83,52.85 317.2,48.22 311.49,48.22H213.79C211.62,48.22 209.49,48.77 207.6,49.82C206.71,50.18 205.73,50.18 204.84,49.83L204.81,49.82C202.92,48.77 200.79,48.22 198.62,48.22H101.22C95.51,48.22 90.88,52.85 90.88,58.55V242.05C90.88,247.76 95.51,252.38 101.22,252.38H198.84C201,252.38 203.13,251.83 205.03,250.78C205.86,250.45 206.78,250.44 207.63,250.73L207.73,250.78C209.62,251.83 213.04,252.38 215.2,252.38H311.49C317.2,252.38 321.83,247.76 321.83,242.05V181.69C322.96,181.65 323.87,180.47 323.87,179.01V152.1C323.87,150.65 322.96,149.46 321.83,149.43V134.76ZM319.45,242.43C319.45,246.61 315.67,250.01 311.49,250.01H101.21C97.04,250.01 93.26,246.61 93.26,242.43V58.55C93.26,54.38 97.04,50.6 101.21,50.6H311.49C315.67,50.6 319.45,54.38 319.45,58.55V242.43Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M128,53L284,53A4,4 0,0 1,288 57L288,243A4,4 0,0 1,284 247L128,247A4,4 0,0 1,124 243L124,57A4,4 0,0 1,128 53z"
+ android:fillColor="#1A73E8"/>
+ <path
+ android:pathData="M130,57L282,57A2,2 0,0 1,284 59L284,241A2,2 0,0 1,282 243L130,243A2,2 0,0 1,128 241L128,59A2,2 0,0 1,130 57z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M144.48,237H134V226.42"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#1A73E8"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M134,237L149,222"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#1A73E8"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M267.52,63L278,63L278,73.58"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#1A73E8"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M278,63L263,78"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#1A73E8"
+ android:strokeLineCap="round"/>
+ </group>
+</vector>
diff --git a/res/drawable/ic_app_aspect_ratio_fullscreen.xml b/res/drawable/ic_app_aspect_ratio_fullscreen.xml
new file mode 100644
index 0000000..0e62fe5
--- /dev/null
+++ b/res/drawable/ic_app_aspect_ratio_fullscreen.xml
@@ -0,0 +1,66 @@
+<!--
+ ~ Copyright (C) 2023 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="412dp"
+ android:height="300dp"
+ android:viewportWidth="412"
+ android:viewportHeight="300">
+ <group>
+ <clip-path
+ android:pathData="M0,0h412v300h-412z"/>
+ <path
+ android:pathData="M384.18,300H27.82C12.53,300 0,287.17 0,271.52V28.48C0,12.83 12.53,0 27.82,0H384.29C399.47,0 412,12.83 412,28.48V271.63C412,287.17 399.47,300 384.18,300Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M321.83,134.76V134C322.96,133.96 323.87,132.78 323.87,131.32V116.86C323.87,115.4 322.96,114.22 321.83,114.18V58.55C321.83,52.85 317.2,48.22 311.49,48.22H213.79C211.62,48.22 209.49,48.77 207.6,49.82C206.71,50.18 205.73,50.18 204.84,49.83L204.81,49.82C202.92,48.77 200.79,48.22 198.62,48.22H101.22C95.51,48.22 90.88,52.85 90.88,58.55V242.05C90.88,247.76 95.51,252.38 101.22,252.38H198.84C201,252.38 203.13,251.83 205.03,250.78C205.86,250.45 206.78,250.44 207.63,250.73L207.73,250.78C209.62,251.83 213.04,252.38 215.2,252.38H311.49C317.2,252.38 321.83,247.76 321.83,242.05V181.69C322.96,181.65 323.87,180.47 323.87,179.01V152.1C323.87,150.65 322.96,149.46 321.83,149.43V134.76ZM319.45,242.43C319.45,246.61 315.67,250.01 311.49,250.01H101.21C97.04,250.01 93.26,246.61 93.26,242.43V58.55C93.26,54.38 97.04,50.6 101.21,50.6H311.49C315.67,50.6 319.45,54.38 319.45,58.55V242.43Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M100,53L312,53A4,4 0,0 1,316 57L316,243A4,4 0,0 1,312 247L100,247A4,4 0,0 1,96 243L96,57A4,4 0,0 1,100 53z"
+ android:fillColor="#1A73E8"/>
+ <path
+ android:pathData="M102,57L310,57A2,2 0,0 1,312 59L312,241A2,2 0,0 1,310 243L102,243A2,2 0,0 1,100 241L100,59A2,2 0,0 1,102 57z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M116.48,237H106V226.42"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#1A73E8"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M106,237L121,222"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#1A73E8"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M295.52,63L306,63L306,73.58"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#1A73E8"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M306,63L291,78"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#1A73E8"
+ android:strokeLineCap="round"/>
+ </group>
+</vector>
diff --git a/res/drawable/ic_app_aspect_ratio_half_screen.xml b/res/drawable/ic_app_aspect_ratio_half_screen.xml
new file mode 100644
index 0000000..43afce1
--- /dev/null
+++ b/res/drawable/ic_app_aspect_ratio_half_screen.xml
@@ -0,0 +1,66 @@
+<!--
+ ~ Copyright (C) 2023 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="412dp"
+ android:height="300dp"
+ android:viewportWidth="412"
+ android:viewportHeight="300">
+ <group>
+ <clip-path
+ android:pathData="M0,0h412v300h-412z"/>
+ <path
+ android:pathData="M384.18,300H27.82C12.53,300 0,287.17 0,271.52V28.48C0,12.83 12.53,0 27.82,0H384.29C399.47,0 412,12.83 412,28.48V271.63C412,287.17 399.47,300 384.18,300Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M321.83,134.76V134C322.96,133.96 323.87,132.78 323.87,131.32V116.86C323.87,115.4 322.96,114.22 321.83,114.18V58.55C321.83,52.85 317.2,48.22 311.49,48.22H213.79C211.62,48.22 209.49,48.77 207.6,49.82C206.71,50.18 205.73,50.18 204.84,49.83L204.81,49.82C202.92,48.77 200.79,48.22 198.62,48.22H101.22C95.51,48.22 90.88,52.85 90.88,58.55V242.05C90.88,247.76 95.51,252.38 101.22,252.38H198.84C201,252.38 203.13,251.83 205.03,250.78C205.86,250.45 206.78,250.44 207.63,250.73L207.73,250.78C209.62,251.83 213.04,252.38 215.2,252.38H311.49C317.2,252.38 321.83,247.76 321.83,242.05V181.69C322.96,181.65 323.87,180.47 323.87,179.01V152.1C323.87,150.65 322.96,149.46 321.83,149.43V134.76ZM319.45,242.43C319.45,246.61 315.67,250.01 311.49,250.01H101.21C97.04,250.01 93.26,246.61 93.26,242.43V58.55C93.26,54.38 97.04,50.6 101.21,50.6H311.49C315.67,50.6 319.45,54.38 319.45,58.55V242.43Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M148,53L264,53A4,4 0,0 1,268 57L268,243A4,4 0,0 1,264 247L148,247A4,4 0,0 1,144 243L144,57A4,4 0,0 1,148 53z"
+ android:fillColor="#1A73E8"/>
+ <path
+ android:pathData="M150,57L262,57A2,2 0,0 1,264 59L264,241A2,2 0,0 1,262 243L150,243A2,2 0,0 1,148 241L148,59A2,2 0,0 1,150 57z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M164.48,237H154V226.42"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#1A73E8"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M154,237L169,222"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#1A73E8"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M247.52,63L258,63L258,73.58"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#1A73E8"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M258,63L243,78"
+ android:strokeLineJoin="round"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#1A73E8"
+ android:strokeLineCap="round"/>
+ </group>
+</vector>
diff --git a/res/layout/battery_tips_card.xml b/res/layout/battery_tips_card.xml
index d2edb51..2fa5bf2 100644
--- a/res/layout/battery_tips_card.xml
+++ b/res/layout/battery_tips_card.xml
@@ -12,36 +12,16 @@
android:id="@+id/tips_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@drawable/battery_tips_all_rounded_bg"
+ android:background="@drawable/battery_tips_all_rounded_bg_ripple"
android:orientation="vertical"
android:padding="24dp">
- <LinearLayout
- android:layout_width="match_parent"
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:orientation="horizontal">
-
- <ImageView
- android:id="@+id/icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical|start"
- android:src="@drawable/ic_battery_tips_lightbulb" />
-
- <Space
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1" />
-
- <ImageButton
- android:id="@+id/dismiss_button"
- style="@style/Banner.Dismiss.SettingsLib"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical|end"
- android:layout_marginEnd="0dp"
- android:src="@drawable/ic_battery_tips_close_icon" />
- </LinearLayout>
+ android:layout_gravity="center_vertical|start"
+ android:src="@drawable/ic_battery_tips_lightbulb" />
<TextView
android:id="@+id/title"
@@ -53,30 +33,40 @@
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="?android:attr/textColorPrimary" />
- <TextView
- android:id="@+id/summary"
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:orientation="horizontal"
android:layout_marginTop="8dp"
- android:gravity="start"
- android:maxLines="10"
- android:textAlignment="viewStart"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:attr/textColorSecondary" />
+ android:gravity="end">
- <com.google.android.material.button.MaterialButton
- android:id="@+id/action_button"
- style="@style/Widget.Material3.Button.OutlinedButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="end"
- android:layout_marginTop="8dp"
- android:text="@string/battery_tips_card_action_button"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:attr/textColorPrimary"
- android:textStyle="bold"
- app:strokeColor="?android:attr/colorAccent"
- app:strokeWidth="1dp" />
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/dismiss_button"
+ style="@style/Widget.Material3.Button.TextButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end"
+ android:paddingHorizontal="16dp"
+ android:layout_marginEnd="8dp"
+ android:text="@string/battery_tips_card_dismiss_button"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/colorAccent"
+ android:textStyle="bold" />
+
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/main_button"
+ style="@style/Widget.Material3.Button.OutlinedButton"
+ android:paddingHorizontal="16dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end"
+ android:text="@string/battery_tips_card_action_button"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textStyle="bold"
+ app:strokeColor="?android:attr/colorAccent"
+ app:strokeWidth="1dp" />
+ </LinearLayout>
</LinearLayout>
<Space
diff --git a/res/layout/bluetooth_pin_confirm.xml b/res/layout/bluetooth_pin_confirm.xml
index 7b5b046..bcc47ad 100644
--- a/res/layout/bluetooth_pin_confirm.xml
+++ b/res/layout/bluetooth_pin_confirm.xml
@@ -76,15 +76,37 @@
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
android:visibility="gone" />
- <CheckBox
- android:id="@+id/phonebook_sharing_message_confirm_pin"
- android:layout_width="wrap_content"
+ <LinearLayout
+ android:id="@+id/phonebook_sharing"
android:layout_height="wrap_content"
- android:minHeight="@dimen/min_tap_target_size"
+ android:layout_width="match_parent"
android:layout_marginStart="@dimen/bluetooth_dialog_padding"
android:layout_marginEnd="@dimen/bluetooth_dialog_padding"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1" />
-
+ android:orientation="horizontal">
+ <LinearLayout
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginEnd="10dp"
+ android:orientation="vertical">
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/bluetooth_pairing_phonebook_toggle_text"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1" />
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/bluetooth_pairing_phonebook_toggle_details"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Caption" />
+ </LinearLayout>
+ <Switch
+ android:id="@+id/phonebook_sharing_message_confirm_pin"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_weight="0"
+ android:gravity="center_vertical" />
+ </LinearLayout>
</LinearLayout>
</ScrollView>
diff --git a/res/layout/radio_with_image_preference.xml b/res/layout/radio_with_image_preference.xml
new file mode 100644
index 0000000..fcd0e26
--- /dev/null
+++ b/res/layout/radio_with_image_preference.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 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:background="?android:attr/selectableItemBackground"
+ android:gravity="center_vertical"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:paddingTop="16dp"
+ android:paddingBottom="16dp">
+
+ <LinearLayout
+ android:id="@android:id/widget_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:paddingHorizontal="20dp"
+ android:gravity="center_horizontal"
+ android:minWidth="56dp"
+ android:orientation="vertical"/>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:maxLines="2"
+ android:textAppearance="?android:attr/textAppearanceListItem"/>
+
+ <LinearLayout
+ android:id="@+id/summary_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone">
+ <TextView
+ android:id="@android:id/summary"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textAlignment="viewStart"
+ android:textColor="?android:attr/textColorSecondary"/>
+ </LinearLayout>
+
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="@dimen/settingslib_illustration_padding"
+ android:adjustViewBounds="true"
+ android:maxWidth="@dimen/settingslib_illustration_width"
+ android:maxHeight="@dimen/settingslib_illustration_height" />
+ </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/res/raw/user_aspect_ratio_education.json b/res/raw/user_aspect_ratio_education.json
new file mode 100644
index 0000000..ab74b45
--- /dev/null
+++ b/res/raw/user_aspect_ratio_education.json
@@ -0,0 +1 @@
+{"v":"5.12.0","fr":60,"ip":0,"op":226,"w":412,"h":300,"nm":"AppCompat_Felix_DT","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".blue400","cl":"blue400","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"k":[{"s":[38.5,-79.5,0],"t":15,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[38.661,-79.5,0],"t":16,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[39.181,-79.5,0],"t":17,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[40.183,-79.5,0],"t":18,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[41.974,-79.5,0],"t":19,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[45.7,-79.5,0],"t":20,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[49.943,-79.5,0],"t":21,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.81,-79.5,0],"t":22,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.893,-79.5,0],"t":23,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[53.628,-79.5,0],"t":24,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[54.171,-79.5,0],"t":25,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[54.59,-79.5,0],"t":26,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[54.925,-79.5,0],"t":27,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.197,-79.5,0],"t":28,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.423,-79.5,0],"t":29,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.611,-79.5,0],"t":30,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.77,-79.5,0],"t":31,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.904,-79.5,0],"t":32,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.017,-79.5,0],"t":33,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.113,-79.5,0],"t":34,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.195,-79.5,0],"t":35,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.263,-79.5,0],"t":36,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.32,-79.5,0],"t":37,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.368,-79.5,0],"t":38,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.406,-79.5,0],"t":39,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.461,-79.5,0],"t":41,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.5,-79.5,0],"t":60,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.823,-79.5,0],"t":61,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.861,-79.5,0],"t":62,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[59.865,-79.5,0],"t":63,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[63.449,-79.5,0],"t":64,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[70.9,-79.5,0],"t":65,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[79.385,-79.5,0],"t":66,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[83.121,-79.5,0],"t":67,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[85.286,-79.5,0],"t":68,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[86.757,-79.5,0],"t":69,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[87.841,-79.5,0],"t":70,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[88.68,-79.5,0],"t":71,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[89.349,-79.5,0],"t":72,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[89.894,-79.5,0],"t":73,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[90.345,-79.5,0],"t":74,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[90.722,-79.5,0],"t":75,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[91.039,-79.5,0],"t":76,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[91.307,-79.5,0],"t":77,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[91.534,-79.5,0],"t":78,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[91.727,-79.5,0],"t":79,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[91.889,-79.5,0],"t":80,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[92.026,-79.5,0],"t":81,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[92.141,-79.5,0],"t":82,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[92.236,-79.5,0],"t":83,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[92.313,-79.5,0],"t":84,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[92.375,-79.5,0],"t":85,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[92.458,-79.5,0],"t":87,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[92.5,-79.5,0],"t":105,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[92.177,-79.5,0],"t":106,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[91.139,-79.5,0],"t":107,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[89.135,-79.5,0],"t":108,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[85.551,-79.5,0],"t":109,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[78.1,-79.5,0],"t":110,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[69.615,-79.5,0],"t":111,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[65.879,-79.5,0],"t":112,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[63.714,-79.5,0],"t":113,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[62.243,-79.5,0],"t":114,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[61.159,-79.5,0],"t":115,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[60.32,-79.5,0],"t":116,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[59.651,-79.5,0],"t":117,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[59.106,-79.5,0],"t":118,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[58.655,-79.5,0],"t":119,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[58.278,-79.5,0],"t":120,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.961,-79.5,0],"t":121,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.693,-79.5,0],"t":122,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.466,-79.5,0],"t":123,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.273,-79.5,0],"t":124,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.111,-79.5,0],"t":125,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.974,-79.5,0],"t":126,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.859,-79.5,0],"t":127,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.764,-79.5,0],"t":128,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.687,-79.5,0],"t":129,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.625,-79.5,0],"t":130,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.577,-79.5,0],"t":131,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.542,-79.5,0],"t":132,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.5,-79.5,0],"t":150,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.339,-79.5,0],"t":151,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.819,-79.5,0],"t":152,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[54.817,-79.5,0],"t":153,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[53.026,-79.5,0],"t":154,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[49.3,-79.5,0],"t":155,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[45.057,-79.5,0],"t":156,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[43.19,-79.5,0],"t":157,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[42.107,-79.5,0],"t":158,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[41.372,-79.5,0],"t":159,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[40.829,-79.5,0],"t":160,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[40.41,-79.5,0],"t":161,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[40.075,-79.5,0],"t":162,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[39.803,-79.5,0],"t":163,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[39.577,-79.5,0],"t":164,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[39.389,-79.5,0],"t":165,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[39.23,-79.5,0],"t":166,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[39.096,-79.5,0],"t":167,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[38.983,-79.5,0],"t":168,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[38.887,-79.5,0],"t":169,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[38.805,-79.5,0],"t":170,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[38.737,-79.5,0],"t":171,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[38.68,-79.5,0],"t":172,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[38.632,-79.5,0],"t":173,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[38.594,-79.5,0],"t":174,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[38.563,-79.5,0],"t":175,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[38.539,-79.5,0],"t":176,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[38.502,-79.5,0],"t":179,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[7.5,3.077],[7.5,-7.5],[-2.981,-7.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-7.5,7.5],[7.5,-7.5]],"c":false},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"st","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":2916,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".blue400","cl":"blue400","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"k":[{"s":[-38.5,79.5,0],"t":15,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-38.661,79.5,0],"t":16,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-39.181,79.5,0],"t":17,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-40.183,79.5,0],"t":18,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-41.974,79.5,0],"t":19,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-45.7,79.5,0],"t":20,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-49.943,79.5,0],"t":21,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-51.81,79.5,0],"t":22,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.893,79.5,0],"t":23,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.628,79.5,0],"t":24,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-54.171,79.5,0],"t":25,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-54.59,79.5,0],"t":26,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-54.925,79.5,0],"t":27,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-55.197,79.5,0],"t":28,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-55.423,79.5,0],"t":29,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-55.611,79.5,0],"t":30,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-55.77,79.5,0],"t":31,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-55.904,79.5,0],"t":32,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-56.017,79.5,0],"t":33,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-56.113,79.5,0],"t":34,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-56.195,79.5,0],"t":35,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-56.263,79.5,0],"t":36,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-56.32,79.5,0],"t":37,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-56.368,79.5,0],"t":38,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-56.406,79.5,0],"t":39,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-56.461,79.5,0],"t":41,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-56.5,79.5,0],"t":60,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-56.823,79.5,0],"t":61,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-57.861,79.5,0],"t":62,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-59.865,79.5,0],"t":63,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-63.449,79.5,0],"t":64,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-70.9,79.5,0],"t":65,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-79.385,79.5,0],"t":66,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-83.121,79.5,0],"t":67,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-85.286,79.5,0],"t":68,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-86.757,79.5,0],"t":69,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-87.841,79.5,0],"t":70,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-88.68,79.5,0],"t":71,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-89.349,79.5,0],"t":72,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-89.894,79.5,0],"t":73,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-90.345,79.5,0],"t":74,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-90.722,79.5,0],"t":75,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-91.039,79.5,0],"t":76,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-91.307,79.5,0],"t":77,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-91.534,79.5,0],"t":78,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-91.727,79.5,0],"t":79,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-91.889,79.5,0],"t":80,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-92.026,79.5,0],"t":81,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-92.141,79.5,0],"t":82,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-92.236,79.5,0],"t":83,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-92.313,79.5,0],"t":84,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-92.375,79.5,0],"t":85,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-92.458,79.5,0],"t":87,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-92.5,79.5,0],"t":105,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-92.177,79.5,0],"t":106,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-91.139,79.5,0],"t":107,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-89.135,79.5,0],"t":108,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-85.551,79.5,0],"t":109,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-78.1,79.5,0],"t":110,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-69.615,79.5,0],"t":111,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-65.879,79.5,0],"t":112,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-63.714,79.5,0],"t":113,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-62.243,79.5,0],"t":114,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-61.159,79.5,0],"t":115,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-60.32,79.5,0],"t":116,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-59.651,79.5,0],"t":117,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-59.106,79.5,0],"t":118,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-58.655,79.5,0],"t":119,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-58.278,79.5,0],"t":120,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-57.961,79.5,0],"t":121,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-57.693,79.5,0],"t":122,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-57.466,79.5,0],"t":123,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-57.273,79.5,0],"t":124,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-57.111,79.5,0],"t":125,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-56.974,79.5,0],"t":126,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-56.859,79.5,0],"t":127,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-56.764,79.5,0],"t":128,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-56.687,79.5,0],"t":129,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-56.625,79.5,0],"t":130,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-56.577,79.5,0],"t":131,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-56.542,79.5,0],"t":132,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-56.5,79.5,0],"t":150,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-56.339,79.5,0],"t":151,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-55.819,79.5,0],"t":152,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-54.817,79.5,0],"t":153,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.026,79.5,0],"t":154,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-49.3,79.5,0],"t":155,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-45.057,79.5,0],"t":156,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-43.19,79.5,0],"t":157,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-42.107,79.5,0],"t":158,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-41.372,79.5,0],"t":159,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-40.829,79.5,0],"t":160,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-40.41,79.5,0],"t":161,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-40.075,79.5,0],"t":162,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-39.803,79.5,0],"t":163,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-39.577,79.5,0],"t":164,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-39.389,79.5,0],"t":165,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-39.23,79.5,0],"t":166,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-39.096,79.5,0],"t":167,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-38.983,79.5,0],"t":168,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-38.887,79.5,0],"t":169,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-38.805,79.5,0],"t":170,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-38.737,79.5,0],"t":171,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-38.68,79.5,0],"t":172,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-38.632,79.5,0],"t":173,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-38.594,79.5,0],"t":174,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-38.563,79.5,0],"t":175,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-38.539,79.5,0],"t":176,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-38.502,79.5,0],"t":179,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-7.5,-3.077],[-7.5,7.5],[2.981,7.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[7.5,-7.5],[-7.5,7.5]],"c":false},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"st","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":2916,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".black","cl":"black","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.8,0.8],"y":[0.15,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":15,"s":[104,186]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.05,0.05],"y":[0.7,0]},"t":20,"s":[118.4,186]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":45,"s":[140,186]},{"i":{"x":[0.8,0.8],"y":[0.15,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":60,"s":[140,186]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.05,0.05],"y":[0.7,0]},"t":65,"s":[168.8,186]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":90,"s":[212,186]},{"i":{"x":[0.8,0.8],"y":[0.15,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":105,"s":[212,186]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.05,0.05],"y":[0.7,0]},"t":110,"s":[183.2,186]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":135,"s":[140,186]},{"i":{"x":[0.8,0.8],"y":[0.15,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":150,"s":[140,186]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.05,0.05],"y":[0.7,0]},"t":155,"s":[125.6,186]},{"t":180,"s":[104,186]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":2,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"inside","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":2916,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.8,0.8],"y":[0.15,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":15,"s":[112,194]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.05,0.05],"y":[0.7,0]},"t":20,"s":[126.4,194]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":45,"s":[148,194]},{"i":{"x":[0.8,0.8],"y":[0.15,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":60,"s":[148,194]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.05,0.05],"y":[0.7,0]},"t":65,"s":[176.8,194]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":90,"s":[220,194]},{"i":{"x":[0.8,0.8],"y":[0.15,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":105,"s":[220,194]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.05,0.05],"y":[0.7,0]},"t":110,"s":[191.2,194]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":135,"s":[148,194]},{"i":{"x":[0.8,0.8],"y":[0.15,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":150,"s":[148,194]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.05,0.05],"y":[0.7,0]},"t":155,"s":[133.6,194]},{"t":180,"s":[112,194]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"outside","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":2916,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".grey600","cl":"grey600","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[207.5,150.303,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.133,-0.038],[0,0],[0,0],[0,-1.46],[0,0],[1.133,-0.038],[0,0],[5.707,0],[0,0],[1.894,1.051],[0,0],[0.833,-0.334],[2.166,0],[0,0],[0,5.707],[0,0],[-5.707,0],[0,0],[-1.894,-1.05],[0,0],[-0.883,0.354],[-2.166,0],[0,0],[0,-5.707],[0,0],[0,-1.46],[0,0]],"o":[[0,0],[0,0],[1.133,0.038],[0,0],[0,1.46],[0,0],[0,5.706],[0,0],[-2.166,0],[0,0],[-0.846,-0.289],[-1.894,1.051],[0,0],[-5.707,0],[0,0],[0,-5.707],[0,0],[2.166,0],[0,0],[0.886,0.346],[1.894,-1.05],[0,0],[5.707,0],[0,0],[1.133,0.038],[0,0],[0,1.46]],"v":[[114.45,-16.3],[114.45,-15.539],[114.45,-0.877],[116.494,1.802],[116.494,28.704],[114.45,31.383],[114.45,91.749],[104.117,102.082],[7.828,102.082],[0.351,100.48],[0.25,100.424],[-2.349,100.48],[-8.539,102.082],[-106.16,102.082],[-116.494,91.748],[-116.494,-91.748],[-106.16,-102.082],[-8.754,-102.082],[-2.563,-100.48],[-2.532,-100.468],[0.221,-100.48],[6.411,-102.082],[104.116,-102.082],[114.45,-91.748],[114.45,-36.119],[116.494,-33.44],[116.494,-18.979]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,4.177],[0,0],[4.177,0],[0,0],[0,-4.177],[0,0],[-4.177,0]],"o":[[4.177,0],[0,0],[0,-4.177],[0,0],[-4.177,0],[0,0],[0,4.177],[0,0]],"v":[[104.117,99.704],[112.072,92.128],[112.072,-91.748],[104.117,-99.704],[-106.161,-99.704],[-114.116,-91.748],[-114.116,92.128],[-106.161,99.704]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.525490224361,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"felix","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":2916,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".black","cl":"black","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-15.291,0],[0,0],[0,15.544],[0,0],[15.185,0],[0,0],[0,-15.652],[0,0]],"o":[[0,0],[15.291,0],[0,0],[0,-15.652],[0,0],[-15.291,0],[0,0],[0,15.652]],"v":[[-178.179,150],[178.179,150],[206,121.63],[206,-121.522],[178.286,-150],[-178.179,-150],[-206,-121.522],[-206,121.522]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".white","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"white"}],"ip":0,"op":2916,"st":0,"ct":1,"bm":0}],"markers":[{"tm":195,"cm":"Plus .5s hold for loop","dr":30}],"props":{}}
\ No newline at end of file
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 787163e..906d4ee 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -1409,4 +1409,25 @@
<integer-array name="network_mode_3g_deprecated_carrier_id" translatable="false">
</integer-array>
+ <!-- The following 4 arrays are for power anomaly tips card. Please keep them the same size. -->
+ <string-array name="power_anomaly_keys" translatable="false">
+ <item>adaptive_brightness</item>
+ <item>screen_timeout</item>
+ </string-array>
+
+ <string-array name="power_anomaly_titles">
+ <item>Turn on adaptive brightness to extend battery life</item>
+ <item>Reduce screen timeout to extend battery life</item>
+ </string-array>
+
+ <string-array name="power_anomaly_main_btn_strings">
+ <item>@string/battery_tips_card_action_button</item>
+ <item>@string/battery_tips_card_action_button</item>
+ </string-array>
+
+ <string-array name="power_anomaly_dismiss_btn_strings">
+ <item>@string/battery_tips_card_dismiss_button</item>
+ <item>@string/battery_tips_card_dismiss_button</item>
+ </string-array>
+
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f116f5b..e62d8f4 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1551,6 +1551,12 @@
<!-- Checkbox message in pairing dialogs. [CHAR LIMIT=NONE] -->
<string name="bluetooth_pairing_shares_phonebook">Allow access to your contacts and call history</string>
+ <!-- Phonebook sharing toggle message in pairing dialogs. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_pairing_phonebook_toggle_text">Also allow access to contacts and call history</string>
+
+ <!-- Phonebook sharing toggle detailed message in pairing dialogs. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_pairing_phonebook_toggle_details">Info will be used for call announcements and more</string>
+
<!-- Title for BT error dialogs. -->
<string name="bluetooth_error_title"></string>
@@ -9735,23 +9741,14 @@
<string name="app_battery_usage_summary">Set battery usage for apps</string>
<!-- Label of action button in battery tips card [CHAR LIMIT=NONE] -->
- <string name="battery_tips_card_action_button" translatable="false">Optimize</string>
+ <string name="battery_tips_card_action_button" translatable="false">View Settings</string>
+
+ <!-- Label of dismiss button in battery tips card [CHAR LIMIT=NONE] -->
+ <string name="battery_tips_card_dismiss_button" translatable="false">Got it</string>
<!-- Feedback card message in battery tips card [CHAR LIMIT=NONE] -->
<string name="battery_tips_card_feedback_info" translatable="false">Is this message helpful?</string>
- <!-- Title of battery tips: adaptive brightness [CHAR LIMIT=NONE] -->
- <string name="battery_tips_adaptive_brightness_title" translatable="false">Turn on adaptive brightness to extend battery life</string>
-
- <!-- Summary of battery tips: adaptive brightness [CHAR LIMIT=NONE] -->
- <string name="battery_tips_adaptive_brightness_summary" translatable="false">It will help reduce your daily battery drain by 10%</string>
-
- <!-- Title of battery tips: reduce screen timeout [CHAR LIMIT=NONE] -->
- <string name="battery_tips_screen_timeout_title" translatable="false">Reduce screen timeout to extend battery life</string>
-
- <!-- Summary of battery tips: reduce screen timeout [CHAR LIMIT=NONE] -->
- <string name="battery_tips_screen_timeout_summary" translatable="false">It will help reduce your daily battery drain by 10%</string>
-
<!-- Filter title for battery unrestricted[CHAR_LIMIT=50]-->
<string name="filter_battery_unrestricted_title">Unrestricted</string>
@@ -10419,7 +10416,7 @@
<!-- Preference category for showing auto-fill services with saved passwords. [CHAR LIMIT=60] -->
<string name="autofill_passwords">Passwords</string>
<!-- Preference category for showing autofill and credman services with saved credentials. [CHAR LIMIT=60] -->
- <string name="credman_chosen_app_title">Passwords, passkeys and data services</string>
+ <string name="credman_chosen_app_title">Passwords, passkeys, and data services</string>
<!-- Preference category for showing additional credential providers. [CHAR LIMIT=60] -->
<string name="credman_credentials">Additional providers</string>
<!-- Summary for passwords settings that shows how many passwords are saved for each autofill
@@ -10461,7 +10458,7 @@
</string>
<!-- Title of the screen where the user picks a provider. [CHAR_LIMIT=NONE] -->
- <string name="credman_picker_title">Passwords, passkeys and data services</string>
+ <string name="credman_picker_title">Passwords, passkeys, and data services</string>
<!-- Title of the warning dialog for disabling the credential provider. [CHAR_LIMIT=NONE] -->
<string name="credman_confirmation_message_title">Turn off %1$s\?</string>
@@ -10485,10 +10482,10 @@
<string name="credman_enable_confirmation_message">%1$s uses what\'s on your screen to determine what can be autofilled.</string>
<!-- Title of the error dialog when too many credential providers are selected. [CHAR_LIMIT=NONE] -->
- <string name="credman_error_message_title">Passwords, passkeys and data services limit</string>
+ <string name="credman_error_message_title">Passwords, passkeys, and data services limit</string>
<!-- Message of the error dialog when too many credential providers are selected. [CHAR_LIMIT=NONE] -->
- <string name="credman_error_message">You can have up to 5 passwords, passkeys and data services active at the same time. Turn off a service to add more.</string>
+ <string name="credman_error_message">You can have up to 5 passwords, passkeys, and data services active at the same time. Turn off a service to add more.</string>
<!-- Positive button to turn off credential manager provider (confirmation). [CHAR LIMIT=60] -->
<string name="credman_confirmation_message_positive_button">Turn off</string>
@@ -12088,6 +12085,19 @@
<!-- The summary of the head tracking [CHAR LIMIT=none] -->
<string name="bluetooth_details_head_tracking_summary">Audio changes as you move your head to sound more natural</string>
+ <!-- The title of the bluetooth audio device type selection [CHAR LIMIT=none] -->
+ <string name="bluetooth_details_audio_device_types_title">Audio Device Type</string>
+ <!-- The audio device type corresponding to unknown selected [CHAR LIMIT=none] -->
+ <string name="bluetooth_details_audio_device_type_unknown">Unknown</string>
+ <!-- The audio device type corresponding to none selected [CHAR LIMIT=none] -->
+ <string name="bluetooth_details_audio_device_type_speaker">Speaker</string>
+ <!-- The audio device type corresponding to speakers [CHAR LIMIT=none] -->
+ <string name="bluetooth_details_audio_device_type_headphones">Headphones</string>
+ <!-- The audio device type corresponding to car kit [CHAR LIMIT=none] -->
+ <string name="bluetooth_details_audio_device_type_carkit">Car Kit</string>
+ <!-- The audio device type corresponding to other device type [CHAR LIMIT=none] -->
+ <string name="bluetooth_details_audio_device_type_other">Other</string>
+
<!-- Developer Settings: Title for network bandwidth ingress rate limit [CHAR LIMIT=none] -->
<string name="ingress_rate_limit_title">Network download rate limit</string>
<!-- Developer Settings: Summary for network bandwidth ingress rate limit [CHAR LIMIT=none] -->
diff --git a/res/xml/bluetooth_device_details_fragment.xml b/res/xml/bluetooth_device_details_fragment.xml
index 35359f7..8f309a4 100644
--- a/res/xml/bluetooth_device_details_fragment.xml
+++ b/res/xml/bluetooth_device_details_fragment.xml
@@ -72,6 +72,9 @@
android:key="device_controls_general" />
<PreferenceCategory
+ android:key="bluetooth_audio_device_type_group"/>
+
+ <PreferenceCategory
android:key="spatial_audio_group"/>
<PreferenceCategory
diff --git a/res/xml/network_provider_settings.xml b/res/xml/network_provider_settings.xml
index 1921ece..418bb8d 100644
--- a/res/xml/network_provider_settings.xml
+++ b/res/xml/network_provider_settings.xml
@@ -65,7 +65,13 @@
<PreferenceCategory
android:key="access_points"
- android:layout="@layout/preference_category_no_label"/>
+ android:layout="@layout/preference_category_no_label">
+
+ <com.android.settings.wifi.AddWifiNetworkPreference
+ android:key="add_wifi_network"
+ android:title="@string/wifi_add_network"
+ android:icon="@drawable/ic_add_24dp"/>
+ </PreferenceCategory>
<Preference
android:key="configure_network_settings"
diff --git a/res/xml/user_aspect_ratio_details.xml b/res/xml/user_aspect_ratio_details.xml
index fc921dd..07c8b6f 100644
--- a/res/xml/user_aspect_ratio_details.xml
+++ b/res/xml/user_aspect_ratio_details.xml
@@ -18,42 +18,49 @@
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:title="@string/aspect_ratio_title">
<com.android.settingslib.widget.ActionButtonsPreference
android:key="header_view" />
- <com.android.settingslib.widget.SelectorWithWidgetPreference
+ <com.android.settings.applications.appcompat.RadioWithImagePreference
android:key="app_default_pref"
android:title="@string/user_aspect_ratio_app_default"/>
- <com.android.settingslib.widget.SelectorWithWidgetPreference
+ <com.android.settings.applications.appcompat.RadioWithImagePreference
android:key="fullscreen_pref"
- android:title="@string/user_aspect_ratio_fullscreen"/>
+ android:title="@string/user_aspect_ratio_fullscreen"
+ android:icon="@drawable/ic_app_aspect_ratio_fullscreen"/>
- <com.android.settingslib.widget.SelectorWithWidgetPreference
+ <com.android.settings.applications.appcompat.RadioWithImagePreference
android:key="half_screen_pref"
- android:title="@string/user_aspect_ratio_half_screen"/>
+ android:title="@string/user_aspect_ratio_half_screen"
+ android:icon="@drawable/ic_app_aspect_ratio_half_screen"/>
- <com.android.settingslib.widget.SelectorWithWidgetPreference
+ <com.android.settings.applications.appcompat.RadioWithImagePreference
android:key="display_size_pref"
- android:title="@string/user_aspect_ratio_device_size"/>
+ android:title="@string/user_aspect_ratio_device_size"
+ android:icon="@drawable/ic_app_aspect_ratio_display_size"/>
- <com.android.settingslib.widget.SelectorWithWidgetPreference
+ <com.android.settings.applications.appcompat.RadioWithImagePreference
android:key="16_9_pref"
- android:title="@string/user_aspect_ratio_16_9"/>
+ android:title="@string/user_aspect_ratio_16_9"
+ android:icon="@drawable/ic_app_aspect_ratio_16_9"/>
- <com.android.settingslib.widget.SelectorWithWidgetPreference
+ <com.android.settings.applications.appcompat.RadioWithImagePreference
android:key="4_3_pref"
- android:title="@string/user_aspect_ratio_4_3"/>
+ android:title="@string/user_aspect_ratio_4_3"
+ android:icon="@drawable/ic_app_aspect_ratio_4_3"/>
- <com.android.settingslib.widget.SelectorWithWidgetPreference
+ <com.android.settings.applications.appcompat.RadioWithImagePreference
android:key="3_2_pref"
- android:title="@string/user_aspect_ratio_3_2"/>
+ android:title="@string/user_aspect_ratio_3_2"
+ android:icon="@drawable/ic_app_aspect_ratio_3_2"/>
<com.android.settingslib.widget.FooterPreference
android:title="@string/app_aspect_ratio_footer"
android:selectable="false"
settings:searchable="false"/>
-</PreferenceScreen>
\ No newline at end of file
+</PreferenceScreen>
diff --git a/src/com/android/settings/RegulatoryInfoDisplayActivity.kt b/src/com/android/settings/RegulatoryInfoDisplayActivity.kt
index ffacb9c..fdf66c3 100644
--- a/src/com/android/settings/RegulatoryInfoDisplayActivity.kt
+++ b/src/com/android/settings/RegulatoryInfoDisplayActivity.kt
@@ -46,7 +46,7 @@
getRegulatoryInfo()?.let {
val view = layoutInflater.inflate(R.layout.regulatory_info, null)
- val image = view.findViewById<ImageView>(R.id.regulatoryInfo)
+ val image = view.requireViewById<ImageView>(R.id.regulatoryInfo)
image.setImageDrawable(it)
builder.setView(view)
builder.show()
diff --git a/src/com/android/settings/applications/appcompat/RadioWithImagePreference.java b/src/com/android/settings/applications/appcompat/RadioWithImagePreference.java
new file mode 100644
index 0000000..77cd86c
--- /dev/null
+++ b/src/com/android/settings/applications/appcompat/RadioWithImagePreference.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2023 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.settings.applications.appcompat;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.View;
+
+import androidx.preference.CheckBoxPreference;
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.settings.R;
+
+/**
+ * Radio button preference with image at the bottom.
+ *
+ * <p>Layout should stay the same as
+ * {@link com.android.settingslib.widget.SelectorWithWidgetPreference} for consistency.
+ */
+public class RadioWithImagePreference extends CheckBoxPreference {
+
+ /**
+ * Interface definition for a callback to be invoked when the preference is clicked.
+ */
+ public interface OnClickListener {
+ /**
+ * Called when a preference has been clicked.
+ *
+ * @param emiter The clicked preference
+ */
+ void onRadioButtonClicked(RadioWithImagePreference emiter);
+ }
+
+ private OnClickListener mListener = null;
+
+ /**
+ * Performs inflation from XML and apply a class-specific base style.
+ *
+ * @param context The {@link Context} this is associated with, through which it can
+ * access the current theme, resources, {@link SharedPreferences}, etc.
+ * @param attrs The attributes of the XML tag that is inflating the preference
+ * @param defStyle An attribute in the current theme that contains a reference to a style
+ * resource that supplies default values for the view. Can be 0 to not
+ * look for defaults.
+ */
+ public RadioWithImagePreference(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init();
+ }
+
+ /**
+ * Performs inflation from XML and apply a class-specific base style.
+ *
+ * @param context The {@link Context} this is associated with, through which it can
+ * access the current theme, resources, {@link SharedPreferences}, etc.
+ * @param attrs The attributes of the XML tag that is inflating the preference
+ */
+ public RadioWithImagePreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ /**
+ * Constructor to create a preference.
+ *
+ * @param context The Context this is associated with.
+ */
+ public RadioWithImagePreference(Context context) {
+ this(context, null);
+ }
+
+ /**
+ * Sets the callback to be invoked when this preference is clicked by the user.
+ *
+ * @param listener The callback to be invoked
+ */
+ public void setOnClickListener(OnClickListener listener) {
+ mListener = listener;
+ }
+
+ /**
+ * Processes a click on the preference.
+ */
+ @Override
+ public void onClick() {
+ if (mListener != null) {
+ mListener.onRadioButtonClicked(this);
+ }
+ }
+
+ /**
+ * Binds the created View to the data for this preference.
+ *
+ * <p>This is a good place to grab references to custom Views in the layout and set
+ * properties on them.
+ *
+ * <p>Make sure to call through to the superclass's implementation.
+ *
+ * @param holder The ViewHolder that provides references to the views to fill in. These views
+ * will be recycled, so you should not hold a reference to them after this method
+ * returns.
+ */
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+
+ View summaryContainer = holder.findViewById(R.id.summary_container);
+ if (summaryContainer != null) {
+ summaryContainer.setVisibility(
+ TextUtils.isEmpty(getSummary()) ? View.GONE : View.VISIBLE);
+ }
+ }
+
+ private void init() {
+ setWidgetLayoutResource(com.android.settingslib.R.layout.preference_widget_radiobutton);
+ setLayoutResource(R.layout.radio_with_image_preference);
+ setIconSpaceReserved(false);
+ }
+}
diff --git a/src/com/android/settings/applications/appcompat/UserAspectRatioDetails.java b/src/com/android/settings/applications/appcompat/UserAspectRatioDetails.java
index f8406f9..e01f28a 100644
--- a/src/com/android/settings/applications/appcompat/UserAspectRatioDetails.java
+++ b/src/com/android/settings/applications/appcompat/UserAspectRatioDetails.java
@@ -42,7 +42,6 @@
import com.android.settings.R;
import com.android.settings.applications.AppInfoWithHeader;
import com.android.settingslib.widget.ActionButtonsPreference;
-import com.android.settingslib.widget.SelectorWithWidgetPreference;
import java.util.ArrayList;
import java.util.List;
@@ -51,7 +50,7 @@
* App specific activity to show aspect ratio overrides
*/
public class UserAspectRatioDetails extends AppInfoWithHeader implements
- SelectorWithWidgetPreference.OnClickListener {
+ RadioWithImagePreference.OnClickListener {
private static final String TAG = UserAspectRatioDetails.class.getSimpleName();
private static final String KEY_HEADER_BUTTONS = "header_view";
@@ -65,7 +64,7 @@
@VisibleForTesting
static final String KEY_PREF_3_2 = "3_2_pref";
- private final List<SelectorWithWidgetPreference> mAspectRatioPreferences = new ArrayList<>();
+ private final List<RadioWithImagePreference> mAspectRatioPreferences = new ArrayList<>();
@NonNull private UserAspectRatioManager mUserAspectRatioManager;
@NonNull private String mSelectedKey = KEY_PREF_DEFAULT;
@@ -87,7 +86,7 @@
}
@Override
- public void onRadioButtonClicked(@NonNull SelectorWithWidgetPreference selected) {
+ public void onRadioButtonClicked(@NonNull RadioWithImagePreference selected) {
final String selectedKey = selected.getKey();
if (mSelectedKey.equals(selectedKey)) {
return;
@@ -198,7 +197,7 @@
private void addPreference(@NonNull String key,
@PackageManager.UserMinAspectRatio int aspectRatio) {
- final SelectorWithWidgetPreference pref = findPreference(key);
+ final RadioWithImagePreference pref = findPreference(key);
if (pref == null) {
return;
}
@@ -212,7 +211,7 @@
}
private void updateAllPreferences(@NonNull String selectedKey) {
- for (SelectorWithWidgetPreference pref : mAspectRatioPreferences) {
+ for (RadioWithImagePreference pref : mAspectRatioPreferences) {
pref.setChecked(selectedKey.equals(pref.getKey()));
}
}
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/fragment/FingerprintSettingsRenameDialog.kt b/src/com/android/settings/biometrics/fingerprint2/ui/fragment/FingerprintSettingsRenameDialog.kt
index a08b3db..9542ed8 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/fragment/FingerprintSettingsRenameDialog.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/fragment/FingerprintSettingsRenameDialog.kt
@@ -106,8 +106,8 @@
val dialog = FingerprintSettingsRenameDialog()
val onClick =
DialogInterface.OnClickListener { _, _ ->
- val dialogTextField =
- dialog.requireDialog().findViewById(R.id.fingerprint_rename_field) as ImeAwareEditText
+ val dialogTextField = dialog.requireDialog()
+ .requireViewById(R.id.fingerprint_rename_field) as ImeAwareEditText
val newName = dialogTextField.text.toString()
if (!TextUtils.equals(newName, fp.name)) {
Log.d(TAG, "rename $fp.name to $newName for $dialog")
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/viewmodel/FingerprintSettingsNavigationViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/viewmodel/FingerprintSettingsNavigationViewModel.kt
index a3a5d3c..a638806 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/viewmodel/FingerprintSettingsNavigationViewModel.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/viewmodel/FingerprintSettingsNavigationViewModel.kt
@@ -26,6 +26,7 @@
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.last
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
@@ -49,7 +50,13 @@
if (challengeInit == null || tokenInit == null) {
_nextStep.update { LaunchConfirmDeviceCredential(userId) }
} else {
- viewModelScope.launch { showSettingsHelper() }
+ viewModelScope.launch {
+ if (fingerprintManagerInteractor.enrolledFingerprints.last().isEmpty()) {
+ _nextStep.update { EnrollFirstFingerprint(userId, null, challenge, token) }
+ } else {
+ showSettingsHelper()
+ }
+ }
}
}
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/viewmodel/FingerprintSettingsViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/viewmodel/FingerprintSettingsViewModel.kt
index 554f336..0bae075 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/viewmodel/FingerprintSettingsViewModel.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/viewmodel/FingerprintSettingsViewModel.kt
@@ -17,8 +17,7 @@
package com.android.settings.biometrics.fingerprint2.ui.viewmodel
import android.hardware.fingerprint.FingerprintManager
-import android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL
-import android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC
+import android.hardware.fingerprint.FingerprintSensorProperties
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
import android.util.Log
import androidx.lifecycle.ViewModel
@@ -67,24 +66,6 @@
}
}
- init {
- viewModelScope.launch {
- fingerprintSensorPropertiesInternal.update {
- fingerprintManagerInteractor.sensorPropertiesInternal()
- }
- }
-
- viewModelScope.launch {
- navigationViewModel.nextStep.filterNotNull().collect {
- _isShowingDialog.update { null }
- if (it is ShowSettings) {
- // reset state
- updateSettingsData()
- }
- }
- }
- }
-
private val _fingerprintStateViewModel: MutableStateFlow<FingerprintStateViewModel?> =
MutableStateFlow(null)
val fingerprintState: Flow<FingerprintStateViewModel?> =
@@ -103,7 +84,6 @@
MutableSharedFlow()
private val attemptsSoFar: MutableStateFlow<Int> = MutableStateFlow(0)
-
/**
* This is a very tricky flow. The current fingerprint manager APIs are not robust, and a proper
* implementation would take quite a lot of code to implement, it might be easier to rewrite
@@ -139,7 +119,13 @@
return@combine false
}
val sensorType = sensorProps[0].sensorType
- if (listOf(TYPE_UDFPS_OPTICAL, TYPE_UDFPS_ULTRASONIC).contains(sensorType)) {
+ if (
+ listOf(
+ FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
+ FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC
+ )
+ .contains(sensorType)
+ ) {
return@combine false
}
@@ -182,6 +168,24 @@
}
.flowOn(backgroundDispatcher)
+ init {
+ viewModelScope.launch {
+ fingerprintSensorPropertiesInternal.update {
+ fingerprintManagerInteractor.sensorPropertiesInternal()
+ }
+ }
+
+ viewModelScope.launch {
+ navigationViewModel.nextStep.filterNotNull().collect {
+ _isShowingDialog.update { null }
+ if (it is ShowSettings) {
+ // reset state
+ updateSettingsData()
+ }
+ }
+ }
+ }
+
/** The rename dialog has finished */
fun onRenameDialogFinished() {
_isShowingDialog.update { null }
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollIntroFragment.kt b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollIntroFragment.kt
index 4205225..d1b3799 100644
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollIntroFragment.kt
+++ b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollIntroFragment.kt
@@ -50,9 +50,9 @@
import com.google.android.setupdesign.util.DeviceHelper
import com.google.android.setupdesign.util.DynamicColorPalette
import com.google.android.setupdesign.util.DynamicColorPalette.ColorType.ACCENT
+import java.util.function.Supplier
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
-import java.util.function.Supplier
/**
* Fingerprint intro onboarding page fragment implementation
@@ -205,8 +205,8 @@
private fun getDescriptionDisabledByAdmin(context: Context): String? {
val defaultStrId: Int =
R.string.security_settings_fingerprint_enroll_introduction_message_unlock_disabled
- val devicePolicyManager: DevicePolicyManager = requireActivity()
- .getSystemService(DevicePolicyManager::class.java)
+ val devicePolicyManager: DevicePolicyManager =
+ checkNotNull(requireActivity().getSystemService(DevicePolicyManager::class.java))
return devicePolicyManager.resources.getString(FINGERPRINT_UNLOCK_DISABLED) {
context.getString(defaultStrId)
@@ -234,7 +234,7 @@
else
View.INVISIBLE
- view!!.findViewById<TextView>(R.id.error_text).let {
+ view!!.requireViewById<TextView>(R.id.error_text).let {
when (status.enrollableStatus) {
FINGERPRINT_ENROLLABLE_OK -> {
it.text = null
@@ -324,6 +324,6 @@
)
}
- view.findViewById<ScrollView>(R.id.sud_scroll_view)?.importantForAccessibility =
- View.IMPORTANT_FOR_ACCESSIBILITY_YES
+ view.findViewById<ScrollView>(com.google.android.setupdesign.R.id.sud_scroll_view)
+ ?.importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_YES
}
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.kt b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.kt
index b81621f..ec96597 100644
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.kt
+++ b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.kt
@@ -140,7 +140,7 @@
action?.let { onEnrollingAction(it) }
}
- private val finishActionObserver = Observer<Int> { action ->
+ private val finishActionObserver = Observer<Int?> { action ->
if (DEBUG) {
Log.d(TAG, "finishActionObserver($action)")
}
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsAudioDeviceTypeController.java b/src/com/android/settings/bluetooth/BluetoothDetailsAudioDeviceTypeController.java
new file mode 100644
index 0000000..ba5f465
--- /dev/null
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsAudioDeviceTypeController.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 com.android.settings.bluetooth;
+
+import static android.bluetooth.BluetoothDevice.DEVICE_TYPE_LE;
+import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_CARKIT;
+import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_HEADPHONES;
+import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_OTHER;
+import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_SPEAKER;
+import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_UNKNOWN;
+
+import android.content.Context;
+import android.media.AudioManager;
+import android.media.AudioManager.AudioDeviceCategory;
+import android.util.Log;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.ListPreference;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceFragmentCompat;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settingslib.bluetooth.A2dpProfile;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.LeAudioProfile;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+/**
+ * Controller responsible for the bluetooth audio device type selection
+ */
+public class BluetoothDetailsAudioDeviceTypeController extends BluetoothDetailsController
+ implements Preference.OnPreferenceChangeListener {
+ private static final String TAG = "BluetoothDetailsAudioDeviceTypeController";
+
+ private static final boolean DEBUG = false;
+
+ private static final String KEY_BT_AUDIO_DEVICE_TYPE_GROUP =
+ "bluetooth_audio_device_type_group";
+ private static final String KEY_BT_AUDIO_DEVICE_TYPE = "bluetooth_audio_device_type";
+
+ private final AudioManager mAudioManager;
+
+ private ListPreference mAudioDeviceTypePreference;
+
+ private final LocalBluetoothProfileManager mProfileManager;
+
+ @VisibleForTesting
+ PreferenceCategory mProfilesContainer;
+
+ public BluetoothDetailsAudioDeviceTypeController(
+ Context context,
+ PreferenceFragmentCompat fragment,
+ LocalBluetoothManager manager,
+ CachedBluetoothDevice device,
+ Lifecycle lifecycle) {
+ super(context, fragment, device, lifecycle);
+ mAudioManager = context.getSystemService(AudioManager.class);
+ mProfileManager = manager.getProfileManager();
+ }
+
+ @Override
+ public boolean isAvailable() {
+ // Available only for A2DP and BLE devices.
+ A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile();
+ boolean a2dpProfileEnabled = false;
+ if (a2dpProfile != null) {
+ a2dpProfileEnabled = a2dpProfile.isEnabled(mCachedDevice.getDevice());
+ }
+
+ LeAudioProfile leAudioProfile = mProfileManager.getLeAudioProfile();
+ boolean leAudioProfileEnabled = false;
+ if (leAudioProfile != null) {
+ leAudioProfileEnabled = leAudioProfile.isEnabled(mCachedDevice.getDevice());
+ }
+
+ return a2dpProfileEnabled || leAudioProfileEnabled;
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ if (preference instanceof ListPreference) {
+ final ListPreference pref = (ListPreference) preference;
+ final String key = pref.getKey();
+ if (key.equals(KEY_BT_AUDIO_DEVICE_TYPE)) {
+ if (newValue instanceof String) {
+ final String value = (String) newValue;
+ final int index = pref.findIndexOfValue(value);
+ if (index >= 0) {
+ pref.setSummary(pref.getEntries()[index]);
+ mAudioManager.setBluetoothAudioDeviceCategory(mCachedDevice.getAddress(),
+ mCachedDevice.getDevice().getType() == DEVICE_TYPE_LE,
+ Integer.parseInt(value));
+ }
+ }
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY_BT_AUDIO_DEVICE_TYPE_GROUP;
+ }
+
+ @Override
+ protected void init(PreferenceScreen screen) {
+ mProfilesContainer = screen.findPreference(getPreferenceKey());
+ refresh();
+ }
+
+ @Override
+ protected void refresh() {
+ mAudioDeviceTypePreference = mProfilesContainer.findPreference(
+ KEY_BT_AUDIO_DEVICE_TYPE);
+ if (mAudioDeviceTypePreference == null) {
+ createAudioDeviceTypePreference(mProfilesContainer.getContext());
+ mProfilesContainer.addPreference(mAudioDeviceTypePreference);
+ }
+ }
+
+ @VisibleForTesting
+ void createAudioDeviceTypePreference(Context context) {
+ mAudioDeviceTypePreference = new ListPreference(context);
+ mAudioDeviceTypePreference.setKey(KEY_BT_AUDIO_DEVICE_TYPE);
+ mAudioDeviceTypePreference.setTitle(
+ mContext.getString(R.string.bluetooth_details_audio_device_types_title));
+ mAudioDeviceTypePreference.setEntries(new CharSequence[]{
+ mContext.getString(R.string.bluetooth_details_audio_device_type_unknown),
+ mContext.getString(R.string.bluetooth_details_audio_device_type_speaker),
+ mContext.getString(R.string.bluetooth_details_audio_device_type_headphones),
+ mContext.getString(R.string.bluetooth_details_audio_device_type_carkit),
+ mContext.getString(R.string.bluetooth_details_audio_device_type_other),
+ });
+ mAudioDeviceTypePreference.setEntryValues(new CharSequence[]{
+ Integer.toString(AUDIO_DEVICE_CATEGORY_UNKNOWN),
+ Integer.toString(AUDIO_DEVICE_CATEGORY_SPEAKER),
+ Integer.toString(AUDIO_DEVICE_CATEGORY_HEADPHONES),
+ Integer.toString(AUDIO_DEVICE_CATEGORY_CARKIT),
+ Integer.toString(AUDIO_DEVICE_CATEGORY_OTHER),
+ });
+
+ @AudioDeviceCategory final int deviceCategory =
+ mAudioManager.getBluetoothAudioDeviceCategory(mCachedDevice.getAddress(),
+ mCachedDevice.getDevice().getType() == DEVICE_TYPE_LE);
+ if (DEBUG) {
+ Log.v(TAG, "getBluetoothAudioDeviceCategory() device: "
+ + mCachedDevice.getDevice().getAnonymizedAddress()
+ + ", has audio device category: " + deviceCategory);
+ }
+ mAudioDeviceTypePreference.setValue(Integer.toString(deviceCategory));
+
+ mAudioDeviceTypePreference.setSummary(mAudioDeviceTypePreference.getEntry());
+ mAudioDeviceTypePreference.setOnPreferenceChangeListener(this);
+ }
+
+ @VisibleForTesting
+ ListPreference getAudioDeviceTypePreference() {
+ return mAudioDeviceTypePreference;
+ }
+}
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
index 1fd09a3..555868b 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
@@ -156,6 +156,7 @@
} else if (profile instanceof PbapServerProfile) {
profilePref.setChecked(device.getPhonebookAccessPermission()
== BluetoothDevice.ACCESS_ALLOWED);
+ profilePref.setSummary(profile.getSummaryResourceForDevice(mCachedDevice.getDevice()));
} else if (profile instanceof PanProfile) {
profilePref.setChecked(profile.getConnectionStatus(device) ==
BluetoothProfile.STATE_CONNECTED);
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
index 534cc61..f9afa5b 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
@@ -300,6 +300,8 @@
lifecycle));
controllers.add(new BluetoothDetailsCompanionAppsController(context, this,
mCachedDevice, lifecycle));
+ controllers.add(new BluetoothDetailsAudioDeviceTypeController(context, this, mManager,
+ mCachedDevice, lifecycle));
controllers.add(new BluetoothDetailsSpatialAudioController(context, this, mCachedDevice,
lifecycle));
controllers.add(new BluetoothDetailsProfilesController(context, this, mManager,
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java b/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java
index 8df4666..a3f9bd4 100644
--- a/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java
@@ -33,6 +33,7 @@
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
+import android.widget.Switch;
import android.widget.TextView;
import androidx.annotation.VisibleForTesting;
@@ -341,11 +342,9 @@
TextView pairingViewCaption = (TextView) view.findViewById(R.id.pairing_caption);
TextView pairingViewContent = (TextView) view.findViewById(R.id.pairing_subhead);
TextView messagePairing = (TextView) view.findViewById(R.id.pairing_code_message);
- CheckBox contactSharing = (CheckBox) view.findViewById(
+ Switch contactSharing = (Switch) view.findViewById(
R.id.phonebook_sharing_message_confirm_pin);
- contactSharing.setText(getString(R.string.bluetooth_pairing_shares_phonebook));
-
- contactSharing.setVisibility(
+ view.findViewById(R.id.phonebook_sharing).setVisibility(
mPairingController.isContactSharingVisible() ? View.VISIBLE : View.GONE);
mPairingController.setContactSharingState();
contactSharing.setChecked(mPairingController.getContactSharingState());
diff --git a/src/com/android/settings/connecteddevice/stylus/StylusFeatureProvider.java b/src/com/android/settings/connecteddevice/stylus/StylusFeatureProvider.java
index cd9e981..106ad70 100644
--- a/src/com/android/settings/connecteddevice/stylus/StylusFeatureProvider.java
+++ b/src/com/android/settings/connecteddevice/stylus/StylusFeatureProvider.java
@@ -41,7 +41,8 @@
* the list will contain only the preference showing the current firmware version.
*
* @param context The context
+ * @param usbDevice The USB device for which to generate preferences.
*/
@Nullable
- List<Preference> getUsbFirmwareUpdatePreferences(Context context);
+ List<Preference> getUsbFirmwareUpdatePreferences(Context context, UsbDevice usbDevice);
}
diff --git a/src/com/android/settings/connecteddevice/stylus/StylusFeatureProviderImpl.java b/src/com/android/settings/connecteddevice/stylus/StylusFeatureProviderImpl.java
index ab9d2ce..9166c13 100644
--- a/src/com/android/settings/connecteddevice/stylus/StylusFeatureProviderImpl.java
+++ b/src/com/android/settings/connecteddevice/stylus/StylusFeatureProviderImpl.java
@@ -32,7 +32,7 @@
}
@Override
- public List<Preference> getUsbFirmwareUpdatePreferences(Context context) {
+ public List<Preference> getUsbFirmwareUpdatePreferences(Context context, UsbDevice usbDevice) {
return null;
}
}
diff --git a/src/com/android/settings/connecteddevice/stylus/StylusUsbFirmwareController.java b/src/com/android/settings/connecteddevice/stylus/StylusUsbFirmwareController.java
index 08fdd73..a89925e 100644
--- a/src/com/android/settings/connecteddevice/stylus/StylusUsbFirmwareController.java
+++ b/src/com/android/settings/connecteddevice/stylus/StylusUsbFirmwareController.java
@@ -88,7 +88,7 @@
StylusFeatureProvider featureProvider =
FeatureFactory.getFeatureFactory().getStylusFeatureProvider();
List<Preference> preferences =
- featureProvider.getUsbFirmwareUpdatePreferences(mContext);
+ featureProvider.getUsbFirmwareUpdatePreferences(mContext, mStylusUsbDevice);
if (preferences != null) {
mPreference = new PreferenceCategory(mContext);
diff --git a/src/com/android/settings/core/TogglePreferenceController.java b/src/com/android/settings/core/TogglePreferenceController.java
index a6c67eb..459312a 100644
--- a/src/com/android/settings/core/TogglePreferenceController.java
+++ b/src/com/android/settings/core/TogglePreferenceController.java
@@ -21,6 +21,7 @@
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.slices.SliceData;
+import com.android.settings.onboarding.OnboardingFeatureProvider;
import com.android.settings.widget.TwoStateButtonPreference;
import com.android.settingslib.PrimarySwitchPreference;
import com.android.settingslib.core.instrumentation.SettingsJankMonitor;
@@ -84,6 +85,11 @@
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider()
.logClickedPreference(preference, getMetricsCategory());
}
+ OnboardingFeatureProvider onboardingFeatureProvider =
+ FeatureFactory.getFeatureFactory().getOnboardingFeatureProvider();
+ if (onboardingFeatureProvider != null) {
+ onboardingFeatureProvider.markPreferenceHasChanged(mContext, mPreferenceKey);
+ }
return setChecked((boolean) newValue);
}
diff --git a/src/com/android/settings/deviceinfo/simstatus/SimEidPreferenceController.kt b/src/com/android/settings/deviceinfo/simstatus/SimEidPreferenceController.kt
index e9380f5..4d1b90b 100644
--- a/src/com/android/settings/deviceinfo/simstatus/SimEidPreferenceController.kt
+++ b/src/com/android/settings/deviceinfo/simstatus/SimEidPreferenceController.kt
@@ -95,10 +95,10 @@
WindowManager.LayoutParams.FLAG_SECURE
)
dialog.setCanceledOnTouchOutside(false)
- val textView = dialog.findViewById<TextView>(R.id.esim_id_value)
+ val textView = dialog.requireViewById<TextView>(R.id.esim_id_value)
textView.text = PhoneNumberUtil.expandByTts(eid)
- val qrCodeView = dialog.findViewById<ImageView>(R.id.esim_id_qrcode)
+ val qrCodeView = dialog.requireViewById<ImageView>(R.id.esim_id_qrcode)
qrCodeView.setImageBitmap(getEidQrCode(eid))
// After "Tap to show", eid is displayed on preference.
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
index 258ded1..30eabfa 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
@@ -22,6 +22,7 @@
import android.util.ArrayMap;
import android.util.SparseIntArray;
+import com.android.settings.fuelgauge.batteryusage.PowerAnomalyEventList;
import com.android.settingslib.fuelgauge.Estimate;
import java.util.List;
@@ -147,7 +148,7 @@
/**
* Returns {@link Bundle} for settings anomaly detection result
*/
- Bundle detectSettingsAnomaly(Context context, double displayDrain);
+ PowerAnomalyEventList detectSettingsAnomaly(Context context, double displayDrain);
/**
* Gets an intent for one time bypass charge limited to resume charging.
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
index 9b5bb5e..127178a 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
@@ -21,13 +21,13 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.os.Bundle;
import android.os.Process;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseIntArray;
import com.android.internal.util.ArrayUtils;
+import com.android.settings.fuelgauge.batteryusage.PowerAnomalyEventList;
import com.android.settingslib.fuelgauge.Estimate;
import java.util.ArrayList;
@@ -82,7 +82,7 @@
@Override
public boolean isBatteryTipsFeedbackEnabled() {
- return true;
+ return false;
}
@Override
@@ -175,7 +175,7 @@
public void insertSettingsData(Context context, double displayDrain) {}
@Override
- public Bundle detectSettingsAnomaly(Context context, double displayDrain) {
+ public PowerAnomalyEventList detectSettingsAnomaly(Context context, double displayDrain) {
return null;
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
index 6652043..d2ca306 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
@@ -36,6 +36,7 @@
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
@@ -52,6 +53,8 @@
import java.util.Calendar;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
/** Controls the update for chart graph and the list items. */
public class BatteryChartPreferenceController extends AbstractPreferenceController
@@ -105,10 +108,9 @@
public interface OnBatteryTipsUpdatedListener {
/**
* The callback function for the battery tips card is updated.
- * @param title the title of the battery tip card
- * @param summary the summary of the battery tip card
+ * @param powerAnomalyEvent the power anomaly event with highest score
*/
- void onBatteryTipsUpdated(String title, String summary);
+ void onBatteryTipsUpdated(PowerAnomalyEvent powerAnomalyEvent);
}
@@ -137,11 +139,13 @@
private final SettingsActivity mActivity;
private final MetricsFeatureProvider mMetricsFeatureProvider;
+ private final PowerUsageFeatureProvider mPowerUsageFeatureProvider;
private final Handler mHandler = new Handler(Looper.getMainLooper());
private final AnimatorListenerAdapter mHourlyChartFadeInAdapter =
createHourlyChartAnimatorListenerAdapter(/*visible=*/ true);
private final AnimatorListenerAdapter mHourlyChartFadeOutAdapter =
createHourlyChartAnimatorListenerAdapter(/*visible=*/ false);
+ private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
@VisibleForTesting
final DailyChartLabelTextGenerator mDailyChartLabelTextGenerator =
@@ -157,6 +161,8 @@
mIs24HourFormat = DateFormat.is24HourFormat(context);
mMetricsFeatureProvider =
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
+ mPowerUsageFeatureProvider =
+ FeatureFactory.getFeatureFactory().getPowerUsageFeatureProvider();
if (lifecycle != null) {
lifecycle.addObserver(this);
}
@@ -365,12 +371,32 @@
slotUsageData, getSlotInformation(), isBatteryUsageMapNullOrEmpty());
if (mOnBatteryTipsUpdatedListener != null) {
- mOnBatteryTipsUpdatedListener.onBatteryTipsUpdated(null, null);
+ mExecutor.execute(() -> {
+ final PowerAnomalyEventList anomalyEventList = mPowerUsageFeatureProvider
+ .detectSettingsAnomaly(mContext, /* displayDrain= */ 0);
+ final PowerAnomalyEvent displayEvent =
+ getHighestScoreAnomalyEvent(anomalyEventList);
+ mHandler.post(()
+ -> mOnBatteryTipsUpdatedListener.onBatteryTipsUpdated(displayEvent));
+ });
}
}
return true;
}
+ private PowerAnomalyEvent getHighestScoreAnomalyEvent(PowerAnomalyEventList anomalyEventList) {
+ if (anomalyEventList == null || anomalyEventList.getPowerAnomalyEventsCount() == 0) {
+ return null;
+ }
+ PowerAnomalyEvent highestScoreEvent = null;
+ for (PowerAnomalyEvent event : anomalyEventList.getPowerAnomalyEventsList()) {
+ if (highestScoreEvent == null || event.getScore() > highestScoreEvent.getScore()) {
+ highestScoreEvent = event;
+ }
+ }
+ return highestScoreEvent;
+ }
+
private boolean refreshUiWithNoLevelDataCase() {
setChartSummaryVisible(false);
if (mBatteryUsageMap == null) {
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java
index 89e2ce9..976897f 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java
@@ -17,15 +17,19 @@
package com.android.settings.fuelgauge.batteryusage;
import android.content.Context;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageButton;
+import android.widget.LinearLayout;
import android.widget.TextView;
+import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
+import com.android.settings.core.SubSettingLauncher;
import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
@@ -40,12 +44,14 @@
private final PowerUsageFeatureProvider mPowerUsageFeatureProvider;
- private MaterialButton mActionButton;
- private ImageButton mDismissButton;
- private ImageButton mThumbUpButton;
- private ImageButton mThumbDownButton;
- private CharSequence mTitle;
- private CharSequence mSummary;
+ @VisibleForTesting
+ CharSequence mMainButtonLabel;
+ @VisibleForTesting
+ CharSequence mDismissButtonLabel;
+ @VisibleForTesting
+ String mDestinationComponentName;
+ @VisibleForTesting
+ int mSourceMetricsCategory;
public BatteryTipsCardPreference(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -55,34 +61,65 @@
.getPowerUsageFeatureProvider();
}
- @Override
- public void setTitle(CharSequence title) {
- mTitle = title;
- notifyChanged();
+ /**
+ * Update the label of main button in tips card.
+ */
+ public void setMainButtonLabel(CharSequence label) {
+ if (!TextUtils.equals(mMainButtonLabel, label)) {
+ mMainButtonLabel = label;
+ notifyChanged();
+ }
}
- @Override
- public void setSummary(CharSequence summary) {
- mSummary = summary;
- notifyChanged();
+ /**
+ * Update the label of dismiss button in tips card.
+ */
+ public void setDismissButtonLabel(CharSequence label) {
+ if (!TextUtils.equals(mDismissButtonLabel, label)) {
+ mDismissButtonLabel = label;
+ notifyChanged();
+ }
+ }
+
+ /**
+ * Update the info of target fragment launched by main button.
+ */
+ public void setMainButtonLauncherInfo(final String destinationClassName,
+ final Integer sourceMetricsCategory) {
+ mDestinationComponentName = destinationClassName;
+ mSourceMetricsCategory = sourceMetricsCategory;
}
@Override
public void onClick(View view) {
- // TODO: replace with the settings anomaly obtained from detectSettingsAnomaly();
+ final int viewId = view.getId();
+ if (viewId == R.id.main_button || viewId == R.id.tips_card) {
+ if (TextUtils.isEmpty(mDestinationComponentName)) {
+ return;
+ }
+ new SubSettingLauncher(getContext())
+ .setDestination(mDestinationComponentName)
+ .setSourceMetricsCategory(mSourceMetricsCategory)
+ .launch();
+ } else if (viewId == R.id.dismiss_button) {
+ setVisible(false);
+ }
}
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
- ((TextView) view.findViewById(R.id.title)).setText(mTitle);
- ((TextView) view.findViewById(R.id.summary)).setText(mSummary);
+ ((TextView) view.findViewById(R.id.title)).setText(getTitle());
- mActionButton = (MaterialButton) view.findViewById(R.id.action_button);
- mActionButton.setOnClickListener(this);
- mDismissButton = (ImageButton) view.findViewById(R.id.dismiss_button);
- mDismissButton.setOnClickListener(this);
+ LinearLayout tipsCard = (LinearLayout) view.findViewById(R.id.tips_card);
+ tipsCard.setOnClickListener(this);
+ MaterialButton mainButton = (MaterialButton) view.findViewById(R.id.main_button);
+ mainButton.setOnClickListener(this);
+ mainButton.setText(mMainButtonLabel);
+ MaterialButton dismissButton = (MaterialButton) view.findViewById(R.id.dismiss_button);
+ dismissButton.setOnClickListener(this);
+ dismissButton.setText(mDismissButtonLabel);
if (!mPowerUsageFeatureProvider.isBatteryTipsFeedbackEnabled()) {
return;
@@ -91,9 +128,9 @@
.setBackgroundResource(R.drawable.battery_tips_half_rounded_top_bg);
view.findViewById(R.id.feedback_card).setVisibility(View.VISIBLE);
- mThumbUpButton = (ImageButton) view.findViewById(R.id.thumb_up);
- mThumbUpButton.setOnClickListener(this);
- mThumbDownButton = (ImageButton) view.findViewById(R.id.thumb_down);
- mThumbDownButton.setOnClickListener(this);
+ ImageButton thumbUpButton = (ImageButton) view.findViewById(R.id.thumb_up);
+ thumbUpButton.setOnClickListener(this);
+ ImageButton thumbDownButton = (ImageButton) view.findViewById(R.id.thumb_down);
+ thumbDownButton.setOnClickListener(this);
}
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java
index 87c43a1..91fe59c 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java
@@ -17,13 +17,18 @@
package com.android.settings.fuelgauge.batteryusage;
import android.content.Context;
+import android.text.TextUtils;
import androidx.preference.PreferenceScreen;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
+import java.util.function.Function;
+
/** Controls the update for battery tips card */
public class BatteryTipsController extends BasePreferenceController {
@@ -31,15 +36,23 @@
private static final String ROOT_PREFERENCE_KEY = "battery_tips_category";
private static final String CARD_PREFERENCE_KEY = "battery_tips_card";
- private final PowerUsageFeatureProvider mPowerUsageFeatureProvider;
+ private final String[] mPowerAnomalyKeys;
- private Context mPrefContext;
- private BatteryTipsCardPreference mCardPreference;
+ @VisibleForTesting
+ BatteryTipsCardPreference mCardPreference;
+ @VisibleForTesting
+ PowerUsageFeatureProvider mPowerUsageFeatureProvider;
public BatteryTipsController(Context context) {
super(context, ROOT_PREFERENCE_KEY);
mPowerUsageFeatureProvider = FeatureFactory.getFeatureFactory()
.getPowerUsageFeatureProvider();
+ mPowerAnomalyKeys = context.getResources().getStringArray(R.array.power_anomaly_keys);
+ }
+
+ private boolean isTipsCardVisible() {
+ // TODO: compared with the timestamp of last user dismiss action in sharedPreference.
+ return mPowerUsageFeatureProvider.isBatteryTipsEnabled();
}
@Override
@@ -50,28 +63,89 @@
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
- mPrefContext = screen.getContext();
mCardPreference = screen.findPreference(CARD_PREFERENCE_KEY);
}
- /**
- * Update the card visibility and contents.
- * @param title a string not extend 2 lines.
- * @param summary a string not extend 10 lines.
- */
- // TODO: replace parameters with SettingsAnomaly Data Proto
- public void handleBatteryTipsCardUpdated(String title, String summary) {
- if (!mPowerUsageFeatureProvider.isBatteryTipsEnabled()) {
- mCardPreference.setVisible(false);
- return;
+ @VisibleForTesting
+ int getPowerAnomalyEventIndex(String powerAnomalyKey) {
+ for (int index = 0; index < mPowerAnomalyKeys.length; index++) {
+ if (mPowerAnomalyKeys[index].equals(powerAnomalyKey)) {
+ return index;
+ }
}
- if (title == null || summary == null) {
- mCardPreference.setVisible(false);
- return;
- }
- mCardPreference.setTitle(title);
- mCardPreference.setSummary(summary);
- mCardPreference.setVisible(true);
+ return -1;
}
+ private <T> T getInfo(PowerAnomalyEvent powerAnomalyEvent,
+ Function<WarningBannerInfo, T> warningBannerInfoSupplier,
+ Function<WarningItemInfo, T> warningItemInfoSupplier) {
+ if (powerAnomalyEvent.hasWarningBannerInfo() && warningBannerInfoSupplier != null) {
+ return warningBannerInfoSupplier.apply(powerAnomalyEvent.getWarningBannerInfo());
+ } else if (powerAnomalyEvent.hasWarningItemInfo() && warningItemInfoSupplier != null) {
+ return warningItemInfoSupplier.apply(powerAnomalyEvent.getWarningItemInfo());
+ }
+ return null;
+ }
+
+ private String getString(PowerAnomalyEvent powerAnomalyEvent,
+ Function<WarningBannerInfo, String> warningBannerInfoSupplier,
+ Function<WarningItemInfo, String> warningItemInfoSupplier,
+ int resourceId, int resourceIndex) {
+ String string =
+ getInfo(powerAnomalyEvent, warningBannerInfoSupplier, warningItemInfoSupplier);
+
+ if (!TextUtils.isEmpty(string) || resourceId < 0) {
+ return string;
+ }
+
+ if (resourceIndex >= 0) {
+ string = mContext.getResources().getStringArray(resourceId)[resourceIndex];
+ }
+
+ return string;
+ }
+
+ @VisibleForTesting
+ void handleBatteryTipsCardUpdated(PowerAnomalyEvent powerAnomalyEvent) {
+ if (!isTipsCardVisible()) {
+ mCardPreference.setVisible(false);
+ return;
+ }
+ if (powerAnomalyEvent == null) {
+ mCardPreference.setVisible(false);
+ return;
+ }
+
+ // Get card preference strings and navigate fragment info
+ final int index = getPowerAnomalyEventIndex(powerAnomalyEvent.getKey());
+
+ String titleString = getString(powerAnomalyEvent, WarningBannerInfo::getTitleString,
+ WarningItemInfo::getTitleString, R.array.power_anomaly_titles, index);
+ if (titleString.isEmpty()) {
+ mCardPreference.setVisible(false);
+ return;
+ }
+
+ String mainBtnString = getString(powerAnomalyEvent,
+ WarningBannerInfo::getMainButtonString, WarningItemInfo::getMainButtonString,
+ R.array.power_anomaly_main_btn_strings, index);
+ String dismissBtnString = getString(powerAnomalyEvent,
+ WarningBannerInfo::getCancelButtonString, WarningItemInfo::getCancelButtonString,
+ R.array.power_anomaly_dismiss_btn_strings, index);
+
+ String destinationClassName = getString(powerAnomalyEvent,
+ WarningBannerInfo::getMainButtonDestination,
+ WarningItemInfo::getMainButtonDestination,
+ -1, -1);
+ Integer sourceMetricsCategory = getInfo(powerAnomalyEvent,
+ WarningBannerInfo::getMainButtonSourceMetricsCategory,
+ WarningItemInfo::getMainButtonSourceMetricsCategory);
+
+ // Updated card preference and main button fragment launcher
+ mCardPreference.setTitle(titleString);
+ mCardPreference.setMainButtonLabel(mainBtnString);
+ mCardPreference.setDismissButtonLabel(dismissBtnString);
+ mCardPreference.setMainButtonLauncherInfo(destinationClassName, sourceMetricsCategory);
+ mCardPreference.setVisible(true);
+ }
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java b/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
index 3fc44cc..5fc4ad5 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
@@ -17,6 +17,7 @@
import android.annotation.IntDef;
import android.annotation.Nullable;
+import android.app.usage.IUsageStatsManager;
import android.app.usage.UsageEvents.Event;
import android.app.usage.UsageStatsManager;
import android.content.ContentValues;
@@ -185,7 +186,8 @@
/** Converts to {@link AppUsageEvent} from {@link Event} */
@Nullable
public static AppUsageEvent convertToAppUsageEvent(
- Context context, final Event event, final long userId) {
+ Context context, IUsageStatsManager usageStatsManager, final Event event,
+ final long userId) {
final String packageName = event.getPackageName();
if (packageName == null) {
// See b/190609174: Event package names should never be null, but sometimes they are.
@@ -210,7 +212,8 @@
}
final String effectivePackageName =
- getEffectivePackageName(context, packageName, taskRootPackageName);
+ getEffectivePackageName(
+ context, usageStatsManager, packageName, taskRootPackageName);
try {
final long uid = context
.getPackageManager()
@@ -326,8 +329,9 @@
*/
@VisibleForTesting
static String getEffectivePackageName(
- Context context, final String packageName, final String taskRootPackageName) {
- final int usageSource = getUsageSource(context);
+ Context context, IUsageStatsManager usageStatsManager, final String packageName,
+ final String taskRootPackageName) {
+ final int usageSource = getUsageSource(context, usageStatsManager);
switch (usageSource) {
case UsageStatsManager.USAGE_SOURCE_TASK_ROOT_ACTIVITY:
return !TextUtils.isEmpty(taskRootPackageName)
@@ -372,9 +376,9 @@
}
}
- private static int getUsageSource(Context context) {
+ private static int getUsageSource(Context context, IUsageStatsManager usageStatsManager) {
if (sUsageSource == EMPTY_USAGE_SOURCE) {
- sUsageSource = DatabaseUtils.getUsageSource(context);
+ sUsageSource = DatabaseUtils.getUsageSource(context, usageStatsManager);
}
return sUsageSource;
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
index f1a8063..71ed46f 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
@@ -32,6 +32,7 @@
import android.os.BatteryUsageStatsQuery;
import android.os.Process;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.UidBatteryConsumer;
import android.os.UserBatteryConsumer;
import android.os.UserHandle;
@@ -108,6 +109,11 @@
@VisibleForTesting
static Set<String> sTestSystemAppsPackageNames;
+ @VisibleForTesting
+ static IUsageStatsManager sUsageStatsManager =
+ IUsageStatsManager.Stub.asInterface(
+ ServiceManager.getService(Context.USAGE_STATS_SERVICE));
+
public static final String CURRENT_TIME_BATTERY_HISTORY_PLACEHOLDER =
"CURRENT_TIME_BATTERY_HISTORY_PLACEHOLDER";
@@ -338,7 +344,8 @@
break;
}
final AppUsageEvent appUsageEvent =
- ConvertUtils.convertToAppUsageEvent(context, event, userId);
+ ConvertUtils.convertToAppUsageEvent(
+ context, sUsageStatsManager, event, userId);
if (appUsageEvent != null) {
numEventsFetched++;
appUsageEventList.add(appUsageEvent);
@@ -694,6 +701,7 @@
final long eventUserId = firstEvent.getUserId();
final String packageName = getEffectivePackageName(
context,
+ sUsageStatsManager,
firstEvent.getPackageName(),
firstEvent.getTaskRootPackageName());
usageEvents.addAll(deviceEvents);
@@ -966,7 +974,7 @@
final long startTime = DatabaseUtils.getAppUsageStartTimestampOfUser(
context, userID, earliestTimestamp);
return loadAppUsageEventsForUserFromService(
- DatabaseUtils.sUsageStatsManager, startTime, now, userID, callingPackage);
+ sUsageStatsManager, startTime, now, userID, callingPackage);
}
@Nullable
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
index ea1f3ed..b54563b 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
@@ -31,7 +31,6 @@
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserManager;
import android.util.Log;
@@ -117,11 +116,6 @@
@VisibleForTesting
static Supplier<Cursor> sFakeSupplier;
- @VisibleForTesting
- static IUsageStatsManager sUsageStatsManager =
- IUsageStatsManager.Stub.asInterface(
- ServiceManager.getService(Context.USAGE_STATS_SERVICE));
-
private DatabaseUtils() {
}
@@ -488,7 +482,7 @@
*
* @see UsageStatsManager#getUsageSource()
*/
- static int getUsageSource(Context context) {
+ static int getUsageSource(Context context, IUsageStatsManager usageStatsManager) {
final SharedPreferences sharedPreferences = getSharedPreferences(context);
if (sharedPreferences != null && sharedPreferences.contains(KEY_LAST_USAGE_SOURCE)) {
return sharedPreferences
@@ -497,7 +491,7 @@
int usageSource = ConvertUtils.DEFAULT_USAGE_SOURCE;
try {
- usageSource = sUsageStatsManager.getUsageSource();
+ usageSource = usageStatsManager.getUsageSource();
} catch (RemoteException e) {
Log.e(TAG, "Failed to getUsageSource", e);
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/SpinnerPreference.java b/src/com/android/settings/fuelgauge/batteryusage/SpinnerPreference.java
index ac3e26d..f57c85a 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/SpinnerPreference.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/SpinnerPreference.java
@@ -84,6 +84,7 @@
return;
}
if (!(state instanceof SavedState)) {
+ super.onRestoreInstanceState(state);
return;
}
SavedState savedState = (SavedState) state;
diff --git a/src/com/android/settings/fuelgauge/protos/power_anomaly_event.proto b/src/com/android/settings/fuelgauge/protos/power_anomaly_event.proto
index b4277c4..380c786 100644
--- a/src/com/android/settings/fuelgauge/protos/power_anomaly_event.proto
+++ b/src/com/android/settings/fuelgauge/protos/power_anomaly_event.proto
@@ -4,14 +4,19 @@
option java_package = "com.android.settings.fuelgauge.batteryusage";
option java_outer_classname = "PowerAnomalyEventProto";
+message PowerAnomalyEventList {
+ repeated PowerAnomalyEvent power_anomaly_events = 1;
+}
+
message PowerAnomalyEvent {
- optional int64 timestamp = 1;
- optional string type = 2; // e.g. settings, apps
- optional string key = 3; // e.g. brightness, significant_increase
- optional float score = 4;
+ optional string event_id = 1;
+ optional int64 timestamp = 2;
+ optional string type = 3; // e.g. settings, apps
+ optional string key = 4; // e.g. brightness, significant_increase
+ optional float score = 5;
oneof info {
- WarningBannerInfo warning_banner_info = 5;
- WarningItemInfo warning_item_info = 6;
+ WarningBannerInfo warning_banner_info = 6;
+ WarningItemInfo warning_item_info = 7;
}
}
@@ -19,9 +24,11 @@
optional string title_string = 1;
optional string description_string = 2;
optional string main_button_string = 3;
- optional string main_button_action = 4;
- optional string cancel_button_string = 5;
- optional string cancel_button_action = 6;
+ // Used in the SubSettingLauncher.setDestination().
+ optional string main_button_destination = 4;
+ // Used in the SubSettingLauncher.setSourceMetricsCategory().
+ optional int32 main_button_source_metrics_category = 5;
+ optional string cancel_button_string = 6;
}
message WarningItemInfo {
@@ -31,7 +38,9 @@
optional string title_string = 4;
optional string description_string = 5;
optional string main_button_string = 6;
- optional string main_button_action = 7;
- optional string cancel_button_string = 8;
- optional string cancel_button_action = 9;
+ // Used in the SubSettingLauncher.setDestination().
+ optional string main_button_destination = 7;
+ // Used in the SubSettingLauncher.setSourceMetricsCategory().
+ optional int32 main_button_source_metrics_category = 8;
+ optional string cancel_button_string = 9;
}
diff --git a/src/com/android/settings/localepicker/LocaleListEditor.java b/src/com/android/settings/localepicker/LocaleListEditor.java
index 934a048..d9109c3 100644
--- a/src/com/android/settings/localepicker/LocaleListEditor.java
+++ b/src/com/android/settings/localepicker/LocaleListEditor.java
@@ -364,6 +364,7 @@
}
});
mSuggestionDialog = dialogBuilder.create();
+ mSuggestionDialog.setCanceledOnTouchOutside(false);
mSuggestionDialog.show();
} else {
Log.d(TAG, "Invalid parameter, dialogType:" + dialogType);
diff --git a/src/com/android/settings/network/NetworkProviderSettings.java b/src/com/android/settings/network/NetworkProviderSettings.java
index 1375ffc..3cbf13d 100644
--- a/src/com/android/settings/network/NetworkProviderSettings.java
+++ b/src/com/android/settings/network/NetworkProviderSettings.java
@@ -137,6 +137,8 @@
@VisibleForTesting
static final String PREF_KEY_FIRST_ACCESS_POINTS = "first_access_points";
private static final String PREF_KEY_ACCESS_POINTS = "access_points";
+ @VisibleForTesting
+ static final String PREF_KEY_ADD_WIFI_NETWORK = "add_wifi_network";
private static final String PREF_KEY_CONFIGURE_NETWORK_SETTINGS = "configure_network_settings";
private static final String PREF_KEY_SAVED_NETWORKS = "saved_networks";
@VisibleForTesting
@@ -322,7 +324,10 @@
mWifiEntryPreferenceCategory = findPreference(PREF_KEY_ACCESS_POINTS);
mConfigureWifiSettingsPreference = findPreference(PREF_KEY_CONFIGURE_NETWORK_SETTINGS);
mSavedNetworksPreference = findPreference(PREF_KEY_SAVED_NETWORKS);
- mAddWifiNetworkPreference = new AddWifiNetworkPreference(getPrefContext());
+ mAddWifiNetworkPreference = findPreference(PREF_KEY_ADD_WIFI_NETWORK);
+ // Hide mAddWifiNetworkPreference by default. updateWifiEntryPreferences() will add it back
+ // later when appropriate.
+ mWifiEntryPreferenceCategory.removePreference(mAddWifiNetworkPreference);
mDataUsagePreference = findPreference(PREF_KEY_DATA_USAGE);
mDataUsagePreference.setVisible(DataUsageUtils.hasWifiRadio(getContext()));
mDataUsagePreference.setTemplate(new NetworkTemplate.Builder(NetworkTemplate.MATCH_WIFI)
@@ -1291,6 +1296,9 @@
if (WifiSavedConfigUtils.getAllConfigsCount(context, wifiManager) == 0) {
keys.add(PREF_KEY_SAVED_NETWORKS);
}
+ if (wifiManager.getWifiState() != WifiManager.WIFI_STATE_ENABLED) {
+ keys.add(PREF_KEY_ADD_WIFI_NETWORK);
+ }
if (!DataUsageUtils.hasWifiRadio(context)) {
keys.add(PREF_KEY_DATA_USAGE);
diff --git a/src/com/android/settings/network/telephony/Enable2gPreferenceController.java b/src/com/android/settings/network/telephony/Enable2gPreferenceController.java
index 765df51..9d9958f 100644
--- a/src/com/android/settings/network/telephony/Enable2gPreferenceController.java
+++ b/src/com/android/settings/network/telephony/Enable2gPreferenceController.java
@@ -119,20 +119,21 @@
String summary;
if (isDisabledByCarrier) {
summary = mContext.getString(R.string.enable_2g_summary_disabled_carrier,
- getCarrierName());
+ getSimCardName());
} else {
summary = mContext.getString(R.string.enable_2g_summary);
}
preference.setSummary(summary);
}
- private String getCarrierName() {
+ private String getSimCardName() {
SubscriptionInfo subInfo = SubscriptionUtil.getSubById(mSubscriptionManager, mSubId);
if (subInfo == null) {
return "";
}
- CharSequence carrierName = subInfo.getCarrierName();
- return TextUtils.isEmpty(carrierName) ? "" : carrierName.toString();
+ // It is the sim card name, and it should be the same name as the sim page.
+ CharSequence simCardName = subInfo.getDisplayName();
+ return TextUtils.isEmpty(simCardName) ? "" : simCardName.toString();
}
/**
diff --git a/src/com/android/settings/notification/app/FullScreenIntentPermissionPreferenceController.kt b/src/com/android/settings/notification/app/FullScreenIntentPermissionPreferenceController.kt
index ec99749..2cc26f6 100644
--- a/src/com/android/settings/notification/app/FullScreenIntentPermissionPreferenceController.kt
+++ b/src/com/android/settings/notification/app/FullScreenIntentPermissionPreferenceController.kt
@@ -81,7 +81,7 @@
private fun isPermissionRequested(): Boolean {
val packageInfo = packageManager.getPackageInfo(packageName, GET_PERMISSIONS)
- for (requestedPermission in packageInfo.requestedPermissions) {
+ for (requestedPermission in packageInfo.requestedPermissions.orEmpty()) {
if (USE_FULL_SCREEN_INTENT.equals(requestedPermission)) {
return true
}
@@ -115,4 +115,4 @@
const val KEY_FSI_PERMISSION = "fsi_permission"
const val TAG = "FsiPermPrefController"
}
-}
\ No newline at end of file
+}
diff --git a/src/com/android/settings/onboarding/OnboardingFeatureProvider.kt b/src/com/android/settings/onboarding/OnboardingFeatureProvider.kt
new file mode 100644
index 0000000..054694f
--- /dev/null
+++ b/src/com/android/settings/onboarding/OnboardingFeatureProvider.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2023 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.settings.onboarding
+
+import android.content.Context
+
+/**
+ * Provider for Onboarding related features.
+ */
+interface OnboardingFeatureProvider {
+ /**
+ * Mark this toggle preference has been changed.
+ * Called after [TogglePreferenceController.onPreferenceChange()].
+ *
+ * @param context App context
+ * @param preferenceKey The key to distinguish which preference has been changed.
+ */
+ fun markPreferenceHasChanged(context: Context, preferenceKey: String)
+}
\ No newline at end of file
diff --git a/src/com/android/settings/overlay/FeatureFactory.kt b/src/com/android/settings/overlay/FeatureFactory.kt
index 256acf4..bda0e17 100644
--- a/src/com/android/settings/overlay/FeatureFactory.kt
+++ b/src/com/android/settings/overlay/FeatureFactory.kt
@@ -24,6 +24,7 @@
import com.android.settings.biometrics2.factory.BiometricsRepositoryProvider
import com.android.settings.bluetooth.BluetoothFeatureProvider
import com.android.settings.connecteddevice.stylus.StylusFeatureProvider
+import com.android.settings.onboarding.OnboardingFeatureProvider
import com.android.settings.dashboard.DashboardFeatureProvider
import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider
import com.android.settings.deviceinfo.hardwareinfo.HardwareInfoFeatureProvider
@@ -149,6 +150,11 @@
*/
abstract val stylusFeatureProvider: StylusFeatureProvider
+ /**
+ * Retrieves implementation for TogglePreference feature.
+ */
+ open val onboardingFeatureProvider: OnboardingFeatureProvider? = null
+
companion object {
private var _factory: FeatureFactory? = null
diff --git a/src/com/android/settings/print/PrintServiceSettingsFragment.java b/src/com/android/settings/print/PrintServiceSettingsFragment.java
index 39b5ab9..c5316e6 100644
--- a/src/com/android/settings/print/PrintServiceSettingsFragment.java
+++ b/src/com/android/settings/print/PrintServiceSettingsFragment.java
@@ -17,6 +17,7 @@
package com.android.settings.print;
import android.app.Activity;
+import android.app.ActivityOptions;
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.Context;
@@ -547,8 +548,13 @@
@Override
public void onClick(View v) {
try {
+ Bundle options = ActivityOptions.makeBasic()
+ .setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED)
+ .toBundle();
getActivity().startIntentSender(
- printer.getInfoIntent().getIntentSender(), null, 0, 0, 0);
+ printer.getInfoIntent().getIntentSender(), null, 0, 0, 0,
+ options);
} catch (SendIntentException e) {
Log.e(LOG_TAG, "Could not execute pending info intent: %s", e);
}
diff --git a/src/com/android/settings/remoteauth/RemoteAuthEnrollBase.kt b/src/com/android/settings/remoteauth/RemoteAuthEnrollBase.kt
index e00faec..05be7ad 100644
--- a/src/com/android/settings/remoteauth/RemoteAuthEnrollBase.kt
+++ b/src/com/android/settings/remoteauth/RemoteAuthEnrollBase.kt
@@ -65,7 +65,7 @@
abstract fun initializeSecondaryFooterButton(): FooterButton?
private fun initializeFooterbarMixin(view: View) {
- val footerBarMixin = getGlifLayout(view).getMixin(FooterBarMixin::class.java)
+ val footerBarMixin = checkNotNull(getGlifLayout(view)).getMixin(FooterBarMixin::class.java)
primaryFooterButton.also { footerBarMixin.primaryButton = it }
secondaryFooterButton?.also { footerBarMixin.secondaryButton = it }
footerBarMixin.getButtonContainer().setBackgroundColor(getBackgroundColor())
@@ -80,4 +80,4 @@
private companion object{
const val TAG = "RemoteAuthEnrollBase"
}
-}
\ No newline at end of file
+}
diff --git a/src/com/android/settings/remoteauth/finish/RemoteAuthEnrollFinish.kt b/src/com/android/settings/remoteauth/finish/RemoteAuthEnrollFinish.kt
index c55b4ed..98df572 100644
--- a/src/com/android/settings/remoteauth/finish/RemoteAuthEnrollFinish.kt
+++ b/src/com/android/settings/remoteauth/finish/RemoteAuthEnrollFinish.kt
@@ -18,12 +18,10 @@
import android.os.Bundle
import android.view.View
-
+import com.airbnb.lottie.LottieAnimationView
import com.android.settings.R
import com.android.settings.remoteauth.RemoteAuthEnrollBase
import com.android.settingslib.widget.LottieColorUtils
-
-import com.airbnb.lottie.LottieAnimationView
import com.google.android.setupcompat.template.FooterButton
/**
@@ -45,7 +43,7 @@
.setText(R.string.security_settings_remoteauth_enroll_finish_btn_next)
.setListener(this::onPrimaryFooterButtonClick)
.setButtonType(FooterButton.ButtonType.NEXT)
- .setTheme(R.style.SudGlifButton_Primary)
+ .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Primary)
.build()
}
diff --git a/src/com/android/settings/remoteauth/introduction/IntroductionImageCarousel.kt b/src/com/android/settings/remoteauth/introduction/IntroductionImageCarousel.kt
index ffc683e..ad85763 100644
--- a/src/com/android/settings/remoteauth/introduction/IntroductionImageCarousel.kt
+++ b/src/com/android/settings/remoteauth/introduction/IntroductionImageCarousel.kt
@@ -38,13 +38,15 @@
import com.android.settingslib.widget.LottieColorUtils
class IntroductionImageCarousel : ConstraintLayout {
- private val carousel: ViewPager2 by lazy { findViewById<ViewPager2>(R.id.image_carousel) }
+ private val carousel: ViewPager2 by lazy { requireViewById<ViewPager2>(R.id.image_carousel) }
private val progressIndicator: RecyclerView by lazy {
- findViewById<RecyclerView>(R.id.carousel_progress_indicator)
+ requireViewById<RecyclerView>(R.id.carousel_progress_indicator)
}
- private val backArrow: ImageView by lazy { findViewById<ImageView>(R.id.carousel_back_arrow) }
+ private val backArrow: ImageView by lazy {
+ requireViewById<ImageView>(R.id.carousel_back_arrow)
+ }
private val forwardArrow: ImageView by lazy {
- findViewById<ImageView>(R.id.carousel_forward_arrow)
+ requireViewById<ImageView>(R.id.carousel_forward_arrow)
}
private val progressIndicatorAdapter = ProgressIndicatorAdapter()
// The index of the current animation we are on
@@ -156,4 +158,4 @@
)
const val TAG = "RemoteAuthCarousel"
}
-}
\ No newline at end of file
+}
diff --git a/src/com/android/settings/remoteauth/introduction/RemoteAuthEnrollIntroduction.kt b/src/com/android/settings/remoteauth/introduction/RemoteAuthEnrollIntroduction.kt
index 21b8af2..268d5f3 100644
--- a/src/com/android/settings/remoteauth/introduction/RemoteAuthEnrollIntroduction.kt
+++ b/src/com/android/settings/remoteauth/introduction/RemoteAuthEnrollIntroduction.kt
@@ -49,7 +49,7 @@
.setText(R.string.security_settings_remoteauth_enroll_introduction_agree)
.setListener(::onPrimaryFooterButtonClick)
.setButtonType(FooterButton.ButtonType.OPT_IN)
- .setTheme(R.style.SudGlifButton_Primary)
+ .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Primary)
.build()
}
@@ -58,7 +58,7 @@
.setText(R.string.security_settings_remoteauth_enroll_introduction_disagree)
.setListener(::onSecondaryFooterButtonClick)
.setButtonType(FooterButton.ButtonType.NEXT)
- .setTheme(R.style.SudGlifButton_Primary)
+ .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Primary)
.build()
}
@@ -71,7 +71,7 @@
}
private fun initializeRequireScrollMixin(view: View) {
- val layout = getGlifLayout(view)
+ val layout = checkNotNull(getGlifLayout(view))
secondaryFooterButton?.visibility = View.INVISIBLE
val requireScrollMixin = layout.getMixin(RequireScrollMixin::class.java)
requireScrollMixin.requireScrollWithButton(requireContext(), primaryFooterButton,
@@ -89,4 +89,4 @@
private companion object {
const val TAG = "RemoteAuthEnrollIntro"
}
-}
\ No newline at end of file
+}
diff --git a/src/com/android/settings/safetycenter/BiometricsSafetySource.java b/src/com/android/settings/safetycenter/BiometricsSafetySource.java
index 9dc5b4e..94db71f 100644
--- a/src/com/android/settings/safetycenter/BiometricsSafetySource.java
+++ b/src/com/android/settings/safetycenter/BiometricsSafetySource.java
@@ -164,7 +164,12 @@
disablingAdmin == null /* enabled */,
fingerprintStatusUtils.hasEnrolled(),
safetyEvent);
+ return;
}
+
+ SafetyCenterManagerWrapper.get()
+ .setSafetySourceData(
+ context, SAFETY_SOURCE_ID, /* safetySourceData= */ null, safetyEvent);
}
/** Notifies Safety Center of a change in biometrics settings. */
diff --git a/src/com/android/settings/safetycenter/LockScreenSafetySource.java b/src/com/android/settings/safetycenter/LockScreenSafetySource.java
index de20e24..4e085c1 100644
--- a/src/com/android/settings/safetycenter/LockScreenSafetySource.java
+++ b/src/com/android/settings/safetycenter/LockScreenSafetySource.java
@@ -63,6 +63,12 @@
}
if (!screenLockPreferenceDetailsUtils.isAvailable()) {
+ SafetyCenterManagerWrapper.get().setSafetySourceData(
+ context,
+ SAFETY_SOURCE_ID,
+ /* safetySourceData= */ null,
+ safetyEvent
+ );
return;
}
diff --git a/src/com/android/settings/search/actionbar/SearchMenuController.java b/src/com/android/settings/search/actionbar/SearchMenuController.java
index dbaa5de..8d0c89a 100644
--- a/src/com/android/settings/search/actionbar/SearchMenuController.java
+++ b/src/com/android/settings/search/actionbar/SearchMenuController.java
@@ -86,8 +86,8 @@
return;
}
final MenuItem searchItem = menu.add(Menu.NONE, MENU_SEARCH, 0 /* order */,
- R.string.search_menu);
- searchItem.setIcon(com.android.settingslib.widget.R.drawable.ic_search_24dp);
+ com.android.settingslib.search.R.string.search_menu);
+ searchItem.setIcon(com.android.settingslib.search.R.drawable.ic_search_24dp);
searchItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
searchItem.setOnMenuItemClickListener(target -> {
diff --git a/src/com/android/settings/security/screenlock/PinPrivacyPreferenceController.kt b/src/com/android/settings/security/screenlock/PinPrivacyPreferenceController.kt
index 176183e..78656e8 100644
--- a/src/com/android/settings/security/screenlock/PinPrivacyPreferenceController.kt
+++ b/src/com/android/settings/security/screenlock/PinPrivacyPreferenceController.kt
@@ -45,7 +45,7 @@
return PREF_KEY
}
- override fun onPreferenceChange(preference: Preference?, value: Any?): Boolean {
+ override fun onPreferenceChange(preference: Preference, value: Any): Boolean {
lockPatternUtils.setPinEnhancedPrivacyEnabled((value as Boolean), userId)
return true
}
diff --git a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt
index 12f5b09..34cf3ee 100644
--- a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt
+++ b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt
@@ -47,6 +47,9 @@
import com.android.settingslib.spa.framework.util.filterItem
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
+import com.android.settingslib.spa.widget.illustration.Illustration
+import com.android.settingslib.spa.widget.illustration.IllustrationModel
+import com.android.settingslib.spa.widget.illustration.ResourceType
import com.android.settingslib.spa.widget.ui.SettingsBody
import com.android.settingslib.spa.widget.ui.SpinnerOption
import com.android.settingslib.spaprivileged.model.app.AppListModel
@@ -108,6 +111,10 @@
Box(Modifier.padding(SettingsDimension.itemPadding)) {
SettingsBody(UserAspectRatioAppsPageProvider.getSummary())
}
+ Illustration(object : IllustrationModel {
+ override val resId = R.raw.user_aspect_ratio_education
+ override val resourceType = ResourceType.LOTTIE
+ })
}
)
}
diff --git a/src/com/android/settings/spa/app/appinfo/AppButtons.kt b/src/com/android/settings/spa/app/appinfo/AppButtons.kt
index 2e9d945..3200b81 100644
--- a/src/com/android/settings/spa/app/appinfo/AppButtons.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppButtons.kt
@@ -45,7 +45,7 @@
@Composable
fun getActionButtons() =
packageInfoPresenter.flow.collectAsStateWithLifecycle(initialValue = null).value?.let {
- getActionButtons(it.applicationInfo)
+ getActionButtons(checkNotNull(it.applicationInfo))
} ?: emptyList()
@Composable
diff --git a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt
index c38d6cf..a9d16ae 100644
--- a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt
@@ -118,7 +118,7 @@
private fun AppInfoSettings(packageInfoPresenter: PackageInfoPresenter) {
LifecycleEffect(onStart = { packageInfoPresenter.reloadPackageInfo() })
val packageInfo = packageInfoPresenter.flow.collectAsStateWithLifecycle().value ?: return
- val app = packageInfo.applicationInfo
+ val app = checkNotNull(packageInfo.applicationInfo)
RegularScaffold(
title = stringResource(R.string.application_info_label),
actions = {
diff --git a/src/com/android/settings/spa/app/appinfo/ClonePageAppButtons.kt b/src/com/android/settings/spa/app/appinfo/ClonePageAppButtons.kt
index 0603f2a..ddc7e17 100644
--- a/src/com/android/settings/spa/app/appinfo/ClonePageAppButtons.kt
+++ b/src/com/android/settings/spa/app/appinfo/ClonePageAppButtons.kt
@@ -41,7 +41,7 @@
@Composable
fun getActionButtons() =
packageInfoPresenter.flow.collectAsStateWithLifecycle(initialValue = null).value?.let {
- getActionButtons(it.applicationInfo)
+ getActionButtons(checkNotNull(it.applicationInfo))
} ?: emptyList()
@Composable
diff --git a/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt b/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt
index 099a274..98a3e66 100644
--- a/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt
+++ b/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt
@@ -77,7 +77,7 @@
DisposableBroadcastReceiverAsUser(intentFilter, userHandle) { intent ->
if (packageName == intent.data?.schemeSpecificPart) {
val packageInfo = flow.value
- if (packageInfo != null && packageInfo.applicationInfo.isSystemApp) {
+ if (packageInfo != null && packageInfo.applicationInfo?.isSystemApp == true) {
// System app still exists after uninstalling the updates, refresh the page.
reloadPackageInfo()
} else {
diff --git a/src/com/android/settings/wifi/AddWifiNetworkPreference.java b/src/com/android/settings/wifi/AddWifiNetworkPreference.java
index 6aafbca..999f4a4 100644
--- a/src/com/android/settings/wifi/AddWifiNetworkPreference.java
+++ b/src/com/android/settings/wifi/AddWifiNetworkPreference.java
@@ -20,10 +20,12 @@
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.UserManager;
+import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageButton;
import androidx.annotation.DrawableRes;
+import androidx.annotation.Nullable;
import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
@@ -40,8 +42,11 @@
private final Drawable mScanIconDrawable;
public AddWifiNetworkPreference(Context context) {
- super(context);
+ this(context, null);
+ }
+ public AddWifiNetworkPreference(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
setLayoutResource(com.android.settingslib.R.layout.preference_access_point);
setWidgetLayoutResource(R.layout.wifi_button_preference_widget);
setIcon(R.drawable.ic_add_24dp);
diff --git a/src/com/android/settings/wifi/dpp/WifiDppConfiguratorAuthActivity.java b/src/com/android/settings/wifi/dpp/WifiDppConfiguratorAuthActivity.java
new file mode 100644
index 0000000..aa77dc1
--- /dev/null
+++ b/src/com/android/settings/wifi/dpp/WifiDppConfiguratorAuthActivity.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2023 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.settings.wifi.dpp;
+
+import static android.content.Intent.ACTION_CLOSE_SYSTEM_DIALOGS;
+import static android.content.Intent.FLAG_RECEIVER_FOREGROUND;
+
+import android.app.Activity;
+import android.app.KeyguardManager;
+import android.app.settings.SettingsEnums;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+import androidx.activity.result.ActivityResult;
+import androidx.activity.result.contract.ActivityResultContracts;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.R;
+import com.android.settings.core.InstrumentedActivity;
+
+/**
+ * Sharing a Wi-Fi network by QR code after unlocking. Used by {@code InternetDialog} in QS.
+ */
+public class WifiDppConfiguratorAuthActivity extends InstrumentedActivity {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ // This is a transparent activity, disable the dim.
+ getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+ Intent authIntent = getSystemService(KeyguardManager.class)
+ .createConfirmDeviceCredentialIntent(
+ getText(R.string.wifi_dpp_lockscreen_title), null, getUserId());
+ if (authIntent == null) {
+ startQrCodeActivity();
+ finish();
+ } else {
+ registerForActivityResult(
+ new ActivityResultContracts.StartActivityForResult(),
+ this::onAuthResult).launch(authIntent);
+ }
+ }
+
+ @VisibleForTesting
+ void onAuthResult(ActivityResult result) {
+ if (result.getResultCode() == Activity.RESULT_OK) {
+ startQrCodeActivity();
+ }
+ finish();
+ }
+
+ private void startQrCodeActivity() {
+ // Close quick settings shade
+ sendBroadcast(
+ new Intent(ACTION_CLOSE_SYSTEM_DIALOGS).setFlags(FLAG_RECEIVER_FOREGROUND));
+ Intent qrCodeIntent = new Intent();
+ qrCodeIntent.setAction(
+ WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_GENERATOR);
+ qrCodeIntent.putExtras(getIntent());
+ startActivity(qrCodeIntent);
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return SettingsEnums.SETTINGS_WIFI_DPP_CONFIGURATOR;
+ }
+}
diff --git a/tests/componenttests/src/com/android/settings/wifi/dpp/WifiDppConfiguratorAuthActivityTest.java b/tests/componenttests/src/com/android/settings/wifi/dpp/WifiDppConfiguratorAuthActivityTest.java
new file mode 100644
index 0000000..94b9369
--- /dev/null
+++ b/tests/componenttests/src/com/android/settings/wifi/dpp/WifiDppConfiguratorAuthActivityTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2023 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.settings.wifi.dpp;
+
+import static android.app.Activity.RESULT_OK;
+
+import static androidx.test.espresso.intent.Intents.intended;
+import static androidx.test.espresso.intent.matcher.IntentMatchers.hasAction;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.hamcrest.Matchers.equalTo;
+
+import android.app.KeyguardManager;
+
+import androidx.activity.result.ActivityResult;
+import androidx.test.core.app.ActivityScenario;
+import androidx.test.espresso.intent.Intents;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class WifiDppConfiguratorAuthActivityTest {
+
+ @Before
+ public void setup() {
+ Intents.init();
+ }
+
+ @After
+ public void teardown() throws Exception {
+ Intents.release();
+ }
+
+ @Test
+ public void launchActivity_sendAuthIntent() {
+ ActivityScenario<WifiDppConfiguratorAuthActivity> activityScenario =
+ ActivityScenario.launch(WifiDppConfiguratorAuthActivity.class);
+ assertThat(activityScenario).isNotNull();
+ intended(hasAction(equalTo(KeyguardManager.ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER)));
+ }
+
+ @Test
+ public void launchActivity_sendQrCodeIntent() {
+ ActivityScenario.launch(WifiDppConfiguratorAuthActivity.class).onActivity(activity ->
+ activity.onAuthResult(new ActivityResult(RESULT_OK, /* data= */ null))
+ );
+ intended(hasAction(
+ equalTo(WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_GENERATOR)));
+ }
+
+ @Test
+ public void launchActivity_shouldFinish() {
+ ActivityScenario.launch(WifiDppConfiguratorAuthActivity.class).onActivity(activity -> {
+ activity.onAuthResult(new ActivityResult(RESULT_OK, /* data= */ null));
+ assertThat(activity.isFinishing()).isTrue();
+ });
+ }
+}
diff --git a/tests/robotests/Android.bp b/tests/robotests/Android.bp
index c2b7c6a..2bd8721 100644
--- a/tests/robotests/Android.bp
+++ b/tests/robotests/Android.bp
@@ -1,7 +1,3 @@
- //############################################################
-// Build SettingsRoboTestStub.apk which includes test-only resources.#
-//############################################################
-
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
@@ -11,6 +7,7 @@
default_applicable_licenses: ["packages_apps_Settings_license"],
}
+// Build SettingsRoboTestStub.apk which includes test-only resources.
android_app {
name: "SettingsRoboTestStub",
defaults: [
@@ -25,33 +22,8 @@
static_libs: [
"Settings-core",
- "androidx-constraintlayout_constraintlayout",
- "androidx.slice_slice-builders",
- "androidx.slice_slice-core",
- "androidx.slice_slice-view",
- "androidx.core_core",
- "androidx.appcompat_appcompat",
- "androidx.cardview_cardview",
"androidx.fragment_fragment-testing",
- "androidx.preference_preference",
- "androidx.recyclerview_recyclerview",
- "androidx.window_window",
- "com.google.android.material_material",
- "setupcompat",
- "setupdesign",
- "androidx.lifecycle_lifecycle-runtime",
- "androidx.test.core",
- "androidx.test.runner",
- "androidx.test.ext.junit",
"frameworks-base-testutils",
- "guava",
- "jsr305",
- "settings-contextual-card-protos-lite",
- "settings-log-bridge-protos-lite",
- "settings-telephony-protos-lite",
- "contextualcards",
- "settings-logtags",
- "zxing-core-1.7",
],
aaptflags: ["--extra-packages com.android.settings"],
@@ -67,9 +39,7 @@
],
}
-//############################################################
-// Settings Robolectric test target. #
-//############################################################
+// Settings Robolectric test target.
android_robolectric_test {
name: "SettingsRoboTests",
srcs: [
@@ -79,12 +49,12 @@
static_libs: [
"SettingsLib-robo-testutils",
- "android-support-annotations",
+ "Settings-robo-testutils",
"androidx.test.core",
+ "androidx.test.espresso.core",
+ "androidx.test.ext.junit",
"androidx.test.rules",
"androidx.test.runner",
- "androidx.test.ext.junit",
- "androidx.test.espresso.core",
],
libs: [
@@ -109,7 +79,7 @@
java_library {
name: "Settings-robo-testutils",
- srcs: ["src/com/android/settings/testutils/**/*.java"],
+ srcs: ["testutils/**/*.java"],
libs: [
"Settings-core",
diff --git a/tests/robotests/src/com/android/settings/applications/appcompat/UserAspectRatioDetailsTest.java b/tests/robotests/src/com/android/settings/applications/appcompat/UserAspectRatioDetailsTest.java
index 31ff76c..d98b0e7 100644
--- a/tests/robotests/src/com/android/settings/applications/appcompat/UserAspectRatioDetailsTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appcompat/UserAspectRatioDetailsTest.java
@@ -32,7 +32,6 @@
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.testutils.shadow.ShadowActivityManager;
-import com.android.settingslib.widget.SelectorWithWidgetPreference;
import org.junit.Before;
import org.junit.Test;
@@ -54,7 +53,7 @@
@Mock
private IActivityManager mAm;
- private SelectorWithWidgetPreference mRadioButtonPref;
+ private RadioWithImagePreference mRadioButtonPref;
private Context mContext;
private UserAspectRatioDetails mFragment;
@@ -67,7 +66,7 @@
when(mFragment.getContext()).thenReturn(mContext);
when(mFragment.getAspectRatioManager()).thenReturn(mUserAspectRatioManager);
ShadowActivityManager.setService(mAm);
- mRadioButtonPref = new SelectorWithWidgetPreference(mContext);
+ mRadioButtonPref = new RadioWithImagePreference(mContext);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioDeviceTypeControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioDeviceTypeControllerTest.java
new file mode 100644
index 0000000..0fc0647
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioDeviceTypeControllerTest.java
@@ -0,0 +1,119 @@
+/*
+ * 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.settings.bluetooth;
+
+import static android.bluetooth.BluetoothDevice.DEVICE_TYPE_LE;
+import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_SPEAKER;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.bluetooth.BluetoothDevice;
+import android.media.AudioManager;
+
+import androidx.preference.ListPreference;
+import androidx.preference.PreferenceCategory;
+
+import com.android.settingslib.bluetooth.LeAudioProfile;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class BluetoothDetailsAudioDeviceTypeControllerTest extends
+ BluetoothDetailsControllerTestBase {
+
+ private static final String MAC_ADDRESS = "04:52:C7:0B:D8:3C";
+ private static final String KEY_BT_AUDIO_DEVICE_TYPE = "bluetooth_audio_device_type";
+
+ @Mock
+ private AudioManager mAudioManager;
+ @Mock
+ private Lifecycle mAudioDeviceTypeLifecycle;
+ @Mock
+ private PreferenceCategory mProfilesContainer;
+ @Mock
+ private BluetoothDevice mBluetoothDevice;
+ @Mock
+ private LocalBluetoothManager mManager;
+ @Mock
+ private LocalBluetoothProfileManager mProfileManager;
+ @Mock
+ private LeAudioProfile mLeAudioProfile;
+ private BluetoothDetailsAudioDeviceTypeController mController;
+ private ListPreference mAudioDeviceTypePref;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mContext = spy(RuntimeEnvironment.application);
+ when(mContext.getSystemService(AudioManager.class)).thenReturn(mAudioManager);
+ when(mCachedDevice.getAddress()).thenReturn(MAC_ADDRESS);
+ when(mCachedDevice.getDevice()).thenReturn(mBluetoothDevice);
+ when(mBluetoothDevice.getAnonymizedAddress()).thenReturn(MAC_ADDRESS);
+ when(mBluetoothDevice.getType()).thenReturn(DEVICE_TYPE_LE);
+ when(mManager.getProfileManager()).thenReturn(mProfileManager);
+ when(mProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile);
+ when(mLeAudioProfile.isEnabled(mCachedDevice.getDevice())).thenReturn(true);
+
+ mController = new BluetoothDetailsAudioDeviceTypeController(mContext, mFragment, mManager,
+ mCachedDevice, mAudioDeviceTypeLifecycle);
+ mController.mProfilesContainer = mProfilesContainer;
+
+ mController.createAudioDeviceTypePreference(mContext);
+ mAudioDeviceTypePref = mController.getAudioDeviceTypePreference();
+
+ when(mProfilesContainer.findPreference(KEY_BT_AUDIO_DEVICE_TYPE)).thenReturn(
+ mAudioDeviceTypePref);
+ }
+
+ @Test
+ public void createAudioDeviceTypePreference_btDeviceIsCategorized_checkSelection() {
+ int deviceType = AUDIO_DEVICE_CATEGORY_SPEAKER;
+ when(mAudioManager.getBluetoothAudioDeviceCategory(MAC_ADDRESS, /*isBle=*/true)).thenReturn(
+ deviceType);
+
+ mController.createAudioDeviceTypePreference(mContext);
+ mAudioDeviceTypePref = mController.getAudioDeviceTypePreference();
+
+ assertThat(mAudioDeviceTypePref.getValue()).isEqualTo(Integer.toString(deviceType));
+ }
+
+ @Test
+ public void selectDeviceTypeSpeaker_invokeSetBluetoothAudioDeviceType() {
+ int deviceType = AUDIO_DEVICE_CATEGORY_SPEAKER;
+ mAudioDeviceTypePref.setValue(Integer.toString(deviceType));
+
+ mController.onPreferenceChange(mAudioDeviceTypePref, Integer.toString(deviceType));
+
+ verify(mAudioManager).setBluetoothAudioDeviceCategory(eq(MAC_ADDRESS), eq(true),
+ eq(AUDIO_DEVICE_CATEGORY_SPEAKER));
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothPairingDialogTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothPairingDialogTest.java
index 517b435..2044881 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothPairingDialogTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothPairingDialogTest.java
@@ -33,7 +33,6 @@
import android.text.TextUtils;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
-import android.widget.CheckBox;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
@@ -276,7 +275,7 @@
}
@Test
- public void contactSharingCheckbox_conditionIsReady_showsUi() {
+ public void contactSharingToggle_conditionIsReady_showsUi() {
// set the dialog variant to confirmation/consent
when(controller.getDialogType()).thenReturn(BluetoothPairingController.CONFIRMATION_DIALOG);
// set a fake device name and pretend the profile has not been set up for it
@@ -286,14 +285,14 @@
// build the fragment
BluetoothPairingDialogFragment frag = makeFragment();
- // verify that the checkbox is visible and that the device name is correct
- CheckBox sharingCheckbox =
- frag.getmDialog().findViewById(R.id.phonebook_sharing_message_confirm_pin);
- assertThat(sharingCheckbox.getVisibility()).isEqualTo(View.VISIBLE);
+ // verify that the toggle is visible
+ View sharingToggle =
+ frag.getmDialog().findViewById(R.id.phonebook_sharing);
+ assertThat(sharingToggle.getVisibility()).isEqualTo(View.VISIBLE);
}
@Test
- public void contactSharingCheckbox_conditionIsNotReady_doesNotShowUi() {
+ public void contactSharingToggle_conditionIsNotReady_doesNotShowUi() {
// set the dialog variant to confirmation/consent
when(controller.getDialogType()).thenReturn(BluetoothPairingController.CONFIRMATION_DIALOG);
// set a fake device name and pretend the profile has been set up for it
@@ -303,10 +302,10 @@
// build the fragment
BluetoothPairingDialogFragment frag = makeFragment();
- // verify that the checkbox is gone
- CheckBox sharingCheckbox =
- frag.getmDialog().findViewById(R.id.phonebook_sharing_message_confirm_pin);
- assertThat(sharingCheckbox.getVisibility()).isEqualTo(View.GONE);
+ // verify that the toggle is gone
+ View sharingToggle =
+ frag.getmDialog().findViewById(R.id.phonebook_sharing);
+ assertThat(sharingToggle.getVisibility()).isEqualTo(View.GONE);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusUsbFirmwareControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusUsbFirmwareControllerTest.java
index 5922016..2ba655a 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusUsbFirmwareControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusUsbFirmwareControllerTest.java
@@ -157,7 +157,7 @@
when(mFeatureFactory.getStylusFeatureProvider()
.isUsbFirmwareUpdateEnabled(any())).thenReturn(true);
when(mFeatureFactory.getStylusFeatureProvider()
- .getUsbFirmwareUpdatePreferences(any()))
+ .getUsbFirmwareUpdatePreferences(any(), any()))
.thenReturn(Collections.singletonList(mock(Preference.class)));
}
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
index c9591a5..bf4e893 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
@@ -73,8 +73,8 @@
}
@Test
- public void testIsBatteryTipsFeedbackEnabled_returnTrue() {
- assertThat(mPowerFeatureProvider.isBatteryTipsFeedbackEnabled()).isTrue();
+ public void testIsBatteryTipsFeedbackEnabled_returnFalse() {
+ assertThat(mPowerFeatureProvider.isBatteryTipsFeedbackEnabled()).isFalse();
}
@Test
public void testGetBatteryUsageListConsumePowerThreshold_return0() {
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreferenceTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreferenceTest.java
index 6f9a474..ed2b315 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreferenceTest.java
@@ -18,15 +18,30 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import android.app.settings.SettingsEnums;
import android.content.Context;
+import android.content.Intent;
+import android.view.View;
import com.android.settings.R;
+import com.android.settings.SettingsActivity;
+import com.android.settings.display.AutoBrightnessSettings;
+import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
+import com.android.settings.testutils.BatteryTestUtils;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
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;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
@@ -35,11 +50,20 @@
private Context mContext;
private BatteryTipsCardPreference mBatteryTipsCardPreference;
+ private BatteryTipsController mBatteryTipsController;
+ @Mock
+ private View mFakeView;
+ @Mock
+ private PowerUsageFeatureProvider mPowerUsageFeatureProvider;
@Before
public void setUp() {
+ MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
mBatteryTipsCardPreference = new BatteryTipsCardPreference(mContext, /*attrs=*/ null);
+ mBatteryTipsController = new BatteryTipsController(mContext);
+ mBatteryTipsController.mCardPreference = mBatteryTipsCardPreference;
+ mBatteryTipsController.mPowerUsageFeatureProvider = mPowerUsageFeatureProvider;
}
@Test
@@ -47,4 +71,23 @@
assertThat(mBatteryTipsCardPreference.getLayoutResource()).isEqualTo(
R.layout.battery_tips_card);
}
+ @Test
+ public void onClick_actionBtn_getAdaptiveBrightnessLauncher() {
+ final ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
+ PowerAnomalyEvent adaptiveBrightnessAnomaly =
+ BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent();
+ when(mPowerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
+ when(mFakeView.getId()).thenReturn(R.id.main_button);
+ doNothing().when(mContext).startActivity(captor.capture());
+
+ mBatteryTipsController.handleBatteryTipsCardUpdated(adaptiveBrightnessAnomaly);
+ mBatteryTipsCardPreference.onClick(mFakeView);
+
+ verify(mContext).startActivity(any(Intent.class));
+ final Intent intent = captor.getValue();
+ assertThat(intent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT))
+ .isEqualTo(AutoBrightnessSettings.class.getName());
+ assertThat(intent.getIntExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY, -1))
+ .isEqualTo(SettingsEnums.SETTINGS_AUTO_BRIGHTNESS);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsControllerTest.java
new file mode 100644
index 0000000..0c9a0b0
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsControllerTest.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2023 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.settings.fuelgauge.batteryusage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.LocaleList;
+
+import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
+import com.android.settings.testutils.BatteryTestUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.Locale;
+import java.util.TimeZone;
+
+@RunWith(RobolectricTestRunner.class)
+public final class BatteryTipsControllerTest {
+
+ private Context mContext;
+ private BatteryTipsController mBatteryTipsController;
+
+ @Mock
+ private BatteryTipsCardPreference mBatteryTipsCardPreference;
+
+ @Mock
+ private PowerUsageFeatureProvider mPowerUsageFeatureProvider;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ Locale.setDefault(new Locale("en_US"));
+ org.robolectric.shadows.ShadowSettings.set24HourTimeFormat(false);
+ TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
+ mContext = spy(RuntimeEnvironment.application);
+ final Resources resources = spy(mContext.getResources());
+ resources.getConfiguration().setLocales(new LocaleList(new Locale("en_US")));
+ doReturn(resources).when(mContext).getResources();
+ mBatteryTipsController = new BatteryTipsController(mContext);
+ mBatteryTipsController.mCardPreference = mBatteryTipsCardPreference;
+ mBatteryTipsController.mPowerUsageFeatureProvider = mPowerUsageFeatureProvider;
+ }
+
+ @Test
+ public void parsePowerAnomalyKey_preDefinedKeys_returnTrue() {
+ final String[] keys = {"adaptive_brightness", "screen_timeout"};
+ for (int index = 0; index < keys.length; index++) {
+ assertThat(mBatteryTipsController.getPowerAnomalyEventIndex(keys[index]))
+ .isEqualTo(index);
+ }
+ }
+
+ @Test
+ public void parsePowerAnomalyKey_unknownKey_returnTrue() {
+ final String key = "unknown_key_for_test";
+ assertThat(mBatteryTipsController.getPowerAnomalyEventIndex(key)).isEqualTo(-1);
+ }
+
+ @Test
+ public void handleBatteryTipsCardUpdated_null_hidePreference() {
+ mBatteryTipsController.handleBatteryTipsCardUpdated(/* powerAnomalyEvents= */ null);
+
+ verify(mBatteryTipsCardPreference).setVisible(false);
+ }
+
+ @Test
+ public void handleBatteryTipsCardUpdated_adaptiveBrightnessAnomaly_showAnomaly() {
+ PowerAnomalyEvent event = BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent();
+ when(mPowerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
+
+ mBatteryTipsController.handleBatteryTipsCardUpdated(event);
+
+ // Check pre-defined string
+ verify(mBatteryTipsCardPreference).setTitle(
+ "Turn on adaptive brightness to extend battery life");
+ verify(mBatteryTipsCardPreference).setMainButtonLabel("View Settings");
+ verify(mBatteryTipsCardPreference).setDismissButtonLabel("Got it");
+ // Check proto info
+ verify(mBatteryTipsCardPreference).setMainButtonLauncherInfo(
+ "com.android.settings.display.AutoBrightnessSettings",
+ 1381);
+ verify(mBatteryTipsCardPreference).setVisible(true);
+ }
+
+ @Test
+ public void handleBatteryTipsCardUpdated_screenTimeoutAnomaly_showAnomaly() {
+ PowerAnomalyEvent event = BatteryTestUtils.createScreenTimeoutAnomalyEvent();
+ when(mPowerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
+
+ mBatteryTipsController.handleBatteryTipsCardUpdated(event);
+
+ verify(mBatteryTipsCardPreference).setTitle("Reduce screen timeout to extend battery life");
+ verify(mBatteryTipsCardPreference).setMainButtonLabel("View Settings");
+ verify(mBatteryTipsCardPreference).setDismissButtonLabel("Got it");
+ verify(mBatteryTipsCardPreference).setMainButtonLauncherInfo(
+ "com.android.settings.display.ScreenTimeoutSettings",
+ 1852);
+ verify(mBatteryTipsCardPreference).setVisible(true);
+ }
+ @Test
+ public void handleBatteryTipsCardUpdated_screenTimeoutAnomalyHasTitle_showAnomaly() {
+ PowerAnomalyEvent event = BatteryTestUtils.createScreenTimeoutAnomalyEvent();
+ String testTitle = "TestTitle";
+ event = event.toBuilder()
+ .setWarningBannerInfo(
+ event.getWarningBannerInfo().toBuilder()
+ .setTitleString(testTitle)
+ .build())
+ .build();
+ when(mPowerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
+
+ mBatteryTipsController.handleBatteryTipsCardUpdated(event);
+
+ verify(mBatteryTipsCardPreference).setTitle(testTitle);
+ verify(mBatteryTipsCardPreference).setMainButtonLabel("View Settings");
+ verify(mBatteryTipsCardPreference).setDismissButtonLabel("Got it");
+ verify(mBatteryTipsCardPreference).setMainButtonLauncherInfo(
+ "com.android.settings.display.ScreenTimeoutSettings",
+ 1852);
+ verify(mBatteryTipsCardPreference).setVisible(true);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
index 3cbe8a4..e9108bc 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
@@ -25,6 +25,7 @@
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
+import android.app.usage.IUsageStatsManager;
import android.app.usage.UsageEvents;
import android.app.usage.UsageEvents.Event;
import android.content.ContentValues;
@@ -61,6 +62,8 @@
private BatteryUsageStats mBatteryUsageStats;
@Mock
private BatteryEntry mMockBatteryEntry;
+ @Mock
+ private IUsageStatsManager mUsageStatsManager;
@Before
public void setUp() {
@@ -68,6 +71,7 @@
mContext = spy(RuntimeEnvironment.application);
ConvertUtils.sUsageSource = ConvertUtils.EMPTY_USAGE_SOURCE;
when(mContext.getPackageManager()).thenReturn(mMockPackageManager);
+ DataProcessor.sUsageStatsManager = mUsageStatsManager;
}
@Test
@@ -299,7 +303,7 @@
final long userId = 2;
final AppUsageEvent appUsageEvent = ConvertUtils.convertToAppUsageEvent(
- mContext, event, userId);
+ mContext, mUsageStatsManager, event, userId);
assertThat(appUsageEvent.getTimestamp()).isEqualTo(101L);
assertThat(appUsageEvent.getType()).isEqualTo(AppUsageEventType.ACTIVITY_RESUMED);
assertThat(appUsageEvent.getPackageName()).isEqualTo("com.android.settings1");
@@ -320,7 +324,7 @@
final long userId = 1;
final AppUsageEvent appUsageEvent =
- ConvertUtils.convertToAppUsageEvent(mContext, event, userId);
+ ConvertUtils.convertToAppUsageEvent(mContext, mUsageStatsManager, event, userId);
assertThat(appUsageEvent.getTimestamp()).isEqualTo(101L);
assertThat(appUsageEvent.getType()).isEqualTo(AppUsageEventType.DEVICE_SHUTDOWN);
assertThat(appUsageEvent.getPackageName()).isEqualTo("com.android.settings1");
@@ -336,7 +340,8 @@
event.mPackage = null;
final AppUsageEvent appUsageEvent =
- ConvertUtils.convertToAppUsageEvent(mContext, event, /*userId=*/ 0);
+ ConvertUtils.convertToAppUsageEvent(
+ mContext, mUsageStatsManager, event, /*userId=*/ 0);
assertThat(appUsageEvent).isNull();
}
@@ -352,7 +357,7 @@
final long userId = 1;
final AppUsageEvent appUsageEvent =
- ConvertUtils.convertToAppUsageEvent(mContext, event, userId);
+ ConvertUtils.convertToAppUsageEvent(mContext, mUsageStatsManager, event, userId);
assertThat(appUsageEvent).isNull();
}
@@ -453,7 +458,7 @@
final String taskRootPackageName = "com.android.settings2";
assertThat(ConvertUtils.getEffectivePackageName(
- mContext, packageName, taskRootPackageName))
+ mContext, mUsageStatsManager, packageName, taskRootPackageName))
.isEqualTo(packageName);
}
@@ -463,7 +468,7 @@
final String taskRootPackageName = "com.android.settings2";
assertThat(ConvertUtils.getEffectivePackageName(
- mContext, packageName, taskRootPackageName))
+ mContext, mUsageStatsManager, packageName, taskRootPackageName))
.isEqualTo(packageName);
}
@@ -474,7 +479,7 @@
final String taskRootPackageName = "com.android.settings2";
assertThat(ConvertUtils.getEffectivePackageName(
- mContext, packageName, taskRootPackageName))
+ mContext, mUsageStatsManager, packageName, taskRootPackageName))
.isEqualTo(taskRootPackageName);
}
@@ -484,10 +489,10 @@
final String packageName = "com.android.settings1";
assertThat(ConvertUtils.getEffectivePackageName(
- mContext, packageName, /*taskRootPackageName=*/ null))
+ mContext, mUsageStatsManager, packageName, /*taskRootPackageName=*/ null))
.isEqualTo(packageName);
assertThat(ConvertUtils.getEffectivePackageName(
- mContext, packageName, /*taskRootPackageName=*/ ""))
+ mContext, mUsageStatsManager, packageName, /*taskRootPackageName=*/ ""))
.isEqualTo(packageName);
}
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java
index 7f7fe43..b610cfb 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java
@@ -72,7 +72,7 @@
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
- DatabaseUtils.sUsageStatsManager = mUsageStatsManager;
+ DataProcessor.sUsageStatsManager = mUsageStatsManager;
doReturn(mContext).when(mContext).getApplicationContext();
doReturn(mUserManager)
.when(mContext)
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
index 8bed054..c9b635e 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
@@ -93,7 +93,7 @@
mPowerUsageFeatureProvider = mFeatureFactory.powerUsageFeatureProvider;
DataProcessor.sTestSystemAppsPackageNames = Set.of();
- DatabaseUtils.sUsageStatsManager = mUsageStatsManager;
+ DataProcessor.sUsageStatsManager = mUsageStatsManager;
doReturn(mIntent).when(mContext).registerReceiver(
isA(BroadcastReceiver.class), isA(IntentFilter.class));
doReturn(100).when(mIntent).getIntExtra(eq(BatteryManager.EXTRA_SCALE), anyInt());
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
index 24be769..8a1ba13 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
@@ -85,7 +85,7 @@
doReturn(mPackageManager).when(mMockContext).getPackageManager();
doReturn(mPackageManager).when(mContext).getPackageManager();
DatabaseUtils.getSharedPreferences(mContext).edit().clear().apply();
- DatabaseUtils.sUsageStatsManager = mUsageStatsManager;
+ DataProcessor.sUsageStatsManager = mUsageStatsManager;
}
@Test
@@ -466,7 +466,7 @@
.putInt(DatabaseUtils.KEY_LAST_USAGE_SOURCE, USAGE_SOURCE_TASK_ROOT_ACTIVITY)
.apply();
- assertThat(DatabaseUtils.getUsageSource(mContext))
+ assertThat(DatabaseUtils.getUsageSource(mContext, mUsageStatsManager))
.isEqualTo(USAGE_SOURCE_TASK_ROOT_ACTIVITY);
}
@@ -474,7 +474,7 @@
public void getUsageSource_notHasData_writeLoadedData() throws RemoteException {
when(mUsageStatsManager.getUsageSource()).thenReturn(USAGE_SOURCE_TASK_ROOT_ACTIVITY);
- assertThat(DatabaseUtils.getUsageSource(mContext))
+ assertThat(DatabaseUtils.getUsageSource(mContext, mUsageStatsManager))
.isEqualTo(USAGE_SOURCE_TASK_ROOT_ACTIVITY);
assertThat(
DatabaseUtils
@@ -487,7 +487,7 @@
public void getUsageSource_throwException_writeDefaultData() throws RemoteException {
when(mUsageStatsManager.getUsageSource()).thenThrow(new RemoteException());
- assertThat(DatabaseUtils.getUsageSource(mContext))
+ assertThat(DatabaseUtils.getUsageSource(mContext, mUsageStatsManager))
.isEqualTo(USAGE_SOURCE_CURRENT_ACTIVITY);
assertThat(
DatabaseUtils
diff --git a/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java b/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java
index cd75bef..ef2013c 100644
--- a/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java
@@ -797,6 +797,28 @@
}
@Test
+ public void getNonIndexableKeys_wifiStateEnabled_addWifiNetworkKeyNotReturned() {
+ when(mWifiManager.getWifiState()).thenReturn(WifiManager.WIFI_STATE_ENABLED);
+ NetworkProviderSettings.SearchIndexProvider searchIndexProvider =
+ new NetworkProviderSettings.SearchIndexProvider(XML_RES, mWifiRestriction);
+
+ final List<String> keys = searchIndexProvider.getNonIndexableKeys(mContext);
+
+ assertThat(keys).doesNotContain(NetworkProviderSettings.PREF_KEY_ADD_WIFI_NETWORK);
+ }
+
+ @Test
+ public void getNonIndexableKeys_wifiStateDisabled_addWifiNetworkKeyReturned() {
+ when(mWifiManager.getWifiState()).thenReturn(WifiManager.WIFI_STATE_DISABLED);
+ NetworkProviderSettings.SearchIndexProvider searchIndexProvider =
+ new NetworkProviderSettings.SearchIndexProvider(XML_RES, mWifiRestriction);
+
+ final List<String> keys = searchIndexProvider.getNonIndexableKeys(mContext);
+
+ assertThat(keys).contains(NetworkProviderSettings.PREF_KEY_ADD_WIFI_NETWORK);
+ }
+
+ @Test
public void launchConfigNewNetworkFragment_fragmentIsRestricted_ignoreWifiEntry() {
mNetworkProviderSettings.mIsRestricted = true;
diff --git a/tests/robotests/src/com/android/settings/remoteauth/finish/RemoteAuthEnrollFinishTest.kt b/tests/robotests/src/com/android/settings/remoteauth/finish/RemoteAuthEnrollFinishTest.kt
index 7bb5c45..1ad7dd8 100644
--- a/tests/robotests/src/com/android/settings/remoteauth/finish/RemoteAuthEnrollFinishTest.kt
+++ b/tests/robotests/src/com/android/settings/remoteauth/finish/RemoteAuthEnrollFinishTest.kt
@@ -16,40 +16,40 @@
package com.android.settings.remoteauth.finish
-
-import android.content.Context
import android.os.Bundle
import androidx.fragment.app.testing.launchFragmentInContainer
-import androidx.test.core.app.ApplicationProvider
+import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.assertion.ViewAssertions.matches
+import androidx.test.espresso.matcher.ViewMatchers.*
import com.android.settings.R
-import com.google.android.setupdesign.GlifLayout
-import com.google.common.truth.Truth.assertThat
-
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
@RunWith(RobolectricTestRunner::class)
class RemoteAuthEnrollFinishTest {
- private var mContext: Context = ApplicationProvider.getApplicationContext()
+
+ @Before
+ fun setup() {
+ launchFragmentInContainer<RemoteAuthEnrollFinish>(Bundle(), R.style.SudThemeGlif)
+ }
@Test
fun testRemoteAuthenticatorEnrollFinish_hasHeader() {
- launchFragmentInContainer<RemoteAuthEnrollFinish>(Bundle(), R.style.SudThemeGlif)
- .onFragment {
- assertThat((it.view as GlifLayout).headerText)
- .isEqualTo(mContext.getString(
- R.string.security_settings_remoteauth_enroll_finish_title))
- }
+ onView(withText(R.string.security_settings_remoteauth_enroll_finish_title)).check(
+ matches(
+ isDisplayed()
+ )
+ )
}
@Test
fun testRemoteAuthenticatorEnrollFinish_hasDescription() {
- launchFragmentInContainer<RemoteAuthEnrollFinish>(Bundle(), R.style.SudThemeGlif)
- .onFragment {
- assertThat((it.view as GlifLayout).descriptionText)
- .isEqualTo(mContext.getString(
- R.string.security_settings_remoteauth_enroll_finish_description))
- }
+ onView(withText(R.string.security_settings_remoteauth_enroll_finish_description)).check(
+ matches(
+ isDisplayed()
+ )
+ )
}
-}
\ No newline at end of file
+}
diff --git a/tests/robotests/src/com/android/settings/remoteauth/introduction/RemoteAuthEnrollIntroductionTest.kt b/tests/robotests/src/com/android/settings/remoteauth/introduction/RemoteAuthEnrollIntroductionTest.kt
index a271184..6855e9f 100644
--- a/tests/robotests/src/com/android/settings/remoteauth/introduction/RemoteAuthEnrollIntroductionTest.kt
+++ b/tests/robotests/src/com/android/settings/remoteauth/introduction/RemoteAuthEnrollIntroductionTest.kt
@@ -16,37 +16,39 @@
package com.android.settings.remoteauth.introduction
-import android.content.Context
import android.os.Bundle
import androidx.fragment.app.testing.launchFragmentInContainer
-import androidx.test.core.app.ApplicationProvider
+import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.assertion.ViewAssertions.matches
+import androidx.test.espresso.matcher.ViewMatchers.*
import com.android.settings.R
-import com.google.android.setupdesign.GlifLayout
-import com.google.common.truth.Truth.assertThat
-
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
@RunWith(RobolectricTestRunner::class)
class RemoteAuthEnrollIntroductionTest {
- private var mContext : Context = ApplicationProvider.getApplicationContext()
+ @Before
+ fun setUp() {
+ launchFragmentInContainer<RemoteAuthEnrollIntroduction>(Bundle(), R.style.SudThemeGlif)
+ }
@Test
fun testRemoteAuthenticatorEnrollIntroduction_hasHeader() {
- launchFragmentInContainer<RemoteAuthEnrollIntroduction>(Bundle(), R.style.SudThemeGlif)
- .onFragment {
- assertThat((it.view as GlifLayout).headerText)
- .isEqualTo(mContext.getString(R.string.security_settings_remoteauth_enroll_introduction_title))
- }
+ onView(withText(R.string.security_settings_remoteauth_enroll_introduction_title)).check(
+ matches(
+ isDisplayed()
+ )
+ )
}
@Test
fun testRemoteAuthenticatorEnrollIntroduction_hasDescription() {
- launchFragmentInContainer<RemoteAuthEnrollIntroduction>(Bundle(), R.style.SudThemeGlif)
- .onFragment {
- assertThat((it.view as GlifLayout).descriptionText)
- .isEqualTo(mContext.getString(R.string.security_settings_remoteauth_enroll_introduction_message))
- }
+ onView(withText(R.string.security_settings_remoteauth_enroll_introduction_message)).check(
+ matches(
+ isDisplayed()
+ )
+ )
}
-}
\ No newline at end of file
+}
diff --git a/tests/robotests/src/com/android/settings/search/actionbar/SearchMenuControllerTest.java b/tests/robotests/src/com/android/settings/search/actionbar/SearchMenuControllerTest.java
index eb6ad0c..d898e64 100644
--- a/tests/robotests/src/com/android/settings/search/actionbar/SearchMenuControllerTest.java
+++ b/tests/robotests/src/com/android/settings/search/actionbar/SearchMenuControllerTest.java
@@ -33,7 +33,6 @@
import androidx.fragment.app.FragmentActivity;
-import com.android.settings.R;
import com.android.settings.core.InstrumentedFragment;
import com.android.settings.testutils.shadow.ShadowUtils;
@@ -72,7 +71,7 @@
when(mHost.getActivity()).thenReturn(mActivity);
when(mMenu.add(Menu.NONE, MENU_SEARCH, 0 /* order */,
- R.string.search_menu))
+ com.android.settingslib.search.R.string.search_menu))
.thenReturn(mock(MenuItem.class));
}
@@ -82,7 +81,7 @@
mHost.getSettingsLifecycle().onCreateOptionsMenu(mMenu, null /* inflater */);
verify(mMenu).add(Menu.NONE, MENU_SEARCH, 0 /* order */,
- R.string.search_menu);
+ com.android.settingslib.search.R.string.search_menu);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java b/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
index c54b750..e99b17f 100644
--- a/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
+++ b/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
@@ -18,6 +18,7 @@
import static org.mockito.Mockito.when;
+import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.Intent;
import android.hardware.usb.UsbManager;
@@ -25,11 +26,17 @@
import android.hardware.usb.UsbPortStatus;
import android.os.BatteryManager;
import android.os.UserManager;
+
import androidx.room.Room;
+import com.android.settings.display.AutoBrightnessSettings;
+import com.android.settings.display.ScreenTimeoutSettings;
import com.android.settings.fuelgauge.batteryusage.BatteryInformation;
import com.android.settings.fuelgauge.batteryusage.ConvertUtils;
import com.android.settings.fuelgauge.batteryusage.DeviceBatteryState;
+import com.android.settings.fuelgauge.batteryusage.PowerAnomalyEvent;
+import com.android.settings.fuelgauge.batteryusage.PowerAnomalyEventList;
+import com.android.settings.fuelgauge.batteryusage.WarningBannerInfo;
import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventDao;
import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity;
import com.android.settings.fuelgauge.batteryusage.db.BatteryState;
@@ -193,4 +200,33 @@
when(mockUsbPortStatus.getComplianceWarnings())
.thenReturn(new int[]{UsbPortStatus.COMPLIANCE_WARNING_OTHER});
}
+
+ /** Create an empty power anomaly event list proto. */
+ public static PowerAnomalyEventList createEmptyPowerAnomalyEventList() {
+ return PowerAnomalyEventList.getDefaultInstance();
+ }
+
+ /** Create a power anomaly event proto of adaptive brightness. */
+ public static PowerAnomalyEvent createAdaptiveBrightnessAnomalyEvent() {
+ return PowerAnomalyEvent.newBuilder()
+ .setType("settings banner")
+ .setKey("adaptive_brightness")
+ .setWarningBannerInfo(WarningBannerInfo.newBuilder()
+ .setMainButtonDestination(AutoBrightnessSettings.class.getName())
+ .setMainButtonSourceMetricsCategory(SettingsEnums.SETTINGS_AUTO_BRIGHTNESS)
+ .build())
+ .build();
+ }
+
+ /** Create a power anomaly event proto of screen timeout. */
+ public static PowerAnomalyEvent createScreenTimeoutAnomalyEvent() {
+ return PowerAnomalyEvent.newBuilder()
+ .setType("settings banner")
+ .setKey("screen_timeout")
+ .setWarningBannerInfo(WarningBannerInfo.newBuilder()
+ .setMainButtonDestination(ScreenTimeoutSettings.class.getName())
+ .setMainButtonSourceMetricsCategory(SettingsEnums.SCREEN_TIMEOUT)
+ .build())
+ .build();
+ }
}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccessPoint.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccessPoint.java
deleted file mode 100644
index 7d206f4..0000000
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccessPoint.java
+++ /dev/null
@@ -1,31 +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.settings.testutils.shadow;
-
-import com.android.settingslib.wifi.AccessPoint;
-
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-
-@Implements(AccessPoint.class)
-public class ShadowAccessPoint {
-
- @Implementation
- protected String getSavedNetworkSummary() {
- return "saved";
- }
-}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAppInfoBase.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAppInfoBase.java
deleted file mode 100644
index f8cdb22..0000000
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAppInfoBase.java
+++ /dev/null
@@ -1,36 +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.settings.testutils.shadow;
-
-import com.android.settings.applications.AppInfoBase;
-
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-
-@Implements(AppInfoBase.class)
-public class ShadowAppInfoBase {
-
- @Implementation
- protected void onResume() {
- // No-op.
- }
-
- @Implementation
- protected void onPause() {
- // No-op.
- }
-}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDataSaverBackend.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDataSaverBackend.java
deleted file mode 100644
index 4d1a2ed..0000000
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDataSaverBackend.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.android.settings.testutils.shadow;
-
-import com.android.settings.datausage.DataSaverBackend;
-
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-
-@Implements(DataSaverBackend.class)
-public class ShadowDataSaverBackend {
-
- private static boolean isEnabled = true;
-
- @Implementation
- protected boolean isDataSaverEnabled() {
- return isEnabled;
- }
-
- @Implementation
- protected void setDataSaverEnabled(boolean enabled) {
- isEnabled = enabled;
- }
-}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowInputManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowInputManager.java
deleted file mode 100644
index c0f7134..0000000
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowInputManager.java
+++ /dev/null
@@ -1,66 +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.settings.testutils.shadow;
-
-import static org.robolectric.util.ReflectionHelpers.ClassParameter.from;
-
-import android.hardware.input.IInputManager;
-import android.hardware.input.InputManager;
-import android.os.Handler;
-
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-import org.robolectric.util.ReflectionHelpers;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Shadow for {@link InputManager} that has accessors for registered
- * {@link InputManager.InputDeviceListener}s.
- */
-@Implements(value = InputManager.class, callThroughByDefault = false)
-public class ShadowInputManager {
-
- private List<InputManager.InputDeviceListener> mInputDeviceListeners;
-
- @Implementation
- protected void __constructor__(IInputManager service) {
- mInputDeviceListeners = new ArrayList<>();
- }
-
- @Implementation
- protected static InputManager getInstance() {
- return ReflectionHelpers.callConstructor(
- InputManager.class,
- from(IInputManager.class, null));
- }
-
- @Implementation
- protected void registerInputDeviceListener(InputManager.InputDeviceListener listener,
- Handler handler) {
- // TODO: Use handler.
- if (!mInputDeviceListeners.contains(listener)) {
- mInputDeviceListeners.add(listener);
- }
- }
-
- @Implementation
- protected void unregisterInputDeviceListener(InputManager.InputDeviceListener listener) {
- mInputDeviceListeners.remove(listener);
- }
-}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowNetworkDetailsTracker.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowNetworkDetailsTracker.java
deleted file mode 100644
index 5df9ba5..0000000
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowNetworkDetailsTracker.java
+++ /dev/null
@@ -1,60 +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.settings.testutils.shadow;
-
-import static org.mockito.Mockito.mock;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.NetworkScoreManager;
-import android.net.wifi.WifiManager;
-import android.os.Handler;
-
-import androidx.annotation.NonNull;
-import androidx.lifecycle.Lifecycle;
-
-import com.android.wifitrackerlib.NetworkDetailsTracker;
-import com.android.wifitrackerlib.WifiEntry;
-
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-
-import java.time.Clock;
-
-@Implements(NetworkDetailsTracker.class)
-public class ShadowNetworkDetailsTracker {
-
- @Implementation
- public static NetworkDetailsTracker createNetworkDetailsTracker(@NonNull Lifecycle lifecycle,
- @NonNull Context context,
- @NonNull WifiManager wifiManager,
- @NonNull ConnectivityManager connectivityManager,
- @NonNull NetworkScoreManager networkScoreManager,
- @NonNull Handler mainHandler,
- @NonNull Handler workerHandler,
- @NonNull Clock clock,
- long maxScanAgeMillis,
- long scanIntervalMillis,
- String key) {
- return mock(NetworkDetailsTracker.class);
- }
-
- @Implementation
- public WifiEntry getWifiEntry() {
- return mock(WifiEntry.class);
- }
-}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowPermissionControllerManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowPermissionControllerManager.java
deleted file mode 100644
index 6a6f710..0000000
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowPermissionControllerManager.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.testutils.shadow;
-
-import android.annotation.CallbackExecutor;
-import android.content.Context;
-import android.os.Handler;
-import android.permission.PermissionControllerManager;
-
-import androidx.annotation.NonNull;
-
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-
-import java.util.concurrent.Executor;
-
-@Implements(PermissionControllerManager.class)
-public class ShadowPermissionControllerManager {
-
- protected void __constructor__(Context contexts, Handler handler) {
- // no nothing, everything is shadowed
- }
-
- @Implementation
- public void getPermissionUsages(boolean countSystem, long numMillis,
- @NonNull @CallbackExecutor Executor executor,
- @NonNull PermissionControllerManager.OnPermissionUsageResultCallback callback) {
-
- // Do nothing
- }
-}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowWifiManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowWifiManager.java
deleted file mode 100644
index ea57bf7..0000000
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowWifiManager.java
+++ /dev/null
@@ -1,93 +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.settings.testutils.shadow;
-
-import static org.robolectric.RuntimeEnvironment.application;
-
-import android.net.wifi.ScanResult;
-import android.net.wifi.SoftApConfiguration;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiManager;
-import android.net.wifi.hotspot2.PasspointConfiguration;
-
-import org.robolectric.annotation.HiddenApi;
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-import org.robolectric.shadow.api.Shadow;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-@Implements(value = WifiManager.class)
-public class ShadowWifiManager extends org.robolectric.shadows.ShadowWifiManager {
-
- private List<PasspointConfiguration> mPasspointConfiguration;
-
- public WifiConfiguration savedWifiConfig;
- private SoftApConfiguration mSavedApConfig;
-
- @Implementation
- protected SoftApConfiguration getSoftApConfiguration() {
- return mSavedApConfig;
- }
-
- @Implementation
- protected boolean setSoftApConfiguration(SoftApConfiguration softApConfig) {
- mSavedApConfig = softApConfig;
- return true;
- }
-
- @HiddenApi // @SystemApi
- @Implementation
- protected void connect(WifiConfiguration config, WifiManager.ActionListener listener) {
- savedWifiConfig = config;
- }
-
- @HiddenApi
- @Implementation
- protected void save(WifiConfiguration config, WifiManager.ActionListener listener) {
- savedWifiConfig = config;
- }
-
- @Implementation
- protected List<PasspointConfiguration> getPasspointConfigurations() {
- return mPasspointConfiguration == null ? Collections.emptyList() : mPasspointConfiguration;
- }
-
- @Implementation
- protected void addOrUpdatePasspointConfiguration(PasspointConfiguration config) {
- if (mPasspointConfiguration == null) {
- mPasspointConfiguration = new ArrayList<>();
- }
- mPasspointConfiguration.add(config);
- }
-
- @Implementation
- protected boolean isDualModeSupported() {
- return false;
- }
-
- @Implementation
- protected List<ScanResult> getScanResults() {
- return new ArrayList<ScanResult>();
- }
-
- public static ShadowWifiManager get() {
- return Shadow.extract(application.getSystemService(WifiManager.class));
- }
-}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowWifiP2pManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowWifiP2pManager.java
deleted file mode 100644
index 2fd8f6b..0000000
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowWifiP2pManager.java
+++ /dev/null
@@ -1,55 +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.settings.testutils.shadow;
-
-import android.net.wifi.p2p.WifiP2pManager;
-
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-import org.robolectric.annotation.Resetter;
-
-/**
- * Shadow class for WifiP2pManager.
- */
-@Implements(value = WifiP2pManager.class)
-public class ShadowWifiP2pManager extends org.robolectric.shadows.ShadowWifiP2pManager {
-
- private static int sFactoryResetCount;
-
- @Implementation
- protected void factoryReset(WifiP2pManager.Channel c, WifiP2pManager.ActionListener listener) {
- if (c != null) {
- sFactoryResetCount++;
- } else {
- throw new IllegalArgumentException("channel must be non-null.");
- }
- }
-
- @Resetter
- public static void reset() {
- sFactoryResetCount = 0;
- }
-
- /**
- * Return the count of factoryReset called.
- *
- * @return the count of factoryReset called.
- */
- public static int getFactoryResetCount() {
- return sFactoryResetCount;
- }
-}
diff --git a/tests/robotests/src/com/android/settings/testutils/CustomActivity.java b/tests/robotests/testutils/com/android/settings/testutils/CustomActivity.java
similarity index 100%
rename from tests/robotests/src/com/android/settings/testutils/CustomActivity.java
rename to tests/robotests/testutils/com/android/settings/testutils/CustomActivity.java
diff --git a/tests/robotests/src/com/android/settings/testutils/DatabaseTestUtils.java b/tests/robotests/testutils/com/android/settings/testutils/DatabaseTestUtils.java
similarity index 100%
rename from tests/robotests/src/com/android/settings/testutils/DatabaseTestUtils.java
rename to tests/robotests/testutils/com/android/settings/testutils/DatabaseTestUtils.java
diff --git a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java b/tests/robotests/testutils/com/android/settings/testutils/FakeFeatureFactory.java
similarity index 96%
rename from tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
rename to tests/robotests/testutils/com/android/settings/testutils/FakeFeatureFactory.java
index 0d7c0b1..c8db62f 100644
--- a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
+++ b/tests/robotests/testutils/com/android/settings/testutils/FakeFeatureFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -11,7 +11,7 @@
* 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
+ * limitations under the License.
*/
package com.android.settings.testutils;
@@ -38,6 +38,7 @@
import com.android.settings.homepage.contextualcards.ContextualCardFeatureProvider;
import com.android.settings.inputmethod.KeyboardSettingsFeatureProvider;
import com.android.settings.localepicker.LocaleFeatureProvider;
+import com.android.settings.onboarding.OnboardingFeatureProvider;
import com.android.settings.overlay.DockUpdaterFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.overlay.SupportFeatureProvider;
@@ -93,6 +94,7 @@
public WifiFeatureProvider mWifiFeatureProvider;
public KeyboardSettingsFeatureProvider mKeyboardSettingsFeatureProvider;
public StylusFeatureProvider mStylusFeatureProvider;
+ public OnboardingFeatureProvider mOnboardingFeatureProvider;
/**
* Call this in {@code @Before} method of the test class to use fake factory.
@@ -137,6 +139,7 @@
mWifiFeatureProvider = mock(WifiFeatureProvider.class);
mKeyboardSettingsFeatureProvider = mock(KeyboardSettingsFeatureProvider.class);
mStylusFeatureProvider = mock(StylusFeatureProvider.class);
+ mOnboardingFeatureProvider = mock(OnboardingFeatureProvider.class);
}
@Override
@@ -299,4 +302,9 @@
public StylusFeatureProvider getStylusFeatureProvider() {
return mStylusFeatureProvider;
}
+
+ @Override
+ public OnboardingFeatureProvider getOnboardingFeatureProvider() {
+ return mOnboardingFeatureProvider;
+ }
}
diff --git a/tests/robotests/src/com/android/settings/testutils/ResolveInfoBuilder.java b/tests/robotests/testutils/com/android/settings/testutils/ResolveInfoBuilder.java
similarity index 100%
rename from tests/robotests/src/com/android/settings/testutils/ResolveInfoBuilder.java
rename to tests/robotests/testutils/com/android/settings/testutils/ResolveInfoBuilder.java
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/SettingsShadowResources.java b/tests/robotests/testutils/com/android/settings/testutils/shadow/SettingsShadowResources.java
similarity index 82%
rename from tests/robotests/src/com/android/settings/testutils/shadow/SettingsShadowResources.java
rename to tests/robotests/testutils/com/android/settings/testutils/shadow/SettingsShadowResources.java
index 8ca577c..b2d5484 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/SettingsShadowResources.java
+++ b/tests/robotests/testutils/com/android/settings/testutils/shadow/SettingsShadowResources.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2023 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.settings.testutils.shadow;
import static org.robolectric.RuntimeEnvironment.application;
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccessibilityServiceInfo.java b/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowAccessibilityServiceInfo.java
similarity index 100%
rename from tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccessibilityServiceInfo.java
rename to tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowAccessibilityServiceInfo.java
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowActivity.java b/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowActivity.java
similarity index 100%
rename from tests/robotests/src/com/android/settings/testutils/shadow/ShadowActivity.java
rename to tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowActivity.java
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowActivityEmbeddingUtils.java b/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowActivityEmbeddingUtils.java
similarity index 100%
rename from tests/robotests/src/com/android/settings/testutils/shadow/ShadowActivityEmbeddingUtils.java
rename to tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowActivityEmbeddingUtils.java
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAlertDialogCompat.java b/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowAlertDialogCompat.java
similarity index 82%
rename from tests/robotests/src/com/android/settings/testutils/shadow/ShadowAlertDialogCompat.java
rename to tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowAlertDialogCompat.java
index e595cb6..d6d17f8 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAlertDialogCompat.java
+++ b/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowAlertDialogCompat.java
@@ -38,39 +38,40 @@
@SuppressLint("StaticFieldLeak")
@Nullable
- private static ShadowAlertDialogCompat latestSupportAlertDialog;
+ private static ShadowAlertDialogCompat sLatestSupportAlertDialog;
@RealObject
- private AlertDialog realAlertDialog;
+ private AlertDialog mRealAlertDialog;
@Implementation
public void show() {
super.show();
- latestSupportAlertDialog = this;
+ sLatestSupportAlertDialog = this;
}
public CharSequence getMessage() {
- final Object alertController = ReflectionHelpers.getField(realAlertDialog, "mAlert");
+ final Object alertController = ReflectionHelpers.getField(mRealAlertDialog, "mAlert");
return ReflectionHelpers.getField(alertController, "mMessage");
}
public CharSequence getTitle() {
- final Object alertController = ReflectionHelpers.getField(realAlertDialog, "mAlert");
+ final Object alertController = ReflectionHelpers.getField(mRealAlertDialog, "mAlert");
return ReflectionHelpers.getField(alertController, "mTitle");
}
public View getView() {
- final Object alertController = ReflectionHelpers.getField(realAlertDialog, "mAlert");
+ final Object alertController = ReflectionHelpers.getField(mRealAlertDialog, "mAlert");
return ReflectionHelpers.getField(alertController, "mView");
}
@Nullable
public static AlertDialog getLatestAlertDialog() {
- return latestSupportAlertDialog == null ? null : latestSupportAlertDialog.realAlertDialog;
+ return sLatestSupportAlertDialog == null
+ ? null : sLatestSupportAlertDialog.mRealAlertDialog;
}
@Resetter
public static void reset() {
- latestSupportAlertDialog = null;
+ sLatestSupportAlertDialog = null;
}
public static ShadowAlertDialogCompat shadowOf(AlertDialog alertDialog) {
@@ -78,6 +79,6 @@
}
public void clickOnItem(int index) {
- Shadows.shadowOf(realAlertDialog.getListView()).performItemClick(index);
+ Shadows.shadowOf(mRealAlertDialog.getListView()).performItemClick(index);
}
-}
\ No newline at end of file
+}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowBluetoothAdapter.java b/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowBluetoothAdapter.java
similarity index 100%
rename from tests/robotests/src/com/android/settings/testutils/shadow/ShadowBluetoothAdapter.java
rename to tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowBluetoothAdapter.java
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowConnectivityManager.java b/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowConnectivityManager.java
similarity index 100%
rename from tests/robotests/src/com/android/settings/testutils/shadow/ShadowConnectivityManager.java
rename to tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowConnectivityManager.java
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowApplicationsState.java b/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowDataSaverBackend.java
similarity index 63%
rename from tests/robotests/src/com/android/settings/testutils/shadow/ShadowApplicationsState.java
rename to tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowDataSaverBackend.java
index 8239ed9..f97a70e 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowApplicationsState.java
+++ b/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowDataSaverBackend.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2023 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.
@@ -16,17 +16,23 @@
package com.android.settings.testutils.shadow;
-import android.os.Looper;
-
-import com.android.settingslib.applications.ApplicationsState;
+import com.android.settings.datausage.DataSaverBackend;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
-@Implements(ApplicationsState.class)
-public class ShadowApplicationsState {
+@Implements(DataSaverBackend.class)
+public class ShadowDataSaverBackend {
+
+ private static boolean sIsEnabled = true;
+
@Implementation
- protected Looper getBackgroundLooper() {
- return Looper.getMainLooper();
+ protected boolean isDataSaverEnabled() {
+ return sIsEnabled;
+ }
+
+ @Implementation
+ protected void setDataSaverEnabled(boolean enabled) {
+ sIsEnabled = enabled;
}
}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowFragment.java b/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowFragment.java
similarity index 100%
rename from tests/robotests/src/com/android/settings/testutils/shadow/ShadowFragment.java
rename to tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowFragment.java
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowInteractionJankMonitor.java b/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowInteractionJankMonitor.java
similarity index 100%
rename from tests/robotests/src/com/android/settings/testutils/shadow/ShadowInteractionJankMonitor.java
rename to tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowInteractionJankMonitor.java
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java b/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java
similarity index 94%
rename from tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java
rename to tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java
index 9afcd37..d0bb2bf 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java
+++ b/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java
@@ -114,8 +114,8 @@
}
@Implementation
- protected byte[] getPasswordHistoryHashFactor(LockscreenCredential currentPassword,
- int userId) {
+ protected byte[] getPasswordHistoryHashFactor(
+ LockscreenCredential currentPassword, int userId) {
return null;
}
@@ -130,8 +130,8 @@
}
@Implementation
- public @DevicePolicyManager.PasswordComplexity int getRequestedPasswordComplexity(int userId,
- boolean deviceWideOnly) {
+ @DevicePolicyManager.PasswordComplexity
+ public int getRequestedPasswordComplexity(int userId, boolean deviceWideOnly) {
int complexity = sUserToComplexityMap.getOrDefault(userId,
DevicePolicyManager.PASSWORD_COMPLEXITY_NONE);
if (!deviceWideOnly) {
@@ -178,14 +178,16 @@
}
@Implementation
- public boolean setLockCredential(@NonNull LockscreenCredential newCredential,
+ public boolean setLockCredential(
+ @NonNull LockscreenCredential newCredential,
@NonNull LockscreenCredential savedCredential, int userHandle) {
setIsSecure(userHandle, true);
return true;
}
@Implementation
- public boolean checkCredential(@NonNull LockscreenCredential credential, int userId,
+ public boolean checkCredential(
+ @NonNull LockscreenCredential credential, int userId,
@Nullable LockPatternUtils.CheckCredentialProgressCallback progressCallback)
throws LockPatternUtils.RequestThrottledException {
return true;
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowThreadUtils.java b/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowThreadUtils.java
similarity index 100%
rename from tests/robotests/src/com/android/settings/testutils/shadow/ShadowThreadUtils.java
rename to tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowThreadUtils.java
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java b/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowUserManager.java
similarity index 98%
rename from tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java
rename to tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowUserManager.java
index 324a829..0b3d3f9 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java
+++ b/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowUserManager.java
@@ -52,7 +52,7 @@
private final Set<Integer> mManagedProfiles = new HashSet<>();
private final Set<String> mEnabledTypes = new HashSet<>();
private boolean mIsQuietModeEnabled = false;
- private int[] profileIdsForUser = new int[0];
+ private int[] mProfileIdsForUser = new int[0];
private boolean mUserSwitchEnabled;
private Bundle mDefaultGuestUserRestriction = new Bundle();
private boolean mIsGuestUser = false;
@@ -154,11 +154,11 @@
@Implementation
protected int[] getProfileIdsWithDisabled(@UserIdInt int userId) {
- return profileIdsForUser;
+ return mProfileIdsForUser;
}
public void setProfileIdsWithDisabled(int[] profileIds) {
- profileIdsForUser = profileIds;
+ mProfileIdsForUser = profileIds;
}
@Implementation
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUtils.java b/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowUtils.java
similarity index 100%
rename from tests/robotests/src/com/android/settings/testutils/shadow/ShadowUtils.java
rename to tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowUtils.java
diff --git a/tests/spa_unit/src/com/android/settings/applications/specialaccess/DataSaverControllerTest.kt b/tests/spa_unit/src/com/android/settings/applications/specialaccess/DataSaverControllerTest.kt
index c2413af..5d3c1c0 100644
--- a/tests/spa_unit/src/com/android/settings/applications/specialaccess/DataSaverControllerTest.kt
+++ b/tests/spa_unit/src/com/android/settings/applications/specialaccess/DataSaverControllerTest.kt
@@ -29,7 +29,6 @@
import com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE
import com.android.settingslib.spaprivileged.model.app.AppListRepository
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
@@ -43,7 +42,6 @@
import org.mockito.junit.MockitoRule
import org.mockito.Mockito.`when` as whenever
-@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidJUnit4::class)
class DataSaverControllerTest {
@get:Rule
diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/DataUsagePreferenceControllerTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/DataUsagePreferenceControllerTest.kt
index 342ebeb..a6d1531 100644
--- a/tests/spa_unit/src/com/android/settings/network/telephony/DataUsagePreferenceControllerTest.kt
+++ b/tests/spa_unit/src/com/android/settings/network/telephony/DataUsagePreferenceControllerTest.kt
@@ -37,7 +37,6 @@
import com.android.settingslib.net.DataUsageController.DataUsageInfo
import com.android.settingslib.spa.testutils.waitUntil
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import org.junit.After
import org.junit.Before
@@ -53,7 +52,6 @@
import org.mockito.quality.Strictness
import org.mockito.Mockito.`when` as whenever
-@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidJUnit4::class)
class DataUsagePreferenceControllerTest {
diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/TelephonyStatusControlSessionTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/TelephonyStatusControlSessionTest.kt
index 7e6a91b..cf6b919 100644
--- a/tests/spa_unit/src/com/android/settings/network/telephony/TelephonyStatusControlSessionTest.kt
+++ b/tests/spa_unit/src/com/android/settings/network/telephony/TelephonyStatusControlSessionTest.kt
@@ -23,12 +23,10 @@
import com.android.settings.core.BasePreferenceController
import com.android.settingslib.spa.testutils.waitUntil
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
-@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidJUnit4::class)
class TelephonyStatusControlSessionTest {
private val context: Context = ApplicationProvider.getApplicationContext()
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/AllAppListTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/AllAppListTest.kt
index 2e7752e..97a5a81 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/AllAppListTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/AllAppListTest.kt
@@ -33,7 +33,6 @@
import com.android.settingslib.spaprivileged.template.app.AppListInput
import com.android.settingslib.spaprivileged.template.app.AppListItemModel
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import org.junit.Rule
@@ -118,7 +117,6 @@
.isEqualTo("AppInfoSettings/package.name/0")
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun allAppListModel_transform() = runTest {
val listModel = AllAppListModel(context) { stateOf(SUMMARY) }
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt
index 0d2869c..19176f8 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt
@@ -34,7 +34,6 @@
import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
import com.android.settingslib.spaprivileged.template.app.AppListItemModel
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import org.junit.Rule
@@ -67,14 +66,16 @@
@Test
fun injectEntry_summary() {
setInjectEntry()
- composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_summary, Build.MODEL))
+ composeTestRule
+ .onNodeWithText(context.getString(R.string.aspect_ratio_summary, Build.MODEL))
.assertIsDisplayed()
}
@Test
fun injectEntry_onClick_navigate() {
setInjectEntry()
- composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_title)).performClick()
+ composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_title))
+ .performClick()
assertThat(fakeNavControllerWrapper.navigateCalledWith).isEqualTo("UserAspectRatioAppsPage")
}
@@ -103,7 +104,6 @@
composeTestRule.onNodeWithText(LABEL).assertIsDisplayed()
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun aspectRatioAppListModel_transform() = runTest {
val listModel = UserAspectRatioAppListModel(context)
@@ -114,7 +114,6 @@
assertThat(recordList[0].app).isSameInstanceAs(APP)
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun aspectRatioAppListModel_filter() = runTest {
val listModel = UserAspectRatioAppListModel(context)
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/PackageInfoPresenterTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/PackageInfoPresenterTest.kt
index 3bfa90e..2648e08 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/PackageInfoPresenterTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/PackageInfoPresenterTest.kt
@@ -28,7 +28,6 @@
import com.android.settingslib.spaprivileged.framework.common.activityManager
import com.android.settingslib.spaprivileged.model.app.IPackageManagers
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -45,7 +44,6 @@
import org.mockito.junit.MockitoRule
import org.mockito.Mockito.`when` as whenever
-@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidJUnit4::class)
class PackageInfoPresenterTest {
@get:Rule
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProviderTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProviderTest.kt
index b3e29af..68ad065 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProviderTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProviderTest.kt
@@ -34,7 +34,6 @@
import com.android.settingslib.spa.testutils.any
import com.android.settingslib.spaprivileged.template.app.AppListItemModel
import com.google.common.truth.Truth
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
@@ -171,7 +170,6 @@
.isEqualTo("AppInfoSettings/package.name/0")
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun backgroundInstalledAppsWithGroupingListModel_getGroupTitleOne() = runTest {
val listModel = BackgroundInstalledAppsWithGroupingListModel(context)
@@ -186,7 +184,6 @@
Truth.assertThat(actualGroupTitle).isEqualTo("Apps installed in the last 6 months")
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun backgroundInstalledAppsWithGroupingListModel_getGroupTitleTwo() = runTest {
val listModel = BackgroundInstalledAppsWithGroupingListModel(context)
@@ -201,7 +198,6 @@
Truth.assertThat(actualGroupTitle).isEqualTo("Apps installed more than 6 months ago")
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun backgroundInstalledAppsWithGroupingListModel_transform() = runTest {
val listModel = BackgroundInstalledAppsWithGroupingListModel(mockContext)
@@ -220,7 +216,6 @@
Truth.assertThat(packageInfoFlagsCaptor.value.value).isEqualTo(EXPECTED_PACKAGE_INFO_FLAG)
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun backgroundInstalledAppsWithGroupingListModel_filter() = runTest {
val listModel = BackgroundInstalledAppsWithGroupingListModel(mockContext)
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/PictureInPictureTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/PictureInPictureTest.kt
index fb0fb69..6054bb5 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/PictureInPictureTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/PictureInPictureTest.kt
@@ -29,7 +29,6 @@
import com.android.settings.R
import com.android.settingslib.spaprivileged.model.app.AppOpsController
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
@@ -46,7 +45,6 @@
import org.mockito.junit.MockitoRule
import org.mockito.Mockito.`when` as whenever
-@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidJUnit4::class)
class PictureInPictureTest {
@get:Rule
diff --git a/tests/spa_unit/src/com/android/settings/spa/development/compat/PlatformCompatAppListModelTest.kt b/tests/spa_unit/src/com/android/settings/spa/development/compat/PlatformCompatAppListModelTest.kt
index 78aca85..0cfdc7d 100644
--- a/tests/spa_unit/src/com/android/settings/spa/development/compat/PlatformCompatAppListModelTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/development/compat/PlatformCompatAppListModelTest.kt
@@ -25,7 +25,6 @@
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
@@ -41,7 +40,6 @@
import org.mockito.junit.MockitoRule
import org.mockito.Mockito.`when` as whenever
-@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidJUnit4::class)
class PlatformCompatAppListModelTest {
@get:Rule
diff --git a/tests/spa_unit/src/com/android/settings/spa/notification/AppNotificationRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/spa/notification/AppNotificationRepositoryTest.kt
index 12fdc23..87ff9ba 100644
--- a/tests/spa_unit/src/com/android/settings/spa/notification/AppNotificationRepositoryTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/notification/AppNotificationRepositoryTest.kt
@@ -34,7 +34,6 @@
import com.android.settingslib.spaprivileged.model.app.IPackageManagers
import com.android.settingslib.spaprivileged.model.app.userId
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
@@ -49,7 +48,6 @@
import org.mockito.junit.MockitoRule
import org.mockito.Mockito.`when` as whenever
-@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidJUnit4::class)
class AppNotificationRepositoryTest {
@get:Rule
diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModelTest.kt b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModelTest.kt
index 976caed..e708f3b 100644
--- a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModelTest.kt
+++ b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModelTest.kt
@@ -35,7 +35,7 @@
import com.android.settings.password.ChooseLockPattern
import com.android.settings.password.ChooseLockSettingsHelper
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
+import java.util.concurrent.atomic.AtomicBoolean
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestScope
@@ -50,7 +50,6 @@
import org.mockito.Mockito
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
-import java.util.concurrent.atomic.AtomicBoolean
import org.mockito.Mockito.`when` as whenever
@RunWith(AndroidJUnit4::class)
@@ -86,7 +85,6 @@
challengeGenerator.challenge = newChallenge
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testCheckCredential_validCredentialCase() = runTest {
val userId = 99
@@ -109,7 +107,6 @@
assertThat(viewModel.createGeneratingChallengeExtras()).isNull()
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testCheckCredential_needToChooseLock() = runTest {
val userId = 100
@@ -132,7 +129,6 @@
assertThat(viewModel.createGeneratingChallengeExtras()).isNull()
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testCheckCredential_needToConfirmLockForSomething() = runTest {
val userId = 101
@@ -156,7 +152,6 @@
assertThat(viewModel.createGeneratingChallengeExtras()).isNull()
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testCheckCredential_needToConfirmLockForNumeric() = runTest {
val userId = 102
@@ -180,7 +175,6 @@
assertThat(viewModel.createGeneratingChallengeExtras()).isNull()
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testCheckCredential_needToConfirmLockForAlphabetic() = runTest {
val userId = 103
@@ -204,7 +198,6 @@
assertThat(viewModel.createGeneratingChallengeExtras()).isNull()
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testCheckCredential_generateChallenge() = runTest {
val userId = 104
@@ -258,7 +251,6 @@
assertThat(tokens[0]).isEqualTo(1)
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testCheckCredential_generateChallengeFail() = runTest {
backgroundScope.launch {
@@ -306,7 +298,6 @@
assertThat(viewModel.userId).isEqualTo(userId)
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testGenerateChallengeAsCredentialActivityResult_invalidChooseLock() = runTest {
backgroundScope.launch {
@@ -332,7 +323,6 @@
}
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testGenerateChallengeAsCredentialActivityResult_invalidConfirmLock() = runTest {
backgroundScope.launch {
@@ -358,7 +348,6 @@
}
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testGenerateChallengeAsCredentialActivityResult_nullDataChooseLock() = runTest {
val userId = 108
@@ -380,7 +369,6 @@
assertThat(generateFails.size).isEqualTo(0)
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testGenerateChallengeAsCredentialActivityResult_nullDataConfirmLock() = runTest {
val userId = 109
@@ -401,7 +389,6 @@
assertThat(generateFails.size).isEqualTo(0)
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testGenerateChallengeAsCredentialActivityResult_validChooseLock() = runTest {
val userId = 108
@@ -447,7 +434,6 @@
assertThat(hasCalledRemoveGkPwHandle.get()).isTrue()
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testGenerateChallengeAsCredentialActivityResult_validConfirmLock() = runTest {
val userId = 109
@@ -493,7 +479,6 @@
assertThat(hasCalledRemoveGkPwHandle.get()).isTrue()
}
- @OptIn(ExperimentalCoroutinesApi::class)
private fun TestScope.listOfGenerateChallengeFailedFlow(): List<Boolean> =
mutableListOf<Boolean>().also {
backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) {
diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollErrorDialogViewModelTest.kt b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollErrorDialogViewModelTest.kt
index 3679dd2..379a5c1 100644
--- a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollErrorDialogViewModelTest.kt
+++ b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollErrorDialogViewModelTest.kt
@@ -19,12 +19,9 @@
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.biometrics2.ui.viewmodel.FingerprintErrorDialogSetResultAction.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintErrorDialogSetResultAction.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.launch
-import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
@@ -56,7 +53,6 @@
assertThat(FingerprintEnrollErrorDialogViewModel(application, true).isSuw).isTrue()
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testNewDialog() = runTest {
val newDialogs: List<Int> = mutableListOf<Int>().also {
@@ -81,7 +77,6 @@
assertThat(newDialogs[0]).isEqualTo(testErrorMsgId)
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testTriggerRetry() = runTest {
val triggerRetries: List<Any> = mutableListOf<Any>().also {
@@ -102,7 +97,6 @@
assertThat(triggerRetries.size).isEqualTo(1)
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testSetResultFinish() = runTest {
val setResults: List<FingerprintErrorDialogSetResultAction> =
diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollIntroViewModelTest.kt b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollIntroViewModelTest.kt
index 08e5ac3..7494aef 100644
--- a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollIntroViewModelTest.kt
+++ b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollIntroViewModelTest.kt
@@ -38,7 +38,6 @@
import com.android.settings.biometrics2.utils.FingerprintRepositoryUtils.setupFingerprintEnrolledFingerprints
import com.android.settings.biometrics2.utils.FingerprintRepositoryUtils.setupSuwMaxFingerprintsEnrollable
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestScope
@@ -78,7 +77,6 @@
application = ApplicationProvider.getApplicationContext()
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testPageStatusFlowDefaultAndUpdate() = runTest {
val viewModel = newFingerprintEnrollIntroViewModel(
@@ -105,7 +103,6 @@
assertThat(statusList[1].enrollableStatus).isEqualTo(FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX)
}
- @OptIn(ExperimentalCoroutinesApi::class)
fun testOnStartToUpdateEnrollableStatusOk_isSuw() = runTest {
setupFingerprintEnrolledFingerprints(fingerprintManager, TEST_USER_ID, 0)
setupSuwMaxFingerprintsEnrollable(application, resources, 1)
@@ -122,7 +119,6 @@
assertThat(statusList[0].enrollableStatus).isEqualTo(FINGERPRINT_ENROLLABLE_OK)
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testOnStartToUpdateEnrollableStatusReachMax_isSuw() = runTest {
setupFingerprintEnrolledFingerprints(fingerprintManager, TEST_USER_ID, 1)
@@ -140,49 +136,41 @@
assertThat(statusList[0].enrollableStatus).isEqualTo(FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX)
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testOnStartToUpdateEnrollableStatusOk_isNotSuw() = runTest {
testOnStartToUpdateEnrollableStatusOk(newAllFalseRequest(application))
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testOnStartToUpdateEnrollableStatusReachMax_isNotSuw() = runTest {
testOnStartToUpdateEnrollableStatusReachMax(newAllFalseRequest(application))
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testOnStartToUpdateEnrollableStatusOk_isSuwDeferred() = runTest {
testOnStartToUpdateEnrollableStatusOk(newIsSuwDeferredRequest(application))
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testOnStartToUpdateEnrollableStatusReachMax_isSuwDeferred() = runTest {
testOnStartToUpdateEnrollableStatusReachMax(newIsSuwDeferredRequest(application))
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testOnStartToUpdateEnrollableStatusOk_isSuwPortal() = runTest {
testOnStartToUpdateEnrollableStatusOk(newIsSuwPortalRequest(application))
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testOnStartToUpdateEnrollableStatusReachMax_isSuwPortal() = runTest {
testOnStartToUpdateEnrollableStatusReachMax(newIsSuwPortalRequest(application))
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testOnStartToUpdateEnrollableStatusOk_isSuwSuggestedActionFlow() = runTest {
testOnStartToUpdateEnrollableStatusOk(newIsSuwSuggestedActionFlowRequest(application))
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testOnStartToUpdateEnrollableStatusReachMax_isSuwSuggestedActionFlow() = runTest {
testOnStartToUpdateEnrollableStatusReachMax(
@@ -190,7 +178,6 @@
)
}
- @OptIn(ExperimentalCoroutinesApi::class)
private fun TestScope.testOnStartToUpdateEnrollableStatusOk(request: EnrollmentRequest) {
setupFingerprintEnrolledFingerprints(fingerprintManager, TEST_USER_ID, 0)
val viewModel = newFingerprintEnrollIntroViewModel(
@@ -206,7 +193,6 @@
assertThat(statusList[0].enrollableStatus).isEqualTo(FINGERPRINT_ENROLLABLE_OK)
}
- @OptIn(ExperimentalCoroutinesApi::class)
private fun TestScope.testOnStartToUpdateEnrollableStatusReachMax(request: EnrollmentRequest) {
setupFingerprintEnrolledFingerprints(fingerprintManager, TEST_USER_ID, 5)
val viewModel = newFingerprintEnrollIntroViewModel(
@@ -268,7 +254,6 @@
assertThat(viewModel.isBiometricUnlockDisabledByAdmin).isEqualTo(false)
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testSetHasScrolledToBottom() = runTest {
val viewModel = newFingerprintEnrollIntroViewModel(
@@ -284,7 +269,6 @@
assertThat(pageStatusList[pageStatusList.size-1].hasScrollToBottom()).isEqualTo(true)
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testOnNextButtonClick_enrollNext() = runTest {
// Set latest status to FINGERPRINT_ENROLLABLE_OK
@@ -305,7 +289,6 @@
assertThat(actions[0]).isEqualTo(CONTINUE_ENROLL)
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testOnNextButtonClick_doneAndFinish() = runTest {
// Set latest status to FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX
@@ -334,7 +317,6 @@
assertThat(actionList[0]).isEqualTo(DONE_AND_FINISH)
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testOnSkipOrCancelButtonClick() = runTest {
val viewModel = newFingerprintEnrollIntroViewModel(
@@ -351,7 +333,6 @@
assertThat(actions[0]).isEqualTo(SKIP_OR_CANCEL)
}
- @OptIn(ExperimentalCoroutinesApi::class)
private fun TestScope.listOfActionFlow(
viewModel: FingerprintEnrollIntroViewModel
): List<FingerprintEnrollIntroAction> =
@@ -361,7 +342,6 @@
}
}
- @OptIn(ExperimentalCoroutinesApi::class)
private fun TestScope.listOfPageStatusFlow(
viewModel: FingerprintEnrollIntroViewModel
): List<FingerprintEnrollIntroStatus> =
diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollmentViewModelTest.kt b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollmentViewModelTest.kt
index bee91c9..6d04f35 100644
--- a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollmentViewModelTest.kt
+++ b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollmentViewModelTest.kt
@@ -30,7 +30,6 @@
import com.android.settings.biometrics2.utils.FingerprintRepositoryUtils.newFingerprintRepository
import com.android.settings.biometrics2.utils.FingerprintRepositoryUtils.setupFingerprintEnrolledFingerprints
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestScope
@@ -226,7 +225,6 @@
assertThat(viewModel.isMaxEnrolledReached(uid)).isTrue()
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testSetResultFlow_defaultEmpty() = runTest {
val activityResults = listOfSetResultFlow()
@@ -236,7 +234,6 @@
assertThat(activityResults.size).isEqualTo(0)
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testCheckFinishActivityDuringOnPause_doNothingIfIsSuw() = runTest {
viewModel = FingerprintEnrollmentViewModel(
@@ -257,7 +254,6 @@
assertThat(activityResults.size).isEqualTo(0)
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testCheckFinishActivityDuringOnPause_doNothingIfIsWaitingActivity() = runTest {
val activityResults = listOfSetResultFlow()
@@ -273,7 +269,6 @@
assertThat(activityResults.size).isEqualTo(0)
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testCheckFinishActivityDuringOnPause_doNothingIfIsActivityFinishing() = runTest {
val activityResults = listOfSetResultFlow()
@@ -288,7 +283,6 @@
assertThat(activityResults.size).isEqualTo(0)
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testCheckFinishActivityDuringOnPause_doNothingIfIsChangingConfigurations() = runTest {
val activityResults = listOfSetResultFlow()
@@ -303,7 +297,6 @@
assertThat(activityResults.size).isEqualTo(0)
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testCheckFinishActivityDuringOnPause_defaultFinishSelf() = runTest {
val activityResults = listOfSetResultFlow()
@@ -320,7 +313,6 @@
assertThat(activityResults[0].data).isEqualTo(null)
}
- @OptIn(ExperimentalCoroutinesApi::class)
private fun TestScope.listOfSetResultFlow(): List<ActivityResult> =
mutableListOf<ActivityResult>().also {
backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) {
diff --git a/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FakeFingerprintManagerInteractor.kt b/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FakeFingerprintManagerInteractor.kt
index 0509d8a..1848c01 100644
--- a/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FakeFingerprintManagerInteractor.kt
+++ b/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FakeFingerprintManagerInteractor.kt
@@ -67,7 +67,11 @@
return enrolledFingerprintsInternal.remove(fp)
}
- override suspend fun renameFingerprint(fp: FingerprintViewModel, newName: String) {}
+ override suspend fun renameFingerprint(fp: FingerprintViewModel, newName: String) {
+ if (enrolledFingerprintsInternal.remove(fp)) {
+ enrolledFingerprintsInternal.add(FingerprintViewModel(newName, fp.fingerId, fp.deviceId))
+ }
+ }
override suspend fun hasSideFps(): Boolean {
return sensorProps.any { it.isAnySidefpsType }
diff --git a/tests/unit/src/com/android/settings/fingerprint2/viewmodel/FingerprintSettingsNavigationViewModelTest.kt b/tests/unit/src/com/android/settings/fingerprint2/viewmodel/FingerprintSettingsNavigationViewModelTest.kt
index 4e1f6b1..9206afb 100644
--- a/tests/unit/src/com/android/settings/fingerprint2/viewmodel/FingerprintSettingsNavigationViewModelTest.kt
+++ b/tests/unit/src/com/android/settings/fingerprint2/viewmodel/FingerprintSettingsNavigationViewModelTest.kt
@@ -17,6 +17,7 @@
package com.android.settings.fingerprint2.viewmodel
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.android.settings.biometrics.BiometricEnrollBase
import com.android.settings.biometrics.fingerprint2.ui.viewmodel.EnrollFirstFingerprint
import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintSettingsNavigationViewModel
import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintViewModel
@@ -272,4 +273,97 @@
assertThat(nextStep).isEqualTo(ShowSettings)
job.cancel()
}
+
+ @Test
+ fun enrollWithToken_andNoUsers_startsFingerprintEnrollment() =
+ testScope.runTest {
+ fakeFingerprintManagerInteractor.enrolledFingerprintsInternal = mutableListOf()
+
+ var nextStep: NextStepViewModel? = null
+ val job = launch { underTest.nextStep.collect { nextStep = it } }
+
+ val token = byteArrayOf(1)
+ val challenge = 5L
+
+ underTest =
+ FingerprintSettingsNavigationViewModel.FingerprintSettingsNavigationModelFactory(
+ defaultUserId,
+ fakeFingerprintManagerInteractor,
+ backgroundDispatcher,
+ token,
+ challenge,
+ )
+ .create(FingerprintSettingsNavigationViewModel::class.java)
+
+ runCurrent()
+
+ assertThat(nextStep).isEqualTo(EnrollFirstFingerprint(defaultUserId, null, challenge, token))
+ job.cancel()
+ }
+
+ @Test
+ fun enroll_shouldNotFinish() =
+ testScope.runTest {
+ fakeFingerprintManagerInteractor.enrolledFingerprintsInternal = mutableListOf()
+
+ var nextStep: NextStepViewModel? = null
+ val job = launch { underTest.nextStep.collect { nextStep = it } }
+
+ val token = byteArrayOf(1)
+ val challenge = 5L
+
+ underTest =
+ FingerprintSettingsNavigationViewModel.FingerprintSettingsNavigationModelFactory(
+ defaultUserId,
+ fakeFingerprintManagerInteractor,
+ backgroundDispatcher,
+ token,
+ challenge,
+ )
+ .create(FingerprintSettingsNavigationViewModel::class.java)
+
+ runCurrent()
+
+ assertThat(nextStep).isEqualTo(EnrollFirstFingerprint(defaultUserId, null, challenge, token))
+ underTest.maybeFinishActivity(false)
+
+ runCurrent()
+ assertThat(nextStep).isEqualTo(EnrollFirstFingerprint(defaultUserId, null, challenge, token))
+ job.cancel()
+ }
+
+ @Test
+ fun showSettings_shouldFinish() =
+ testScope.runTest {
+ fakeFingerprintManagerInteractor.enrolledFingerprintsInternal =
+ mutableListOf(FingerprintViewModel("a", 1, 3L))
+
+ var nextStep: NextStepViewModel? = null
+ val job = launch { underTest.nextStep.collect { nextStep = it } }
+
+ val token = byteArrayOf(1)
+ val challenge = 5L
+
+ underTest =
+ FingerprintSettingsNavigationViewModel.FingerprintSettingsNavigationModelFactory(
+ defaultUserId,
+ fakeFingerprintManagerInteractor,
+ backgroundDispatcher,
+ token,
+ challenge,
+ )
+ .create(FingerprintSettingsNavigationViewModel::class.java)
+
+ runCurrent()
+ assertThat(nextStep).isEqualTo(ShowSettings)
+
+ underTest.maybeFinishActivity(false)
+
+ runCurrent()
+ assertThat(nextStep)
+ .isEqualTo(
+ FinishSettingsWithResult(BiometricEnrollBase.RESULT_TIMEOUT, "onStop finishing settings")
+ )
+ job.cancel()
+ }
}
diff --git a/tests/unit/src/com/android/settings/fingerprint2/viewmodel/FingerprintSettingsViewModelTest.kt b/tests/unit/src/com/android/settings/fingerprint2/viewmodel/FingerprintSettingsViewModelTest.kt
index d430827..8bd0b10 100644
--- a/tests/unit/src/com/android/settings/fingerprint2/viewmodel/FingerprintSettingsViewModelTest.kt
+++ b/tests/unit/src/com/android/settings/fingerprint2/viewmodel/FingerprintSettingsViewModelTest.kt
@@ -213,7 +213,8 @@
@Test
fun deleteDialog_showAndDismiss() = runTest {
val fingerprintToDelete = FingerprintViewModel("A", 1, 10L)
- fakeFingerprintManagerInteractor.enrolledFingerprintsInternal = mutableListOf(fingerprintToDelete)
+ fakeFingerprintManagerInteractor.enrolledFingerprintsInternal =
+ mutableListOf(fingerprintToDelete)
underTest =
FingerprintSettingsViewModel.FingerprintSettingsViewModelFactory(
@@ -244,4 +245,170 @@
dialogJob.cancel()
}
+
+ @Test
+ fun renameDialog_showAndDismiss() = runTest {
+ val fingerprintToRename = FingerprintViewModel("World", 1, 10L)
+ fakeFingerprintManagerInteractor.enrolledFingerprintsInternal =
+ mutableListOf(fingerprintToRename)
+
+ underTest =
+ FingerprintSettingsViewModel.FingerprintSettingsViewModelFactory(
+ defaultUserId,
+ fakeFingerprintManagerInteractor,
+ backgroundDispatcher,
+ navigationViewModel,
+ )
+ .create(FingerprintSettingsViewModel::class.java)
+
+ var dialog: PreferenceViewModel? = null
+ val dialogJob = launch { underTest.isShowingDialog.collect { dialog = it } }
+
+ // Move to the ShowSettings state
+ navigationViewModel.onConfirmDevice(true, 10L)
+ runCurrent()
+ underTest.onPrefClicked(fingerprintToRename)
+ runCurrent()
+
+ assertThat(dialog is PreferenceViewModel.DeleteDialog)
+ assertThat(dialog).isEqualTo(PreferenceViewModel.RenameDialog(fingerprintToRename))
+
+ underTest.renameFingerprint(fingerprintToRename, "Hello")
+ underTest.onRenameDialogFinished()
+ runCurrent()
+
+ assertThat(dialog).isNull()
+ assertThat(fakeFingerprintManagerInteractor.enrolledFingerprintsInternal.first().name)
+ .isEqualTo("Hello")
+
+ dialogJob.cancel()
+ }
+
+ @Test
+ fun testTwoDialogsCannotShow_atSameTime() = runTest {
+ val fingerprintToDelete = FingerprintViewModel("A", 1, 10L)
+ fakeFingerprintManagerInteractor.enrolledFingerprintsInternal =
+ mutableListOf(fingerprintToDelete)
+
+ underTest =
+ FingerprintSettingsViewModel.FingerprintSettingsViewModelFactory(
+ defaultUserId,
+ fakeFingerprintManagerInteractor,
+ backgroundDispatcher,
+ navigationViewModel,
+ )
+ .create(FingerprintSettingsViewModel::class.java)
+
+ var dialog: PreferenceViewModel? = null
+ val dialogJob = launch { underTest.isShowingDialog.collect { dialog = it } }
+
+ // Move to the ShowSettings state
+ navigationViewModel.onConfirmDevice(true, 10L)
+ runCurrent()
+ underTest.onDeleteClicked(fingerprintToDelete)
+ runCurrent()
+
+ assertThat(dialog is PreferenceViewModel.DeleteDialog)
+ assertThat(dialog).isEqualTo(PreferenceViewModel.DeleteDialog(fingerprintToDelete))
+
+ underTest.onPrefClicked(fingerprintToDelete)
+ runCurrent()
+ assertThat(dialog is PreferenceViewModel.DeleteDialog)
+ assertThat(dialog).isEqualTo(PreferenceViewModel.DeleteDialog(fingerprintToDelete))
+
+ dialogJob.cancel()
+ }
+
+ @Test
+ fun authenticatePauses_whenPaused() =
+ testScope.runTest {
+ val fingerprints = setupAuth()
+ val success = FingerprintAuthAttemptViewModel.Success(fingerprints.first().fingerId)
+
+ var authAttempt: FingerprintAuthAttemptViewModel? = null
+
+ val job = launch { underTest.authFlow.take(5).collectLatest { authAttempt = it } }
+
+ underTest.shouldAuthenticate(true)
+ navigationViewModel.onConfirmDevice(true, 10L)
+
+ advanceTimeBy(400)
+ runCurrent()
+ assertThat(authAttempt).isEqualTo(success)
+
+ fakeFingerprintManagerInteractor.authenticateAttempt =
+ FingerprintAuthAttemptViewModel.Success(10)
+ underTest.shouldAuthenticate(false)
+ advanceTimeBy(400)
+ runCurrent()
+
+ // The most recent auth attempt shouldn't have changed.
+ assertThat(authAttempt).isEqualTo(success)
+ job.cancel()
+ }
+
+ @Test
+ fun dialog_pausesAuth() =
+ testScope.runTest {
+ val fingerprints = setupAuth()
+
+ var authAttempt: FingerprintAuthAttemptViewModel? = null
+ val job = launch { underTest.authFlow.take(1).collectLatest { authAttempt = it } }
+ underTest.shouldAuthenticate(true)
+ navigationViewModel.onConfirmDevice(true, 10L)
+
+ underTest.onPrefClicked(fingerprints[0])
+ advanceTimeBy(400)
+
+ job.cancel()
+ assertThat(authAttempt).isEqualTo(null)
+ }
+
+ @Test
+ fun cannotAuth_when_notShowingSettings() =
+ testScope.runTest {
+ val fingerprints = setupAuth()
+
+ var authAttempt: FingerprintAuthAttemptViewModel? = null
+ val job = launch { underTest.authFlow.take(1).collectLatest { authAttempt = it } }
+ underTest.shouldAuthenticate(true)
+ navigationViewModel.onConfirmDevice(true, 10L)
+
+ // This should cause the state to change to FingerprintEnrolling
+ navigationViewModel.onAddFingerprintClicked()
+ advanceTimeBy(400)
+
+ job.cancel()
+ assertThat(authAttempt).isEqualTo(null)
+ }
+
+ private fun setupAuth(): MutableList<FingerprintViewModel> {
+ fakeFingerprintManagerInteractor.sensorProps =
+ listOf(
+ FingerprintSensorPropertiesInternal(
+ 0 /* sensorId */,
+ SensorProperties.STRENGTH_STRONG,
+ 5 /* maxEnrollmentsPerUser */,
+ emptyList() /* ComponentInfoInternal */,
+ FingerprintSensorProperties.TYPE_POWER_BUTTON,
+ true /* resetLockoutRequiresHardwareAuthToken */
+ )
+ )
+ val fingerprints =
+ mutableListOf(FingerprintViewModel("a", 1, 3L), FingerprintViewModel("b", 2, 5L))
+ fakeFingerprintManagerInteractor.enrolledFingerprintsInternal = fingerprints
+ val success = FingerprintAuthAttemptViewModel.Success(1)
+ fakeFingerprintManagerInteractor.authenticateAttempt = success
+
+ underTest =
+ FingerprintSettingsViewModel.FingerprintSettingsViewModelFactory(
+ defaultUserId,
+ fakeFingerprintManagerInteractor,
+ backgroundDispatcher,
+ navigationViewModel,
+ )
+ .create(FingerprintSettingsViewModel::class.java)
+
+ return fingerprints
+ }
}
diff --git a/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java b/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java
index 01c2143..f6356bc 100644
--- a/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java
+++ b/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java
@@ -67,24 +67,18 @@
@RunWith(AndroidJUnit4.class)
public class BiometricsSafetySourceTest {
- private static final ComponentName COMPONENT_NAME =
- new ComponentName("package", "class");
+ private static final ComponentName COMPONENT_NAME = new ComponentName("package", "class");
private static final UserHandle USER_HANDLE = new UserHandle(UserHandle.myUserId());
private static final SafetyEvent EVENT_SOURCE_STATE_CHANGED =
new SafetyEvent.Builder(SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build();
private Context mApplicationContext;
- @Mock
- private PackageManager mPackageManager;
- @Mock
- private DevicePolicyManager mDevicePolicyManager;
- @Mock
- private FingerprintManager mFingerprintManager;
- @Mock
- private FaceManager mFaceManager;
- @Mock
- private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper;
+ @Mock private PackageManager mPackageManager;
+ @Mock private DevicePolicyManager mDevicePolicyManager;
+ @Mock private FingerprintManager mFingerprintManager;
+ @Mock private FaceManager mFaceManager;
+ @Mock private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper;
@Before
public void setUp() {
@@ -119,15 +113,16 @@
}
@Test
- public void setSafetySourceData_whenSafetyCenterIsEnabled_withoutBiometrics_doesNotSetData() {
+ public void setSafetySourceData_whenSafetyCenterIsEnabled_withoutBiometrics_setsNullData() {
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(false);
when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
when(mFaceManager.isHardwareDetected()).thenReturn(false);
BiometricsSafetySource.setSafetySourceData(mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
- verify(mSafetyCenterManagerWrapper, never())
- .setSafetySourceData(any(), any(), any(), any());
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(), eq(BiometricsSafetySource.SAFETY_SOURCE_ID), eq(null), any());
}
@Test
@@ -140,8 +135,9 @@
BiometricsSafetySource.setSafetySourceData(mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
- verify(mSafetyCenterManagerWrapper).setSafetySourceData(
- any(), eq(BiometricsSafetySource.SAFETY_SOURCE_ID), any(), any());
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(), eq(BiometricsSafetySource.SAFETY_SOURCE_ID), any(), any());
}
@Test
@@ -225,7 +221,8 @@
assertSafetySourceEnabledDataSetWithPluralSummary(
"security_settings_fingerprint_preference_title",
- "security_settings_fingerprint_preference_summary", enrolledFingerprintsCount,
+ "security_settings_fingerprint_preference_summary",
+ enrolledFingerprintsCount,
FingerprintSettings.class.getName());
}
@@ -346,8 +343,9 @@
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
when(mFaceManager.isHardwareDetected()).thenReturn(true);
when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME))
- .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FACE
- | DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT);
+ .thenReturn(
+ DevicePolicyManager.KEYGUARD_DISABLE_FACE
+ | DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT);
BiometricsSafetySource.setSafetySourceData(mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
@@ -363,8 +361,8 @@
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
when(mFaceManager.isHardwareDetected()).thenReturn(true);
when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
- when(mFingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn(
- createFingerprintList(enrolledFingerprintsCount));
+ when(mFingerprintManager.getEnrolledFingerprints(anyInt()))
+ .thenReturn(createFingerprintList(enrolledFingerprintsCount));
BiometricsSafetySource.setSafetySourceData(mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
@@ -381,8 +379,8 @@
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
when(mFaceManager.isHardwareDetected()).thenReturn(true);
when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
- when(mFingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn(
- createFingerprintList(enrolledFingerprintsCount));
+ when(mFingerprintManager.getEnrolledFingerprints(anyInt()))
+ .thenReturn(createFingerprintList(enrolledFingerprintsCount));
BiometricsSafetySource.setSafetySourceData(mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
@@ -398,8 +396,8 @@
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
when(mFaceManager.isHardwareDetected()).thenReturn(true);
when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
- when(mFingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn(
- Collections.emptyList());
+ when(mFingerprintManager.getEnrolledFingerprints(anyInt()))
+ .thenReturn(Collections.emptyList());
BiometricsSafetySource.setSafetySourceData(mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
@@ -415,8 +413,8 @@
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
when(mFaceManager.isHardwareDetected()).thenReturn(false);
- when(mFingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn(
- createFingerprintList(enrolledFingerprintsCount));
+ when(mFingerprintManager.getEnrolledFingerprints(anyInt()))
+ .thenReturn(createFingerprintList(enrolledFingerprintsCount));
ActiveUnlockTestUtils.enable(mApplicationContext);
@@ -452,8 +450,8 @@
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
when(mFaceManager.isHardwareDetected()).thenReturn(true);
when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
- when(mFingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn(
- createFingerprintList(enrolledFingerprintsCount));
+ when(mFingerprintManager.getEnrolledFingerprints(anyInt()))
+ .thenReturn(createFingerprintList(enrolledFingerprintsCount));
ActiveUnlockTestUtils.enable(mApplicationContext);
BiometricsSafetySource.setSafetySourceData(mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
@@ -462,7 +460,6 @@
"security_settings_biometric_preference_title",
"security_settings_biometric_preference_summary_both_fp_single",
Settings.CombinedBiometricSettingsActivity.class.getName());
-
}
@Test
@@ -472,14 +469,15 @@
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
when(mFaceManager.isHardwareDetected()).thenReturn(true);
when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
- when(mFingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn(
- createFingerprintList(enrolledFingerprintsCount));
+ when(mFingerprintManager.getEnrolledFingerprints(anyInt()))
+ .thenReturn(createFingerprintList(enrolledFingerprintsCount));
BiometricsSafetySource.setSafetySourceData(mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
assertSafetySourceEnabledDataSetWithPluralSummary(
"security_settings_biometric_preference_title",
- "security_settings_fingerprint_preference_summary", enrolledFingerprintsCount,
+ "security_settings_fingerprint_preference_summary",
+ enrolledFingerprintsCount,
Settings.CombinedBiometricSettingsActivity.class.getName());
}
@@ -494,8 +492,12 @@
BiometricsSafetySource.setSafetySourceData(mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
- verify(mSafetyCenterManagerWrapper).setSafetySourceData(
- any(), eq(BiometricsSafetySource.SAFETY_SOURCE_ID), captor.capture(), any());
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(),
+ eq(BiometricsSafetySource.SAFETY_SOURCE_ID),
+ captor.capture(),
+ any());
SafetySourceStatus safetySourceStatus = captor.getValue().getStatus();
assertThat(safetySourceStatus.getSeverityLevel())
.isEqualTo(SafetySourceData.SEVERITY_LEVEL_INFORMATION);
@@ -512,8 +514,12 @@
BiometricsSafetySource.setSafetySourceData(mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
- verify(mSafetyCenterManagerWrapper).setSafetySourceData(
- any(), eq(BiometricsSafetySource.SAFETY_SOURCE_ID), captor.capture(), any());
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(),
+ eq(BiometricsSafetySource.SAFETY_SOURCE_ID),
+ captor.capture(),
+ any());
SafetySourceStatus safetySourceStatus = captor.getValue().getStatus();
assertThat(safetySourceStatus.getSeverityLevel())
.isEqualTo(SafetySourceData.SEVERITY_LEVEL_INFORMATION);
@@ -530,8 +536,12 @@
BiometricsSafetySource.setSafetySourceData(mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
- verify(mSafetyCenterManagerWrapper).setSafetySourceData(
- any(), eq(BiometricsSafetySource.SAFETY_SOURCE_ID), captor.capture(), any());
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(),
+ eq(BiometricsSafetySource.SAFETY_SOURCE_ID),
+ captor.capture(),
+ any());
SafetySourceStatus safetySourceStatus = captor.getValue().getStatus();
assertThat(safetySourceStatus.getSeverityLevel())
.isEqualTo(SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED);
@@ -547,8 +557,12 @@
BiometricsSafetySource.setSafetySourceData(mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
- verify(mSafetyCenterManagerWrapper).setSafetySourceData(
- any(), eq(BiometricsSafetySource.SAFETY_SOURCE_ID), captor.capture(), any());
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(),
+ eq(BiometricsSafetySource.SAFETY_SOURCE_ID),
+ captor.capture(),
+ any());
SafetySourceStatus safetySourceStatus = captor.getValue().getStatus();
assertThat(safetySourceStatus.getSeverityLevel())
.isEqualTo(SafetySourceData.SEVERITY_LEVEL_INFORMATION);
@@ -564,8 +578,12 @@
BiometricsSafetySource.setSafetySourceData(mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
- verify(mSafetyCenterManagerWrapper).setSafetySourceData(
- any(), eq(BiometricsSafetySource.SAFETY_SOURCE_ID), captor.capture(), any());
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(),
+ eq(BiometricsSafetySource.SAFETY_SOURCE_ID),
+ captor.capture(),
+ any());
SafetySourceStatus safetySourceStatus = captor.getValue().getStatus();
assertThat(safetySourceStatus.getSeverityLevel())
.isEqualTo(SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED);
@@ -581,8 +599,12 @@
BiometricsSafetySource.setSafetySourceData(mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
- verify(mSafetyCenterManagerWrapper).setSafetySourceData(
- any(), eq(BiometricsSafetySource.SAFETY_SOURCE_ID), captor.capture(), any());
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(),
+ eq(BiometricsSafetySource.SAFETY_SOURCE_ID),
+ captor.capture(),
+ any());
SafetySourceStatus safetySourceStatus = captor.getValue().getStatus();
assertThat(safetySourceStatus.getSeverityLevel())
.isEqualTo(SafetySourceData.SEVERITY_LEVEL_INFORMATION);
@@ -598,61 +620,74 @@
BiometricsSafetySource.setSafetySourceData(mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
- verify(mSafetyCenterManagerWrapper).setSafetySourceData(
- any(), eq(BiometricsSafetySource.SAFETY_SOURCE_ID), captor.capture(), any());
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(),
+ eq(BiometricsSafetySource.SAFETY_SOURCE_ID),
+ captor.capture(),
+ any());
SafetySourceStatus safetySourceStatus = captor.getValue().getStatus();
assertThat(safetySourceStatus.getSeverityLevel())
.isEqualTo(SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED);
}
- private void assertSafetySourceDisabledDataSetWithSingularSummary(String expectedTitleResName,
- String expectedSummaryResName) {
+ private void assertSafetySourceDisabledDataSetWithSingularSummary(
+ String expectedTitleResName, String expectedSummaryResName) {
assertSafetySourceDisabledDataSet(
ResourcesUtils.getResourcesString(mApplicationContext, expectedTitleResName),
- ResourcesUtils.getResourcesString(mApplicationContext, expectedSummaryResName)
- );
+ ResourcesUtils.getResourcesString(mApplicationContext, expectedSummaryResName));
}
- private void assertSafetySourceEnabledDataSetWithSingularSummary(String expectedTitleResName,
+ private void assertSafetySourceEnabledDataSetWithSingularSummary(
+ String expectedTitleResName,
String expectedSummaryResName,
String expectedSettingsClassName) {
assertSafetySourceEnabledDataSet(
ResourcesUtils.getResourcesString(mApplicationContext, expectedTitleResName),
ResourcesUtils.getResourcesString(mApplicationContext, expectedSummaryResName),
- expectedSettingsClassName
- );
+ expectedSettingsClassName);
}
- private void assertSafetySourceDisabledDataSetWithPluralSummary(String expectedTitleResName,
- String expectedSummaryResName, int expectedSummaryQuantity) {
- final int stringResId = ResourcesUtils.getResourcesId(
- ApplicationProvider.getApplicationContext(), "string",
- expectedSummaryResName);
+ private void assertSafetySourceDisabledDataSetWithPluralSummary(
+ String expectedTitleResName,
+ String expectedSummaryResName,
+ int expectedSummaryQuantity) {
+ final int stringResId =
+ ResourcesUtils.getResourcesId(
+ ApplicationProvider.getApplicationContext(),
+ "string",
+ expectedSummaryResName);
assertSafetySourceDisabledDataSet(
ResourcesUtils.getResourcesString(mApplicationContext, expectedTitleResName),
- StringUtil.getIcuPluralsString(mApplicationContext,
- expectedSummaryQuantity, stringResId)
- );
+ StringUtil.getIcuPluralsString(
+ mApplicationContext, expectedSummaryQuantity, stringResId));
}
- private void assertSafetySourceEnabledDataSetWithPluralSummary(String expectedTitleResName,
- String expectedSummaryResName, int expectedSummaryQuantity,
+ private void assertSafetySourceEnabledDataSetWithPluralSummary(
+ String expectedTitleResName,
+ String expectedSummaryResName,
+ int expectedSummaryQuantity,
String expectedSettingsClassName) {
- final int stringResId = ResourcesUtils.getResourcesId(
- ApplicationProvider.getApplicationContext(), "string",
- expectedSummaryResName);
+ final int stringResId =
+ ResourcesUtils.getResourcesId(
+ ApplicationProvider.getApplicationContext(),
+ "string",
+ expectedSummaryResName);
assertSafetySourceEnabledDataSet(
ResourcesUtils.getResourcesString(mApplicationContext, expectedTitleResName),
- StringUtil.getIcuPluralsString(mApplicationContext,
- expectedSummaryQuantity, stringResId),
- expectedSettingsClassName
- );
+ StringUtil.getIcuPluralsString(
+ mApplicationContext, expectedSummaryQuantity, stringResId),
+ expectedSettingsClassName);
}
private void assertSafetySourceDisabledDataSet(String expectedTitle, String expectedSummary) {
ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
- verify(mSafetyCenterManagerWrapper).setSafetySourceData(
- any(), eq(BiometricsSafetySource.SAFETY_SOURCE_ID), captor.capture(), any());
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(),
+ eq(BiometricsSafetySource.SAFETY_SOURCE_ID),
+ captor.capture(),
+ any());
SafetySourceData safetySourceData = captor.getValue();
SafetySourceStatus safetySourceStatus = safetySourceData.getStatus();
@@ -667,11 +702,15 @@
assertThat(clickIntent.getAction()).isEqualTo(ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
}
- private void assertSafetySourceEnabledDataSet(String expectedTitle, String expectedSummary,
- String expectedSettingsClassName) {
+ private void assertSafetySourceEnabledDataSet(
+ String expectedTitle, String expectedSummary, String expectedSettingsClassName) {
ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
- verify(mSafetyCenterManagerWrapper).setSafetySourceData(
- any(), eq(BiometricsSafetySource.SAFETY_SOURCE_ID), captor.capture(), any());
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(),
+ eq(BiometricsSafetySource.SAFETY_SOURCE_ID),
+ captor.capture(),
+ any());
SafetySourceData safetySourceData = captor.getValue();
SafetySourceStatus safetySourceStatus = safetySourceData.getStatus();
@@ -680,10 +719,8 @@
assertThat(safetySourceStatus.isEnabled()).isTrue();
final Intent clickIntent = safetySourceStatus.getPendingIntent().getIntent();
assertThat(clickIntent).isNotNull();
- assertThat(clickIntent.getComponent().getPackageName())
- .isEqualTo("com.android.settings");
- assertThat(clickIntent.getComponent().getClassName())
- .isEqualTo(expectedSettingsClassName);
+ assertThat(clickIntent.getComponent().getPackageName()).isEqualTo("com.android.settings");
+ assertThat(clickIntent.getComponent().getClassName()).isEqualTo(expectedSettingsClassName);
}
private List<Fingerprint> createFingerprintList(int size) {
diff --git a/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java b/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java
index 9dc39da..4a6afb1 100644
--- a/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java
+++ b/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java
@@ -102,15 +102,15 @@
}
@Test
- public void setSafetySourceData_whenScreenLockIsDisabled_doesNotSetData() {
+ public void setSafetySourceData_whenScreenLockIsDisabled_setsNullData() {
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
when(mScreenLockPreferenceDetailsUtils.isAvailable()).thenReturn(false);
LockScreenSafetySource.setSafetySourceData(mApplicationContext,
mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
- verify(mSafetyCenterManagerWrapper, never()).setSafetySourceData(
- any(), any(), any(), any());
+ verify(mSafetyCenterManagerWrapper).setSafetySourceData(
+ any(), eq(LockScreenSafetySource.SAFETY_SOURCE_ID), eq(null), any());
}
@Test
diff --git a/tests/unit/src/com/android/settings/slices/SliceTestUtils.java b/tests/unit/src/com/android/settings/slices/SliceTestUtils.java
deleted file mode 100644
index 020bde2..0000000
--- a/tests/unit/src/com/android/settings/slices/SliceTestUtils.java
+++ /dev/null
@@ -1,85 +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.settings.slices;
-
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.sqlite.SQLiteDatabase;
-import android.net.Uri;
-import android.provider.SettingsSlicesContract;
-
-import com.android.settings.testutils.FakeIndexProvider;
-import com.android.settings.testutils.FakeToggleController;
-
-class SliceTestUtils {
-
- public static final String FAKE_TITLE = "title";
- public static final String FAKE_SUMMARY = "summary";
- public static final String FAKE_SCREEN_TITLE = "screen_title";
- public static final String FAKE_KEYWORDS = "a, b, c";
- public static final int FAKE_ICON = 1234;
- public static final String FAKE_FRAGMENT_NAME = FakeIndexProvider.class.getName();
- public static final String FAKE_CONTROLLER_NAME = FakeToggleController.class.getName();
- public static final int FAKE_HIGHLIGHT_MENU_RES = FakeToggleController.HIGHLIGHT_MENU_RES;
-
-
- public static void insertSliceToDb(Context context, String key) {
- insertSliceToDb(context, key, true /* isPlatformSlice */);
- }
-
- public static void insertSliceToDb(Context context, String key, boolean isPlatformSlice) {
- insertSliceToDb(context, key, isPlatformSlice, null /*customizedUnavailableSliceSubtitle*/);
- }
-
- public static void insertSliceToDb(Context context, String key, boolean isPlatformSlice,
- String customizedUnavailableSliceSubtitle) {
- insertSliceToDb(context, key, isPlatformSlice, customizedUnavailableSliceSubtitle, false);
- }
-
- public static void insertSliceToDb(Context context, String key, boolean isPlatformSlice,
- String customizedUnavailableSliceSubtitle, boolean isPublicSlice) {
- final SQLiteDatabase db = SlicesDatabaseHelper.getInstance(context).getWritableDatabase();
- ContentValues values = new ContentValues();
- values.put(SlicesDatabaseHelper.IndexColumns.KEY, key);
- values.put(SlicesDatabaseHelper.IndexColumns.SLICE_URI,
- new Uri.Builder()
- .scheme(ContentResolver.SCHEME_CONTENT)
- .authority(isPlatformSlice
- ? SettingsSlicesContract.AUTHORITY
- : SettingsSliceProvider.SLICE_AUTHORITY)
- .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
- .appendPath(key)
- .build().toString());
- values.put(SlicesDatabaseHelper.IndexColumns.TITLE, FAKE_TITLE);
- values.put(SlicesDatabaseHelper.IndexColumns.SUMMARY, FAKE_SUMMARY);
- values.put(SlicesDatabaseHelper.IndexColumns.SCREENTITLE, FAKE_SCREEN_TITLE);
- values.put(SlicesDatabaseHelper.IndexColumns.KEYWORDS, FAKE_KEYWORDS);
- values.put(SlicesDatabaseHelper.IndexColumns.ICON_RESOURCE, FAKE_ICON);
- values.put(SlicesDatabaseHelper.IndexColumns.FRAGMENT, FAKE_FRAGMENT_NAME);
- values.put(SlicesDatabaseHelper.IndexColumns.CONTROLLER, FAKE_CONTROLLER_NAME);
- values.put(SlicesDatabaseHelper.IndexColumns.SLICE_TYPE, SliceData.SliceType.INTENT);
- values.put(SlicesDatabaseHelper.IndexColumns.UNAVAILABLE_SLICE_SUBTITLE,
- customizedUnavailableSliceSubtitle);
- values.put(SlicesDatabaseHelper.IndexColumns.PUBLIC_SLICE, isPublicSlice);
- values.put(SlicesDatabaseHelper.IndexColumns.HIGHLIGHT_MENU_RESOURCE,
- FAKE_HIGHLIGHT_MENU_RES);
-
- db.replaceOrThrow(SlicesDatabaseHelper.Tables.TABLE_SLICES_INDEX, null, values);
- db.close();
- }
-}
diff --git a/tests/unit/src/com/android/settings/testutils/AirplaneModeRule.java b/tests/unit/src/com/android/settings/testutils/AirplaneModeRule.java
deleted file mode 100644
index 459ac15..0000000
--- a/tests/unit/src/com/android/settings/testutils/AirplaneModeRule.java
+++ /dev/null
@@ -1,71 +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.settings.testutils;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.provider.Settings;
-import android.util.Log;
-
-import androidx.test.core.app.ApplicationProvider;
-
-import org.junit.rules.ExternalResource;
-
-/** A test rule that is used to manager the Airplane Mode resource for testing. */
-public final class AirplaneModeRule extends ExternalResource {
-
- private static final String TAG = "AirplaneModeRule";
-
- private Context mContext;
- private ContentResolver mContentResolver;
- private boolean mBackupValue;
- private boolean mShouldRestore;
-
- @Override
- protected void before() throws Throwable {
- mContext = ApplicationProvider.getApplicationContext();
- mContentResolver = mContext.getContentResolver();
- }
-
- @Override
- protected void after() {
- if (!mShouldRestore) {
- return;
- }
- Log.d(TAG, "Restore Airplane Mode value:" + mBackupValue);
- Settings.Global.putInt(mContentResolver, Settings.Global.AIRPLANE_MODE_ON,
- mBackupValue ? 1 : 0);
- }
-
- public void setAirplaneMode(boolean enable) {
- if (enable == isAirplaneModeOn()) {
- return;
- }
- if (!mShouldRestore) {
- mShouldRestore = true;
- mBackupValue = !enable;
- Log.d(TAG, "Backup Airplane Mode value:" + mBackupValue);
- }
- Log.d(TAG, "Set Airplane Mode enable:" + enable);
- Settings.Global.putInt(mContentResolver, Settings.Global.AIRPLANE_MODE_ON, enable ? 1 : 0);
- }
-
- public boolean isAirplaneModeOn() {
- return Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
- }
-}
diff --git a/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java b/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java
index 90b4efe..05ed662 100644
--- a/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java
+++ b/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java
@@ -23,6 +23,7 @@
import com.android.settings.accessibility.AccessibilitySearchFeatureProvider;
import com.android.settings.accounts.AccountFeatureProvider;
import com.android.settings.applications.ApplicationFeatureProvider;
+import com.android.settings.onboarding.OnboardingFeatureProvider;
import com.android.settings.biometrics.face.FaceFeatureProvider;
import com.android.settings.biometrics2.factory.BiometricsRepositoryProvider;
import com.android.settings.bluetooth.BluetoothFeatureProvider;
@@ -92,6 +93,7 @@
public WifiFeatureProvider mWifiFeatureProvider;
public KeyboardSettingsFeatureProvider mKeyboardSettingsFeatureProvider;
public StylusFeatureProvider mStylusFeatureProvider;
+ public OnboardingFeatureProvider mOnboardingFeatureProvider;
/**
* Call this in {@code @Before} method of the test class to use fake factory.
@@ -136,6 +138,7 @@
mWifiFeatureProvider = mock(WifiFeatureProvider.class);
mKeyboardSettingsFeatureProvider = mock(KeyboardSettingsFeatureProvider.class);
mStylusFeatureProvider = mock(StylusFeatureProvider.class);
+ mOnboardingFeatureProvider = mock(OnboardingFeatureProvider.class);
}
@Override
@@ -298,4 +301,9 @@
public StylusFeatureProvider getStylusFeatureProvider() {
return mStylusFeatureProvider;
}
+
+ @Override
+ public OnboardingFeatureProvider getOnboardingFeatureProvider() {
+ return mOnboardingFeatureProvider;
+ }
}
diff --git a/tests/unit/src/com/android/settings/testutils/FakeIndexProvider.java b/tests/unit/src/com/android/settings/testutils/FakeIndexProvider.java
deleted file mode 100644
index 5cbfb54..0000000
--- a/tests/unit/src/com/android/settings/testutils/FakeIndexProvider.java
+++ /dev/null
@@ -1,46 +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.settings.testutils;
-
-import android.content.Context;
-
-import com.android.settings.R;
-import com.android.settings.search.BaseSearchIndexProvider;
-import com.android.settingslib.search.Indexable;
-
-import java.util.List;
-
-public class FakeIndexProvider implements Indexable {
-
- public static final String KEY = "TestKey";
-
- /**
- * The fake SearchIndexProvider. Note that the use of location_settings below implies that tests
- * using this should be using the res/xml-mcc999/location_settings.xml or
- * res/xml-mcc998/location_settings.xml. Annotate tests with
- * {@code @Config(qualifiers = "mcc999")}.
- */
- public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
- new BaseSearchIndexProvider(R.xml.location_settings) {
-
- @Override
- public List<String> getNonIndexableKeys(Context context) {
- List<String> result = super.getNonIndexableKeys(context);
- result.add(KEY);
- return result;
- }
- };
-}
diff --git a/tests/unit/src/com/android/settings/testutils/FakeUnavailablePreferenceController.java b/tests/unit/src/com/android/settings/testutils/FakeUnavailablePreferenceController.java
deleted file mode 100644
index 97379e3..0000000
--- a/tests/unit/src/com/android/settings/testutils/FakeUnavailablePreferenceController.java
+++ /dev/null
@@ -1,40 +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.settings.testutils;
-
-import android.content.Context;
-import android.provider.Settings;
-
-import com.android.settings.core.BasePreferenceController;
-
-public class FakeUnavailablePreferenceController extends BasePreferenceController {
-
- public static final String AVAILABILITY_KEY = "fake_availability_key";
-
- public FakeUnavailablePreferenceController(Context context) {
- super(context, "key");
- }
-
- @Override
- public int getAvailabilityStatus() {
- return Settings.Global.getInt(mContext.getContentResolver(), AVAILABILITY_KEY, 0);
- }
-
- @Override
- public boolean isSliceable() {
- return true;
- }
-}
diff --git a/tests/unit/src/com/android/settings/testutils/ResolveInfoBuilder.java b/tests/unit/src/com/android/settings/testutils/ResolveInfoBuilder.java
deleted file mode 100644
index 5eaf2a4..0000000
--- a/tests/unit/src/com/android/settings/testutils/ResolveInfoBuilder.java
+++ /dev/null
@@ -1,71 +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.settings.testutils;
-
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.ProviderInfo;
-import android.content.pm.ResolveInfo;
-
-import com.google.common.base.Preconditions;
-
-/**
- * Helper for building {@link ResolveInfo}s to be used in Robolectric tests.
- *
- * <p>The resulting {@link PackageInfo}s should typically be added to {@link
- * org.robolectric.shadows.ShadowPackageManager#addResolveInfoForIntent(Intent, ResolveInfo)}.
- */
-public final class ResolveInfoBuilder {
-
- private final String mPackageName;
- private ActivityInfo mActivityInfo;
- private ProviderInfo mProviderInfo;
-
- public ResolveInfoBuilder(String packageName) {
- this.mPackageName = Preconditions.checkNotNull(packageName);
- }
-
- public ResolveInfoBuilder setActivity(String packageName, String className) {
- mActivityInfo = new ActivityInfo();
- mActivityInfo.packageName = packageName;
- mActivityInfo.name = className;
- return this;
- }
-
- public ResolveInfoBuilder setProvider(
- String packageName, String className, String authority, boolean isSystemApp) {
- mProviderInfo = new ProviderInfo();
- mProviderInfo.authority = authority;
- mProviderInfo.applicationInfo = new ApplicationInfo();
- if (isSystemApp) {
- mProviderInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
- }
- mProviderInfo.packageName = mPackageName;
- mProviderInfo.applicationInfo.packageName = mPackageName;
- mProviderInfo.name = className;
- return this;
- }
-
- public ResolveInfo build() {
- ResolveInfo info = new ResolveInfo();
- info.activityInfo = mActivityInfo;
- info.resolvePackageName = mPackageName;
- info.providerInfo = mProviderInfo;
- return info;
- }
-}
diff --git a/tests/unit/src/com/android/settings/testutils/SliceTester.java b/tests/unit/src/com/android/settings/testutils/SliceTester.java
deleted file mode 100644
index be13e13..0000000
--- a/tests/unit/src/com/android/settings/testutils/SliceTester.java
+++ /dev/null
@@ -1,324 +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.settings.testutils;
-
-import static android.app.slice.Slice.HINT_TITLE;
-import static android.app.slice.Slice.SUBTYPE_COLOR;
-import static android.app.slice.SliceItem.FORMAT_IMAGE;
-import static android.app.slice.SliceItem.FORMAT_INT;
-import static android.app.slice.SliceItem.FORMAT_TEXT;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.app.PendingIntent;
-import android.content.Context;
-import android.text.TextUtils;
-
-import androidx.core.graphics.drawable.IconCompat;
-import androidx.slice.Slice;
-import androidx.slice.SliceItem;
-import androidx.slice.SliceMetadata;
-import androidx.slice.builders.ListBuilder;
-import androidx.slice.core.SliceAction;
-import androidx.slice.core.SliceQuery;
-import androidx.slice.widget.EventInfo;
-
-import com.android.settings.Utils;
-import com.android.settings.slices.SettingsSliceProvider;
-import com.android.settings.slices.SliceBuilderUtils;
-import com.android.settings.slices.SliceData;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/**
- * Testing utility class to verify the contents of the different Settings Slices.
- *
- * TODO (77712944) check Summary, range (metadata.getRange()), toggle icons.
- */
-public class SliceTester {
-
- /**
- * Test the contents of an intent based slice, including:
- * - No toggles
- * - Correct intent
- * - Correct title
- * - Correct keywords
- * - TTL
- * - Color
- */
- public static void testSettingsIntentSlice(Context context, Slice slice, SliceData sliceData) {
- final SliceMetadata metadata = SliceMetadata.from(context, slice);
-
- final long sliceTTL = metadata.getExpiry();
- assertThat(sliceTTL).isEqualTo(ListBuilder.INFINITY);
-
- final SliceItem colorItem = SliceQuery.findSubtype(slice, FORMAT_INT, SUBTYPE_COLOR);
- final int color = colorItem.getInt();
- assertThat(color).isEqualTo(Utils.getColorAccentDefaultColor(context));
-
- final List<SliceAction> toggles = metadata.getToggles();
- assertThat(toggles).isEmpty();
-
- final PendingIntent primaryPendingIntent = metadata.getPrimaryAction().getAction();
- assertThat(primaryPendingIntent).isEqualTo(
- SliceBuilderUtils.getContentPendingIntent(context, sliceData));
-
- assertThat(metadata.getTitle()).isEqualTo(sliceData.getTitle());
-
- assertKeywords(metadata, sliceData);
- }
-
- /**
- * Test the contents of an toggle based slice, including:
- * - Contains one toggle
- * - Correct toggle intent
- * - Correct content intent
- * - Correct title
- * - Correct keywords
- * - TTL
- * - Color
- */
- public static void testSettingsToggleSlice(Context context, Slice slice, SliceData sliceData) {
- final SliceMetadata metadata = SliceMetadata.from(context, slice);
-
- final SliceItem colorItem = SliceQuery.findSubtype(slice, FORMAT_INT, SUBTYPE_COLOR);
- final int color = colorItem.getInt();
- assertThat(color).isEqualTo(Utils.getColorAccentDefaultColor(context));
-
- final List<SliceAction> toggles = metadata.getToggles();
- assertThat(toggles).hasSize(1);
-
- final long sliceTTL = metadata.getExpiry();
- assertThat(sliceTTL).isEqualTo(ListBuilder.INFINITY);
-
- final SliceAction mainToggleAction = toggles.get(0);
-
- assertThat(mainToggleAction.getIcon()).isNull();
-
- // Check intent in Toggle Action
- final PendingIntent togglePendingIntent = mainToggleAction.getAction();
- assertThat(togglePendingIntent).isEqualTo(SliceBuilderUtils.getActionIntent(context,
- SettingsSliceProvider.ACTION_TOGGLE_CHANGED, sliceData));
-
- // Check primary intent
- final PendingIntent primaryPendingIntent = metadata.getPrimaryAction().getAction();
- assertThat(primaryPendingIntent).isEqualTo(
- SliceBuilderUtils.getContentPendingIntent(context, sliceData));
-
- assertThat(metadata.getTitle()).isEqualTo(sliceData.getTitle());
-
- assertKeywords(metadata, sliceData);
- }
-
- /**
- * Test the contents of an slider based slice, including:
- * - No intent
- * - Correct title
- * - Correct keywords
- * - TTL
- * - Color
- */
- public static void testSettingsSliderSlice(Context context, Slice slice, SliceData sliceData) {
- final SliceMetadata metadata = SliceMetadata.from(context, slice);
- final SliceAction primaryAction = metadata.getPrimaryAction();
-
- final IconCompat icon = primaryAction.getIcon();
- if (icon == null) {
- final SliceItem colorItem = SliceQuery.findSubtype(slice, FORMAT_INT, SUBTYPE_COLOR);
- final int color = colorItem.getInt();
- assertThat(color).isEqualTo(Utils.getColorAccentDefaultColor(context));
-
- } else {
- final IconCompat expectedIcon = IconCompat.createWithResource(context,
- sliceData.getIconResource());
- assertThat(expectedIcon.toString()).isEqualTo(icon.toString());
- }
-
- final long sliceTTL = metadata.getExpiry();
- assertThat(sliceTTL).isEqualTo(ListBuilder.INFINITY);
-
- final int headerType = metadata.getHeaderType();
- assertThat(headerType).isEqualTo(EventInfo.ROW_TYPE_SLIDER);
-
- // Check primary intent
- final PendingIntent primaryPendingIntent = primaryAction.getAction();
- assertThat(primaryPendingIntent).isEqualTo(
- SliceBuilderUtils.getContentPendingIntent(context, sliceData));
-
- assertThat(metadata.getTitle()).isEqualTo(sliceData.getTitle());
-
- assertKeywords(metadata, sliceData);
- }
-
- /**
- * Test the copyable slice, including:
- * - No intent
- * - Correct title
- * - Correct intent
- * - Correct keywords
- * - TTL
- * - Color
- */
- public static void testSettingsCopyableSlice(Context context, Slice slice,
- SliceData sliceData) {
- final SliceMetadata metadata = SliceMetadata.from(context, slice);
-
- final SliceItem colorItem = SliceQuery.findSubtype(slice, FORMAT_INT, SUBTYPE_COLOR);
- final int color = colorItem.getInt();
- assertThat(color).isEqualTo(Utils.getColorAccentDefaultColor(context));
-
- final SliceAction primaryAction = metadata.getPrimaryAction();
-
- final IconCompat expectedIcon = IconCompat.createWithResource(context,
- sliceData.getIconResource());
- assertThat(expectedIcon.toString()).isEqualTo(primaryAction.getIcon().toString());
-
- final long sliceTTL = metadata.getExpiry();
- assertThat(sliceTTL).isEqualTo(ListBuilder.INFINITY);
-
- // Check primary intent
- final PendingIntent primaryPendingIntent = primaryAction.getAction();
- assertThat(primaryPendingIntent).isEqualTo(
- SliceBuilderUtils.getContentPendingIntent(context, sliceData));
-
- assertThat(metadata.getTitle()).isEqualTo(sliceData.getTitle());
-
- assertKeywords(metadata, sliceData);
- }
-
- /**
- * Test the contents of an unavailable slice, including:
- * - No toggles
- * - Correct title
- * - Correct intent
- * - Correct keywords
- * - Color
- * - TTL
- */
- public static void testSettingsUnavailableSlice(Context context, Slice slice,
- SliceData sliceData) {
- final SliceMetadata metadata = SliceMetadata.from(context, slice);
-
- final long sliceTTL = metadata.getExpiry();
- assertThat(sliceTTL).isEqualTo(ListBuilder.INFINITY);
-
- final SliceItem colorItem = SliceQuery.findSubtype(slice, FORMAT_INT, SUBTYPE_COLOR);
- final int color = colorItem.getInt();
- assertThat(color).isEqualTo(Utils.getColorAccentDefaultColor(context));
-
- final List<SliceAction> toggles = metadata.getToggles();
- assertThat(toggles).isEmpty();
-
- final PendingIntent primaryPendingIntent = metadata.getPrimaryAction().getAction();
- assertThat(primaryPendingIntent).isEqualTo(SliceBuilderUtils.getContentPendingIntent(
- context, sliceData));
-
- assertThat(metadata.getTitle()).isEqualTo(sliceData.getTitle());
-
- assertKeywords(metadata, sliceData);
- }
-
- /**
- * Assert any slice item contains title.
- *
- * @param sliceItems All slice items of a Slice.
- * @param title Title for asserting.
- */
- public static void assertAnySliceItemContainsTitle(List<SliceItem> sliceItems, String title) {
- assertThat(hasText(sliceItems, title, HINT_TITLE)).isTrue();
- }
-
- /**
- * Assert any slice item contains subtitle.
- *
- * @param sliceItems All slice items of a Slice.
- * @param subtitle Subtitle for asserting.
- */
- public static void assertAnySliceItemContainsSubtitle(List<SliceItem> sliceItems,
- String subtitle) {
- // Subtitle has no hints
- assertThat(hasText(sliceItems, subtitle, null /* hints */)).isTrue();
- }
-
- /**
- * Assert no slice item contains subtitle.
- *
- * @param sliceItems All slice items of a Slice.
- * @param subtitle Subtitle for asserting.
- */
- public static void assertNoSliceItemContainsSubtitle(List<SliceItem> sliceItems,
- String subtitle) {
- // Subtitle has no hints
- assertThat(hasText(sliceItems, subtitle, null /* hints */)).isFalse();
- }
-
- private static boolean hasText(List<SliceItem> sliceItems, String text, String hints) {
- boolean hasText = false;
- for (SliceItem item : sliceItems) {
- List<SliceItem> textItems = SliceQuery.findAll(item, FORMAT_TEXT, hints,
- null /* non-hints */);
- if (textItems == null) {
- continue;
- }
-
- for (SliceItem textItem : textItems) {
- if (TextUtils.equals(textItem.getText(), text)) {
- hasText = true;
- break;
- }
- }
- }
- return hasText;
- }
-
- /**
- * Assert any slice item contains icon.
- *
- * @param sliceItems All slice items of a Slice.
- * @param icon Icon for asserting.
- */
- public static void assertAnySliceItemContainsIcon(List<SliceItem> sliceItems, IconCompat icon) {
- boolean hasIcon = false;
- for (SliceItem item : sliceItems) {
- List<SliceItem> iconItems = SliceQuery.findAll(item, FORMAT_IMAGE,
- (String) null /* hints */, null /* non-hints */);
- if (iconItems == null) {
- continue;
- }
-
- for (SliceItem iconItem : iconItems) {
- if (icon.toString().equals(iconItem.getIcon().toString())) {
- hasIcon = true;
- break;
- }
- }
- }
- assertThat(hasIcon).isTrue();
- }
-
- private static void assertKeywords(SliceMetadata metadata, SliceData data) {
- final List<String> keywords = metadata.getSliceKeywords();
- final Set<String> expectedKeywords = Arrays.stream(data.getKeywords().split(","))
- .map(s -> s = s.trim())
- .collect(Collectors.toSet());
- expectedKeywords.add(data.getTitle());
- expectedKeywords.add(data.getScreenTitle().toString());
- assertThat(keywords).containsExactlyElementsIn(expectedKeywords);
- }
-}